1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
3 * This file is open source software, licensed to you under the terms
4 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
5 * distributed with this work for additional information regarding copyright
6 * ownership. You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
20 * Copyright (C) 2014 Cloudius Systems, Ltd.
24 * Ceph - scalable distributed file system
26 * Copyright (C) 2015 XSky <haomai@xsky.com>
28 * Author: Haomai Wang <haomaiwang@gmail.com>
30 * This is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Lesser General Public
32 * License version 2.1, as published by the Free Software
33 * Foundation. See file COPYING.
37 #ifndef CEPH_MSG_ARP_H_
38 #define CEPH_MSG_ARP_H_
42 #include <unordered_map>
45 #include "msg/async/Event.h"
48 #include "circular_buffer.h"
54 template <typename L3>
57 class arp_for_protocol {
62 arp_for_protocol(arp& a, uint16_t proto_num);
63 virtual ~arp_for_protocol();
64 virtual int received(Packet p) = 0;
65 virtual bool forward(forward_hash& out_hash_data, Packet& p, size_t off) { return false; }
73 subscription<Packet, ethernet_address> _rx_packets;
74 std::unordered_map<uint16_t, arp_for_protocol*> _arp_for_protocol;
75 circular_buffer<l3_protocol::l3packet> _packetq;
82 hdr.htype = ::ntoh(htype);
83 hdr.ptype = ::ntoh(ptype);
88 hdr.htype = ::hton(htype);
89 hdr.ptype = ::hton(ptype);
94 explicit arp(interface* netif);
95 void add(uint16_t proto_num, arp_for_protocol* afp);
96 void del(uint16_t proto_num);
98 ethernet_address l2self() { return _netif->hw_address(); }
99 int process_packet(Packet p, ethernet_address from);
100 bool forward(forward_hash& out_hash_data, Packet& p, size_t off);
101 Tub<l3_protocol::l3packet> get_packet();
102 template <class l3_proto>
103 friend class arp_for;
106 template <typename L3>
107 class arp_for : public arp_for_protocol {
109 using l2addr = ethernet_address;
110 using l3addr = typename L3::address_type;
112 static constexpr auto max_waiters = 512;
123 l2addr sender_hwaddr;
125 l2addr target_hwaddr;
130 hdr.htype = ::ntoh(htype);
131 hdr.ptype = ::ntoh(ptype);
132 hdr.oper = ::ntoh(oper);
133 hdr.sender_hwaddr = sender_hwaddr.ntoh();
134 hdr.sender_paddr = sender_paddr.ntoh();
135 hdr.target_hwaddr = target_hwaddr.ntoh();
136 hdr.target_paddr = target_paddr.ntoh();
142 hdr.htype = ::hton(htype);
143 hdr.ptype = ::hton(ptype);
144 hdr.oper = ::hton(oper);
145 hdr.sender_hwaddr = sender_hwaddr.hton();
146 hdr.sender_paddr = sender_paddr.hton();
147 hdr.target_hwaddr = target_hwaddr.hton();
148 hdr.target_paddr = target_paddr.hton();
153 std::vector<std::pair<resolution_cb, Packet>> _waiters;
156 class C_handle_arp_timeout : public EventCallback {
162 C_handle_arp_timeout(arp_for *a, l3addr addr, bool first):
163 arp(a), paddr(addr), first_request(first) {}
164 void do_request(int r) {
165 arp->send_query(paddr);
166 auto &res = arp->_in_progress[paddr];
168 for (auto& p : res._waiters) {
169 p.first(ethernet_address(), std::move(p.second), -ETIMEDOUT);
171 res._waiters.clear();
172 res.timeout_fd = arp->center->create_time_event(
176 friend class C_handle_arp_timeout;
181 l3addr _l3self = L3::broadcast_address();
182 std::unordered_map<l3addr, l2addr> _table;
183 std::unordered_map<l3addr, resolution> _in_progress;
185 Packet make_query_packet(l3addr paddr);
186 virtual int received(Packet p) override;
187 int handle_request(arp_hdr* ah);
188 l2addr l2self() { return _arp.l2self(); }
189 void send(l2addr to, Packet &&p);
191 void send_query(const l3addr& paddr);
192 explicit arp_for(CephContext *c, arp& a, EventCenter *cen)
193 : arp_for_protocol(a, L3::arp_protocol_type()), cct(c), center(cen) {
194 _table[L3::broadcast_address()] = ethernet::broadcast_address();
197 for (auto && p : _in_progress)
198 center->delete_time_event(p.second.timeout_fd);
200 void wait(const l3addr& addr, Packet p, resolution_cb cb);
201 void learn(l2addr l2, l3addr l3);
203 void set_self_addr(l3addr addr) {
204 _table.erase(_l3self);
205 _table[addr] = l2self();
211 template <typename L3>
212 void arp_for<L3>::send(l2addr to, Packet &&p) {
213 _arp._packetq.push_back(l3_protocol::l3packet{eth_protocol_num::arp, to, std::move(p)});
216 template <typename L3>
217 Packet arp_for<L3>::make_query_packet(l3addr paddr) {
219 hdr.htype = ethernet::arp_hardware_type();
220 hdr.ptype = L3::arp_protocol_type();
221 hdr.hlen = sizeof(l2addr);
222 hdr.plen = sizeof(l3addr);
223 hdr.oper = op_request;
224 hdr.sender_hwaddr = l2self();
225 hdr.sender_paddr = _l3self;
226 hdr.target_hwaddr = ethernet::broadcast_address();
227 hdr.target_paddr = paddr;
229 return Packet(reinterpret_cast<char*>(&hdr), sizeof(hdr));
232 template <typename L3>
233 void arp_for<L3>::send_query(const l3addr& paddr) {
234 send(ethernet::broadcast_address(), make_query_packet(paddr));
237 template <typename L3>
238 void arp_for<L3>::learn(l2addr hwaddr, l3addr paddr) {
239 _table[paddr] = hwaddr;
240 auto i = _in_progress.find(paddr);
241 if (i != _in_progress.end()) {
242 auto& res = i->second;
243 center->delete_time_event(res.timeout_fd);
244 for (auto &&p : res._waiters) {
245 p.first(hwaddr, std::move(p.second), 0);
247 _in_progress.erase(i);
251 template <typename L3>
252 void arp_for<L3>::wait(const l3addr& paddr, Packet p, resolution_cb cb) {
253 auto i = _table.find(paddr);
254 if (i != _table.end()) {
255 cb(i->second, std::move(p), 0);
259 auto j = _in_progress.find(paddr);
260 auto first_request = j == _in_progress.end();
261 auto& res = first_request ? _in_progress[paddr] : j->second;
264 res.timeout_fd = center->create_time_event(
265 1*1000*1000, new C_handle_arp_timeout(this, paddr, first_request));
269 if (res._waiters.size() >= max_waiters) {
270 cb(ethernet_address(), std::move(p), -EBUSY);
274 res._waiters.emplace_back(cb, std::move(p));
278 template <typename L3>
279 int arp_for<L3>::received(Packet p) {
280 auto ah = p.get_header<arp_hdr>();
285 if (h.hlen != sizeof(l2addr) || h.plen != sizeof(l3addr)) {
290 return handle_request(&h);
292 _arp._netif->arp_learn(h.sender_hwaddr, h.sender_paddr);
299 template <typename L3>
300 int arp_for<L3>::handle_request(arp_hdr* ah) {
301 if (ah->target_paddr == _l3self
302 && _l3self != L3::broadcast_address()) {
304 ah->target_hwaddr = ah->sender_hwaddr;
305 ah->target_paddr = ah->sender_paddr;
306 ah->sender_hwaddr = l2self();
307 ah->sender_paddr = _l3self;
309 send(ah->target_hwaddr, Packet(reinterpret_cast<char*>(ah), sizeof(*ah)));
314 #endif /* CEPH_MSG_ARP_H_ */