]> git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/dpdk/ARP.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / msg / async / dpdk / ARP.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 /*
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.
7 *
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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
17 * under the License.
18 */
19 /*
20 * Copyright (C) 2014 Cloudius Systems, Ltd.
21 *
22 */
23
24 #ifndef CEPH_MSG_ARP_H_
25 #define CEPH_MSG_ARP_H_
26
27 #include <errno.h>
28
29 #include <unordered_map>
30 #include <functional>
31
32 #include "msg/async/Event.h"
33
34 #include "ethernet.h"
35 #include "circular_buffer.h"
36 #include "ip_types.h"
37 #include "net.h"
38 #include "Packet.h"
39
40 class arp;
41 template <typename L3>
42 class arp_for;
43
44 class arp_for_protocol {
45 protected:
46 arp& _arp;
47 uint16_t _proto_num;
48 public:
49 arp_for_protocol(arp& a, uint16_t proto_num);
50 virtual ~arp_for_protocol();
51 virtual int received(Packet p) = 0;
52 virtual bool forward(forward_hash& out_hash_data, Packet& p, size_t off) { return false; }
53 };
54
55 class interface;
56
57 class arp {
58 interface* _netif;
59 l3_protocol _proto;
60 subscription<Packet, ethernet_address> _rx_packets;
61 std::unordered_map<uint16_t, arp_for_protocol*> _arp_for_protocol;
62 circular_buffer<l3_protocol::l3packet> _packetq;
63 private:
64 struct arp_hdr {
65 uint16_t htype;
66 uint16_t ptype;
67 arp_hdr ntoh() {
68 arp_hdr hdr = *this;
69 hdr.htype = ::ntoh(htype);
70 hdr.ptype = ::ntoh(ptype);
71 return hdr;
72 }
73 arp_hdr hton() {
74 arp_hdr hdr = *this;
75 hdr.htype = ::hton(htype);
76 hdr.ptype = ::hton(ptype);
77 return hdr;
78 }
79 };
80 public:
81 explicit arp(interface* netif);
82 void add(uint16_t proto_num, arp_for_protocol* afp);
83 void del(uint16_t proto_num);
84 private:
85 ethernet_address l2self() { return _netif->hw_address(); }
86 int process_packet(Packet p, ethernet_address from);
87 bool forward(forward_hash& out_hash_data, Packet& p, size_t off);
88 std::optional<l3_protocol::l3packet> get_packet();
89 template <class l3_proto>
90 friend class arp_for;
91 };
92
93 template <typename L3>
94 class arp_for : public arp_for_protocol {
95 public:
96 using l2addr = ethernet_address;
97 using l3addr = typename L3::address_type;
98 private:
99 static constexpr auto max_waiters = 512;
100 enum oper {
101 op_request = 1,
102 op_reply = 2,
103 };
104 struct arp_hdr {
105 uint16_t htype;
106 uint16_t ptype;
107 uint8_t hlen;
108 uint8_t plen;
109 uint16_t oper;
110 l2addr sender_hwaddr;
111 l3addr sender_paddr;
112 l2addr target_hwaddr;
113 l3addr target_paddr;
114
115 arp_hdr ntoh() {
116 arp_hdr hdr = *this;
117 hdr.htype = ::ntoh(htype);
118 hdr.ptype = ::ntoh(ptype);
119 hdr.oper = ::ntoh(oper);
120 hdr.sender_hwaddr = sender_hwaddr.ntoh();
121 hdr.sender_paddr = sender_paddr.ntoh();
122 hdr.target_hwaddr = target_hwaddr.ntoh();
123 hdr.target_paddr = target_paddr.ntoh();
124 return hdr;
125 }
126
127 arp_hdr hton() {
128 arp_hdr hdr = *this;
129 hdr.htype = ::hton(htype);
130 hdr.ptype = ::hton(ptype);
131 hdr.oper = ::hton(oper);
132 hdr.sender_hwaddr = sender_hwaddr.hton();
133 hdr.sender_paddr = sender_paddr.hton();
134 hdr.target_hwaddr = target_hwaddr.hton();
135 hdr.target_paddr = target_paddr.hton();
136 return hdr;
137 }
138 };
139 struct resolution {
140 std::vector<std::pair<resolution_cb, Packet>> _waiters;
141 uint64_t timeout_fd;
142 };
143 class C_handle_arp_timeout : public EventCallback {
144 arp_for *arp;
145 l3addr paddr;
146 bool first_request;
147
148 public:
149 C_handle_arp_timeout(arp_for *a, l3addr addr, bool first):
150 arp(a), paddr(addr), first_request(first) {}
151 void do_request(uint64_t r) {
152 arp->send_query(paddr);
153 auto &res = arp->_in_progress[paddr];
154
155 for (auto& p : res._waiters) {
156 p.first(ethernet_address(), std::move(p.second), -ETIMEDOUT);
157 }
158 res._waiters.clear();
159 res.timeout_fd = arp->center->create_time_event(
160 1*1000*1000, this);
161 }
162 };
163 friend class C_handle_arp_timeout;
164
165 private:
166 CephContext *cct;
167 EventCenter *center;
168 l3addr _l3self = L3::broadcast_address();
169 std::unordered_map<l3addr, l2addr> _table;
170 std::unordered_map<l3addr, resolution> _in_progress;
171 private:
172 Packet make_query_packet(l3addr paddr);
173 virtual int received(Packet p) override;
174 int handle_request(arp_hdr* ah);
175 l2addr l2self() { return _arp.l2self(); }
176 void send(l2addr to, Packet &&p);
177 public:
178 void send_query(const l3addr& paddr);
179 explicit arp_for(CephContext *c, arp& a, EventCenter *cen)
180 : arp_for_protocol(a, L3::arp_protocol_type()), cct(c), center(cen) {
181 _table[L3::broadcast_address()] = ethernet::broadcast_address();
182 }
183 ~arp_for() {
184 for (auto && p : _in_progress)
185 center->delete_time_event(p.second.timeout_fd);
186 }
187 void wait(const l3addr& addr, Packet p, resolution_cb cb);
188 void learn(l2addr l2, l3addr l3);
189 void run();
190 void set_self_addr(l3addr addr) {
191 _table.erase(_l3self);
192 _table[addr] = l2self();
193 _l3self = addr;
194 }
195 friend class arp;
196 };
197
198 template <typename L3>
199 void arp_for<L3>::send(l2addr to, Packet &&p) {
200 _arp._packetq.push_back(l3_protocol::l3packet{eth_protocol_num::arp, to, std::move(p)});
201 }
202
203 template <typename L3>
204 Packet arp_for<L3>::make_query_packet(l3addr paddr) {
205 arp_hdr hdr;
206 hdr.htype = ethernet::arp_hardware_type();
207 hdr.ptype = L3::arp_protocol_type();
208 hdr.hlen = sizeof(l2addr);
209 hdr.plen = sizeof(l3addr);
210 hdr.oper = op_request;
211 hdr.sender_hwaddr = l2self();
212 hdr.sender_paddr = _l3self;
213 hdr.target_hwaddr = ethernet::broadcast_address();
214 hdr.target_paddr = paddr;
215 hdr = hdr.hton();
216 return Packet(reinterpret_cast<char*>(&hdr), sizeof(hdr));
217 }
218
219 template <typename L3>
220 void arp_for<L3>::send_query(const l3addr& paddr) {
221 send(ethernet::broadcast_address(), make_query_packet(paddr));
222 }
223
224 template <typename L3>
225 void arp_for<L3>::learn(l2addr hwaddr, l3addr paddr) {
226 _table[paddr] = hwaddr;
227 auto i = _in_progress.find(paddr);
228 if (i != _in_progress.end()) {
229 auto& res = i->second;
230 center->delete_time_event(res.timeout_fd);
231 for (auto &&p : res._waiters) {
232 p.first(hwaddr, std::move(p.second), 0);
233 }
234 _in_progress.erase(i);
235 }
236 }
237
238 template <typename L3>
239 void arp_for<L3>::wait(const l3addr& paddr, Packet p, resolution_cb cb) {
240 auto i = _table.find(paddr);
241 if (i != _table.end()) {
242 cb(i->second, std::move(p), 0);
243 return ;
244 }
245
246 auto j = _in_progress.find(paddr);
247 auto first_request = j == _in_progress.end();
248 auto& res = first_request ? _in_progress[paddr] : j->second;
249
250 if (first_request) {
251 res.timeout_fd = center->create_time_event(
252 1*1000*1000, new C_handle_arp_timeout(this, paddr, first_request));
253 send_query(paddr);
254 }
255
256 if (res._waiters.size() >= max_waiters) {
257 cb(ethernet_address(), std::move(p), -EBUSY);
258 return ;
259 }
260
261 res._waiters.emplace_back(cb, std::move(p));
262 return ;
263 }
264
265 template <typename L3>
266 int arp_for<L3>::received(Packet p) {
267 auto ah = p.get_header<arp_hdr>();
268 if (!ah) {
269 return 0;
270 }
271 auto h = ah->ntoh();
272 if (h.hlen != sizeof(l2addr) || h.plen != sizeof(l3addr)) {
273 return 0;
274 }
275 switch (h.oper) {
276 case op_request:
277 return handle_request(&h);
278 case op_reply:
279 _arp._netif->arp_learn(h.sender_hwaddr, h.sender_paddr);
280 return 0;
281 default:
282 return 0;
283 }
284 }
285
286 template <typename L3>
287 int arp_for<L3>::handle_request(arp_hdr* ah) {
288 if (ah->target_paddr == _l3self
289 && _l3self != L3::broadcast_address()) {
290 ah->oper = op_reply;
291 ah->target_hwaddr = ah->sender_hwaddr;
292 ah->target_paddr = ah->sender_paddr;
293 ah->sender_hwaddr = l2self();
294 ah->sender_paddr = _l3self;
295 *ah = ah->hton();
296 send(ah->target_hwaddr, Packet(reinterpret_cast<char*>(ah), sizeof(*ah)));
297 }
298 return 0;
299 }
300
301 #endif /* CEPH_MSG_ARP_H_ */