]>
git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/dpdk/ARP.h
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 #ifndef CEPH_MSG_ARP_H_
25 #define CEPH_MSG_ARP_H_
29 #include <unordered_map>
32 #include "msg/async/Event.h"
35 #include "circular_buffer.h"
41 template <typename L3
>
44 class arp_for_protocol
{
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; }
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
;
69 hdr
.htype
= ::ntoh(htype
);
70 hdr
.ptype
= ::ntoh(ptype
);
75 hdr
.htype
= ::hton(htype
);
76 hdr
.ptype
= ::hton(ptype
);
81 explicit arp(interface
* netif
);
82 void add(uint16_t proto_num
, arp_for_protocol
* afp
);
83 void del(uint16_t proto_num
);
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
>
93 template <typename L3
>
94 class arp_for
: public arp_for_protocol
{
96 using l2addr
= ethernet_address
;
97 using l3addr
= typename
L3::address_type
;
99 static constexpr auto max_waiters
= 512;
110 l2addr sender_hwaddr
;
112 l2addr target_hwaddr
;
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();
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();
140 std::vector
<std::pair
<resolution_cb
, Packet
>> _waiters
;
143 class C_handle_arp_timeout
: public EventCallback
{
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
];
155 for (auto& p
: res
._waiters
) {
156 p
.first(ethernet_address(), std::move(p
.second
), -ETIMEDOUT
);
158 res
._waiters
.clear();
159 res
.timeout_fd
= arp
->center
->create_time_event(
163 friend class C_handle_arp_timeout
;
168 l3addr _l3self
= L3::broadcast_address();
169 std::unordered_map
<l3addr
, l2addr
> _table
;
170 std::unordered_map
<l3addr
, resolution
> _in_progress
;
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
);
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();
184 for (auto && p
: _in_progress
)
185 center
->delete_time_event(p
.second
.timeout_fd
);
187 void wait(const l3addr
& addr
, Packet p
, resolution_cb cb
);
188 void learn(l2addr l2
, l3addr l3
);
190 void set_self_addr(l3addr addr
) {
191 _table
.erase(_l3self
);
192 _table
[addr
] = l2self();
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
)});
203 template <typename L3
>
204 Packet arp_for
<L3
>::make_query_packet(l3addr paddr
) {
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
;
216 return Packet(reinterpret_cast<char*>(&hdr
), sizeof(hdr
));
219 template <typename L3
>
220 void arp_for
<L3
>::send_query(const l3addr
& paddr
) {
221 send(ethernet::broadcast_address(), make_query_packet(paddr
));
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);
234 _in_progress
.erase(i
);
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);
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
;
251 res
.timeout_fd
= center
->create_time_event(
252 1*1000*1000, new C_handle_arp_timeout(this, paddr
, first_request
));
256 if (res
._waiters
.size() >= max_waiters
) {
257 cb(ethernet_address(), std::move(p
), -EBUSY
);
261 res
._waiters
.emplace_back(cb
, std::move(p
));
265 template <typename L3
>
266 int arp_for
<L3
>::received(Packet p
) {
267 auto ah
= p
.get_header
<arp_hdr
>();
272 if (h
.hlen
!= sizeof(l2addr
) || h
.plen
!= sizeof(l3addr
)) {
277 return handle_request(&h
);
279 _arp
._netif
->arp_learn(h
.sender_hwaddr
, h
.sender_paddr
);
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()) {
291 ah
->target_hwaddr
= ah
->sender_hwaddr
;
292 ah
->target_paddr
= ah
->sender_paddr
;
293 ah
->sender_hwaddr
= l2self();
294 ah
->sender_paddr
= _l3self
;
296 send(ah
->target_hwaddr
, Packet(reinterpret_cast<char*>(ah
), sizeof(*ah
)));
301 #endif /* CEPH_MSG_ARP_H_ */