]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/net/arp.hh
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / include / seastar / net / arp.hh
CommitLineData
11fdf7f2
TL
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18/*
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
20 *
21 */
22
23#pragma once
24
25#include <seastar/net/net.hh>
11fdf7f2
TL
26#include <seastar/core/byteorder.hh>
27#include <seastar/net/ethernet.hh>
11fdf7f2
TL
28#include <unordered_map>
29
30namespace seastar {
31
32namespace net {
33
34class arp;
35class arp_for_protocol;
36template <typename L3>
37class arp_for;
38
39class arp_for_protocol {
40protected:
41 arp& _arp;
42 uint16_t _proto_num;
43public:
44 arp_for_protocol(arp& a, uint16_t proto_num);
45 virtual ~arp_for_protocol();
46 virtual future<> received(packet p) = 0;
47 virtual bool forward(forward_hash& out_hash_data, packet& p, size_t off) { return false; }
48};
49
50class arp {
51 interface* _netif;
52 l3_protocol _proto;
11fdf7f2
TL
53 std::unordered_map<uint16_t, arp_for_protocol*> _arp_for_protocol;
54 circular_buffer<l3_protocol::l3packet> _packetq;
55private:
56 struct arp_hdr {
57 uint16_t htype;
58 uint16_t ptype;
59
60 static arp_hdr read(const char* p) {
61 arp_hdr ah;
62 ah.htype = consume_be<uint16_t>(p);
63 ah.ptype = consume_be<uint16_t>(p);
64 return ah;
65 }
66 static constexpr size_t size() { return 4; }
67 };
68public:
69 explicit arp(interface* netif);
70 void add(uint16_t proto_num, arp_for_protocol* afp);
71 void del(uint16_t proto_num);
72private:
73 ethernet_address l2self() { return _netif->hw_address(); }
74 future<> process_packet(packet p, ethernet_address from);
75 bool forward(forward_hash& out_hash_data, packet& p, size_t off);
f67539c2 76 std::optional<l3_protocol::l3packet> get_packet();
11fdf7f2
TL
77 template <class l3_proto>
78 friend class arp_for;
79};
80
81template <typename L3>
82class arp_for : public arp_for_protocol {
83public:
84 using l2addr = ethernet_address;
85 using l3addr = typename L3::address_type;
86private:
87 static constexpr auto max_waiters = 512;
88 enum oper {
89 op_request = 1,
90 op_reply = 2,
91 };
92 struct arp_hdr {
93 uint16_t htype;
94 uint16_t ptype;
95 uint8_t hlen;
96 uint8_t plen;
97 uint16_t oper;
98 l2addr sender_hwaddr;
99 l3addr sender_paddr;
100 l2addr target_hwaddr;
101 l3addr target_paddr;
102
103 static arp_hdr read(const char* p) {
104 arp_hdr ah;
105 ah.htype = consume_be<uint16_t>(p);
106 ah.ptype = consume_be<uint16_t>(p);
107 ah.hlen = consume_be<uint8_t>(p);
108 ah.plen = consume_be<uint8_t>(p);
109 ah.oper = consume_be<uint16_t>(p);
110 ah.sender_hwaddr = l2addr::consume(p);
111 ah.sender_paddr = l3addr::consume(p);
112 ah.target_hwaddr = l2addr::consume(p);
113 ah.target_paddr = l3addr::consume(p);
114 return ah;
115 }
116 void write(char* p) const {
117 produce_be<uint16_t>(p, htype);
118 produce_be<uint16_t>(p, ptype);
119 produce_be<uint8_t>(p, hlen);
120 produce_be<uint8_t>(p, plen);
121 produce_be<uint16_t>(p, oper);
122 sender_hwaddr.produce(p);
123 sender_paddr.produce(p);
124 target_hwaddr.produce(p);
125 target_paddr.produce(p);
126 }
127 static constexpr size_t size() {
128 return 8 + 2 * (l2addr::size() + l3addr::size());
129 }
130 };
131 struct resolution {
132 std::vector<promise<l2addr>> _waiters;
133 timer<> _timeout_timer;
134 };
135private:
136 l3addr _l3self = L3::broadcast_address();
137 std::unordered_map<l3addr, l2addr> _table;
138 std::unordered_map<l3addr, resolution> _in_progress;
139private:
140 packet make_query_packet(l3addr paddr);
141 virtual future<> received(packet p) override;
142 future<> handle_request(arp_hdr* ah);
143 l2addr l2self() { return _arp.l2self(); }
144 void send(l2addr to, packet p);
145public:
146 future<> send_query(const l3addr& paddr);
147 explicit arp_for(arp& a) : arp_for_protocol(a, L3::arp_protocol_type()) {
148 _table[L3::broadcast_address()] = ethernet::broadcast_address();
149 }
150 future<ethernet_address> lookup(const l3addr& addr);
151 void learn(l2addr l2, l3addr l3);
152 void run();
153 void set_self_addr(l3addr addr) {
154 _table.erase(_l3self);
155 _table[addr] = l2self();
156 _l3self = addr;
157 }
158 friend class arp;
159};
160
161template <typename L3>
162packet
163arp_for<L3>::make_query_packet(l3addr paddr) {
164 arp_hdr hdr;
165 hdr.htype = ethernet::arp_hardware_type();
166 hdr.ptype = L3::arp_protocol_type();
167 hdr.hlen = sizeof(l2addr);
168 hdr.plen = sizeof(l3addr);
169 hdr.oper = op_request;
170 hdr.sender_hwaddr = l2self();
171 hdr.sender_paddr = _l3self;
172 hdr.target_hwaddr = ethernet::broadcast_address();
173 hdr.target_paddr = paddr;
174 auto p = packet();
175 p.prepend_uninitialized_header(hdr.size());
176 hdr.write(p.get_header(0, hdr.size()));
177 return p;
178}
179
180template <typename L3>
181void arp_for<L3>::send(l2addr to, packet p) {
182 _arp._packetq.push_back(l3_protocol::l3packet{eth_protocol_num::arp, to, std::move(p)});
183}
184
185template <typename L3>
186future<>
187arp_for<L3>::send_query(const l3addr& paddr) {
188 send(ethernet::broadcast_address(), make_query_packet(paddr));
189 return make_ready_future<>();
190}
191
192class arp_error : public std::runtime_error {
193public:
194 arp_error(const std::string& msg) : std::runtime_error(msg) {}
195};
196
197class arp_timeout_error : public arp_error {
198public:
199 arp_timeout_error() : arp_error("ARP timeout") {}
200};
201
202class arp_queue_full_error : public arp_error {
203public:
204 arp_queue_full_error() : arp_error("ARP waiter's queue is full") {}
205};
206
207template <typename L3>
208future<ethernet_address>
209arp_for<L3>::lookup(const l3addr& paddr) {
210 auto i = _table.find(paddr);
211 if (i != _table.end()) {
212 return make_ready_future<ethernet_address>(i->second);
213 }
214 auto j = _in_progress.find(paddr);
215 auto first_request = j == _in_progress.end();
216 auto& res = first_request ? _in_progress[paddr] : j->second;
217
218 if (first_request) {
219 res._timeout_timer.set_callback([paddr, this, &res] {
9f95a23c
TL
220 // FIXME: future is discarded
221 (void)send_query(paddr);
11fdf7f2
TL
222 for (auto& w : res._waiters) {
223 w.set_exception(arp_timeout_error());
224 }
225 res._waiters.clear();
226 });
227 res._timeout_timer.arm_periodic(std::chrono::seconds(1));
9f95a23c
TL
228 // FIXME: future is discarded
229 (void)send_query(paddr);
11fdf7f2
TL
230 }
231
232 if (res._waiters.size() >= max_waiters) {
233 return make_exception_future<ethernet_address>(arp_queue_full_error());
234 }
235
236 res._waiters.emplace_back();
237 return res._waiters.back().get_future();
238}
239
240template <typename L3>
241void
242arp_for<L3>::learn(l2addr hwaddr, l3addr paddr) {
243 _table[paddr] = hwaddr;
244 auto i = _in_progress.find(paddr);
245 if (i != _in_progress.end()) {
246 auto& res = i->second;
247 res._timeout_timer.cancel();
248 for (auto &&pr : res._waiters) {
249 pr.set_value(hwaddr);
250 }
251 _in_progress.erase(i);
252 }
253}
254
255template <typename L3>
256future<>
257arp_for<L3>::received(packet p) {
258 auto ah = p.get_header(0, arp_hdr::size());
259 if (!ah) {
260 return make_ready_future<>();
261 }
262 auto h = arp_hdr::read(ah);
263 if (h.hlen != sizeof(l2addr) || h.plen != sizeof(l3addr)) {
264 return make_ready_future<>();
265 }
266 switch (h.oper) {
267 case op_request:
268 return handle_request(&h);
269 case op_reply:
270 arp_learn(h.sender_hwaddr, h.sender_paddr);
271 return make_ready_future<>();
272 default:
273 return make_ready_future<>();
274 }
275}
276
277template <typename L3>
278future<>
279arp_for<L3>::handle_request(arp_hdr* ah) {
280 if (ah->target_paddr == _l3self
281 && _l3self != L3::broadcast_address()) {
282 ah->oper = op_reply;
283 ah->target_hwaddr = ah->sender_hwaddr;
284 ah->target_paddr = ah->sender_paddr;
285 ah->sender_hwaddr = l2self();
286 ah->sender_paddr = _l3self;
287 auto p = packet();
288 ah->write(p.prepend_uninitialized_header(ah->size()));
289 send(ah->target_hwaddr, std::move(p));
290 }
291 return make_ready_future<>();
292}
293
294}
295
296}