Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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  * Ceph - scalable distributed file system
25  *
26  * Copyright (C) 2015 XSky <haomai@xsky.com>
27  *
28  * Author: Haomai Wang <haomaiwang@gmail.com>
29  *
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.
34  *
35  */
36
37 #ifndef CEPH_MSG_ARP_H_
38 #define CEPH_MSG_ARP_H_
39
40 #include <errno.h>
41
42 #include <unordered_map>
43 #include <functional>
44
45 #include "msg/async/Event.h"
46
47 #include "ethernet.h"
48 #include "circular_buffer.h"
49 #include "ip_types.h"
50 #include "net.h"
51 #include "Packet.h"
52
53 class arp;
54 template <typename L3>
55 class arp_for;
56
57 class arp_for_protocol {
58  protected:
59   arp& _arp;
60   uint16_t _proto_num;
61  public:
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; }
66 };
67
68 class interface;
69
70 class arp {
71   interface* _netif;
72   l3_protocol _proto;
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;
76  private:
77   struct arp_hdr {
78     uint16_t htype;
79     uint16_t ptype;
80     arp_hdr ntoh() {
81       arp_hdr hdr = *this;
82       hdr.htype = ::ntoh(htype);
83       hdr.ptype = ::ntoh(ptype);
84       return hdr;
85     }
86     arp_hdr hton() {
87       arp_hdr hdr = *this;
88       hdr.htype = ::hton(htype);
89       hdr.ptype = ::hton(ptype);
90       return hdr;
91     }
92   };
93  public:
94   explicit arp(interface* netif);
95   void add(uint16_t proto_num, arp_for_protocol* afp);
96   void del(uint16_t proto_num);
97  private:
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;
104 };
105
106 template <typename L3>
107 class arp_for : public arp_for_protocol {
108  public:
109   using l2addr = ethernet_address;
110   using l3addr = typename L3::address_type;
111  private:
112   static constexpr auto max_waiters = 512;
113   enum oper {
114     op_request = 1,
115     op_reply = 2,
116   };
117   struct arp_hdr {
118     uint16_t htype;
119     uint16_t ptype;
120     uint8_t hlen;
121     uint8_t plen;
122     uint16_t oper;
123     l2addr sender_hwaddr;
124     l3addr sender_paddr;
125     l2addr target_hwaddr;
126     l3addr target_paddr;
127
128     arp_hdr ntoh() {
129       arp_hdr hdr = *this;
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();
137       return hdr;
138     }
139
140     arp_hdr hton() {
141       arp_hdr hdr = *this;
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();
149       return hdr;
150     }
151   };
152   struct resolution {
153     std::vector<std::pair<resolution_cb, Packet>> _waiters;
154     uint64_t timeout_fd;
155   };
156   class C_handle_arp_timeout : public EventCallback {
157     arp_for *arp;
158     l3addr paddr;
159     bool first_request;
160
161    public:
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];
167
168       for (auto& p : res._waiters) {
169         p.first(ethernet_address(), std::move(p.second), -ETIMEDOUT);
170       }
171       res._waiters.clear();
172       res.timeout_fd = arp->center->create_time_event(
173           1*1000*1000, this);
174     }
175   };
176   friend class C_handle_arp_timeout;
177
178  private:
179   CephContext *cct;
180   EventCenter *center;
181   l3addr _l3self = L3::broadcast_address();
182   std::unordered_map<l3addr, l2addr> _table;
183   std::unordered_map<l3addr, resolution> _in_progress;
184  private:
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);
190  public:
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();
195   }
196   ~arp_for() {
197     for (auto && p : _in_progress)
198       center->delete_time_event(p.second.timeout_fd);
199   }
200   void wait(const l3addr& addr, Packet p, resolution_cb cb);
201   void learn(l2addr l2, l3addr l3);
202   void run();
203   void set_self_addr(l3addr addr) {
204     _table.erase(_l3self);
205     _table[addr] = l2self();
206     _l3self = addr;
207   }
208   friend class arp;
209 };
210
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)});
214 }
215
216 template <typename L3>
217 Packet arp_for<L3>::make_query_packet(l3addr paddr) {
218   arp_hdr hdr;
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;
228   hdr = hdr.hton();
229   return Packet(reinterpret_cast<char*>(&hdr), sizeof(hdr));
230 }
231
232 template <typename L3>
233 void arp_for<L3>::send_query(const l3addr& paddr) {
234   send(ethernet::broadcast_address(), make_query_packet(paddr));
235 }
236
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);
246     }
247     _in_progress.erase(i);
248   }
249 }
250
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);
256     return ;
257   }
258
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;
262
263   if (first_request) {
264     res.timeout_fd = center->create_time_event(
265         1*1000*1000, new C_handle_arp_timeout(this, paddr, first_request));
266     send_query(paddr);
267   }
268
269   if (res._waiters.size() >= max_waiters) {
270     cb(ethernet_address(), std::move(p), -EBUSY);
271     return ;
272   }
273
274   res._waiters.emplace_back(cb, std::move(p));
275   return ;
276 }
277
278 template <typename L3>
279 int arp_for<L3>::received(Packet p) {
280   auto ah = p.get_header<arp_hdr>();
281   if (!ah) {
282     return 0;
283   }
284   auto h = ah->ntoh();
285   if (h.hlen != sizeof(l2addr) || h.plen != sizeof(l3addr)) {
286     return 0;
287   }
288   switch (h.oper) {
289     case op_request:
290       return handle_request(&h);
291     case op_reply:
292       _arp._netif->arp_learn(h.sender_hwaddr, h.sender_paddr);
293       return 0;
294     default:
295       return 0;
296   }
297 }
298
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()) {
303     ah->oper = op_reply;
304     ah->target_hwaddr = ah->sender_hwaddr;
305     ah->target_paddr = ah->sender_paddr;
306     ah->sender_hwaddr = l2self();
307     ah->sender_paddr = _l3self;
308     *ah = ah->hton();
309     send(ah->target_hwaddr, Packet(reinterpret_cast<char*>(ah), sizeof(*ah)));
310   }
311   return 0;
312 }
313
314 #endif /* CEPH_MSG_ARP_H_ */