1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
//
// Copyright 2019 Ettus Research, a National Instruments brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#ifndef INCLUDED_UHDLIB_TRANSPORT_UDP_DPDK_LINK_HPP
#define INCLUDED_UHDLIB_TRANSPORT_UDP_DPDK_LINK_HPP
#include <uhd/config.hpp>
#include <uhd/transport/buffer_pool.hpp>
#include <uhd/types/device_addr.hpp>
#include <uhdlib/transport/dpdk/common.hpp>
#include <uhdlib/transport/link_if.hpp>
#include <uhdlib/transport/links.hpp>
#include <rte_udp.h>
#include <cassert>
#include <string>
#include <vector>
namespace uhd { namespace transport {
/*!
* A zero copy transport interface to the dpdk DMA library.
*/
class udp_dpdk_link : public virtual recv_link_if, public virtual send_link_if
{
public:
using sptr = std::shared_ptr<udp_dpdk_link>;
udp_dpdk_link(const dpdk::port_id_t port_id,
const std::string& remote_addr,
const std::string& remote_port,
const std::string& local_port,
const link_params_t& params);
~udp_dpdk_link();
/*!
* Make a new dpdk link. Get port ID from routing table.
*
* \param remote_addr Remote IP address
* \param remote_port Remote UDP port
* \param params Values for frame sizes, num frames, and buffer sizes
* \return a shared_ptr to a new udp dpdk link
*/
static sptr make(const std::string& remote_addr,
const std::string& remote_port,
const link_params_t& params);
/*!
* Make a new dpdk link. User specifies DPDK port ID directly.
*
* \param port_id DPDK port ID to use for communication
* \param remote_addr Remote IP address
* \param remote_port Remote UDP port
* \param local_port Local UDP port
* \param params Values for frame sizes, num frames, and buffer sizes
* \return a shared_ptr to a new udp dpdk link
*/
static sptr make(const dpdk::port_id_t port_id,
const std::string& remote_addr,
const std::string& remote_port,
const std::string& local_port,
const link_params_t& params);
/*!
* Get the associated dpdk_port
*
* \return a pointer to the dpdk_port used by this link
*/
inline dpdk::dpdk_port* get_port()
{
return _port;
}
/*!
* Get the DMA queue associated with this link
*
* \return the queue ID for this link's DMA queue
*/
inline dpdk::queue_id_t get_queue_id()
{
return _queue;
}
/*!
* Get the local UDP port used by this link
*
* \return the local UDP port, in network order
*/
inline uint16_t get_local_port()
{
return _local_port;
}
/*!
* Get the remote UDP port used by this link
*
* \return the remote UDP port, in network order
*/
inline uint16_t get_remote_port()
{
return _remote_port;
}
/*!
* Get the remote IPv4 address used by this link
*
* \return the remote IPv4 address, in network order
*/
inline uint32_t get_remote_ipv4()
{
return _remote_ipv4;
}
/*!
* Set the remote host's MAC address
* This MAC address must be filled in for the remote IPv4 address before
* the link can reach its destination.
*
* \param mac the remote host's MAC address
*/
inline void set_remote_mac(struct ether_addr& mac)
{
ether_addr_copy(&mac, &_remote_mac);
}
/*!
* Get the remote host's MAC address
*
* \param mac Where to write the MAC address
*/
inline void get_remote_mac(struct ether_addr& dst)
{
ether_addr_copy(&_remote_mac, &dst);
}
/*!
* Get the number of frame buffers that can be queued by this link.
*/
size_t get_num_send_frames() const
{
return _num_send_frames;
}
/*!
* Get the maximum capacity of a frame buffer.
*/
size_t get_send_frame_size() const
{
return _send_frame_size;
}
/*!
* Get the physical adapter ID used for this link
*/
inline adapter_id_t get_send_adapter_id() const
{
return _adapter_id;
}
/*!
* Get the number of frame buffers that can be queued by this link.
*/
size_t get_num_recv_frames() const
{
return _num_recv_frames;
}
/*!
* Get the maximum capacity of a frame buffer.
*/
size_t get_recv_frame_size() const
{
return _recv_frame_size;
}
/*!
* Get the physical adapter ID used for this link
*/
inline adapter_id_t get_recv_adapter_id() const
{
return _adapter_id;
}
/*!
* Enqueue a received mbuf, which can be pulled via get_recv_buff()
*/
void enqueue_recv_mbuf(struct rte_mbuf* mbuf);
/*!
* Receive a packet and return a frame buffer containing the packet data.
* The timeout argument is ignored.
*
* Received buffers are pulled from the frame buffer list. No buffers can
* be retrieved unless the corresponding rte_mbufs were placed in the list
* via the enqueue_recv_mbuf() method.
*
* \return a frame buffer, or null uptr if timeout occurs
*/
frame_buff::uptr get_recv_buff(int32_t /*timeout_ms*/);
/*!
* Release a frame buffer, allowing the link driver to reuse it.
*
* \param buffer frame buffer to release for reuse by the link
*/
void release_recv_buff(frame_buff::uptr buff);
/*!
* Get an empty frame buffer in which to write packet contents.
*
* \param timeout_ms a positive timeout value specifies the maximum number
of ms to wait, a negative value specifies to block
until successful, and a value of 0 specifies no wait.
* \return a frame buffer, or null uptr if timeout occurs
*/
frame_buff::uptr get_send_buff(int32_t /*timeout_ms*/);
/*!
* Send a packet with the contents of the frame buffer and release the
* buffer, allowing the link driver to reuse it. If the size of the frame
* buffer is 0, the buffer is released with no packet being sent.
*
* Note that this function will only fill in the L2 header and send the
* mbuf. The L3 and L4 headers, in addition to the lengths in the rte_mbuf
* fields, must be set in the I/O service.
*
* \param buffer frame buffer containing packet data
*
* Throws an exception if an I/O error occurs while sending
*/
void release_send_buff(frame_buff::uptr buff);
private:
//! A reference to the DPDK context
dpdk::dpdk_ctx::sptr _ctx;
//! The DPDK NIC port used by this link
dpdk::dpdk_port* _port;
//! Local UDP port, in network order
uint16_t _local_port;
//! Remote UDP port, in network order
uint16_t _remote_port;
//! Remote IPv4 address, in network order
uint32_t _remote_ipv4;
//! Remote host's MAC address
struct ether_addr _remote_mac;
//! Number of recv frames is not validated
size_t _num_recv_frames;
//! Maximum bytes of UDP payload data in recv frame
size_t _recv_frame_size;
//! Number of send frames is not validated
size_t _num_send_frames;
//! Maximum bytes of UDP payload data in send frame
size_t _send_frame_size;
//! Registered adapter ID for this link's DPDK NIC port
adapter_id_t _adapter_id;
//! The RX frame buff list head
dpdk::dpdk_frame_buff* _recv_buff_head = nullptr;
// TODO: Implement ability to use multiple queues
dpdk::queue_id_t _queue = 0;
};
}} // namespace uhd::transport
#endif /* INCLUDED_UHDLIB_TRANSPORT_UDP_DPDK_LINK_HPP */
|