Click
Loading...
Searching...
No Matches
dpdkdevice.hh
1#ifndef CLICK_DPDKDEVICE_HH
2#define CLICK_DPDKDEVICE_HH
3
9#ifndef UINT8_MAX
10#define UINT8_MAX 255
11#endif
12#ifndef UINT16_MAX
13#define UINT16_MAX 65535
14#endif
15
16#include <rte_common.h>
17#include <rte_eal.h>
18#include <rte_ethdev.h>
19#include <rte_lcore.h>
20#include <rte_mbuf.h>
21#include <rte_mempool.h>
22#include <rte_pci.h>
23#include <rte_version.h>
24
25#if RTE_VERSION >= RTE_VERSION_NUM(21, 02, 0, 0)
26#include <rte_power_pmd_mgmt.h>
27#endif
28
29
30
31#if HAVE_FLOW_API
32 #include <click/flowruleparser.hh>
33#endif
34
35#if RTE_VERSION >= RTE_VERSION_NUM(17,11,0,0) && RTE_VERSION < RTE_VERSION_NUM(19,2,0,0)
36 #include <rte_bus_pci.h>
37#endif
38
39#include <click/packet.hh>
40#include <click/error.hh>
41#include <click/hashtable.hh>
42#include <click/vector.hh>
43#include <click/args.hh>
44#include <click/etheraddress.hh>
45#include <click/timer.hh>
46#include <click/router.hh>
47
48#if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0)
49#define rte_ipv4_hdr ipv4_hdr
50#define rte_ether_addr ether_addr
51#endif
52#include <nicscheduler/ethernetdevice.hh>
53
54#if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0)
55#define rte_ipv4_hdr ipv4_hdr
56#define rte_ether_addr ether_addr
57#endif
58
64#ifndef PORTID_T_DEFINED
65 #define PORTID_T_DEFINED
66 typedef uint8_t portid_t;
67#else
68 // Already defined in <testpmd.h>
69#endif
70
71CLICK_DECLS
72
73enum FlowControlMode {FC_UNSET, FC_NONE, FC_RX, FC_TX, FC_FULL};
74
75class DPDKDeviceArg;
76
77#if HAVE_INT64_TYPES
78typedef uint64_t counter_t;
79#else
80typedef uint32_t counter_t;
81#endif
82
83extern bool dpdk_enabled;
84
85#ifdef RTE_PCI_ANY_ID
86#define MY_PCI_ANY_ID RTE_PCI_ANY_ID
87#else
88#define MY_PCI_ANY_ID PCI_ANY_ID
89#endif
90
91class DPDKDevice : public DPDKEthernetDevice {
92public:
93
94
95 DPDKDevice(portid_t port_id = -1) CLICK_COLD;
96
97 struct DevInfo {
98 inline DevInfo() :
99 vendor_id(MY_PCI_ANY_ID), vendor_name(), device_id(MY_PCI_ANY_ID), driver(0),
100 init_mac(), init_mtu(0), init_rss(-1), init_reta_size(-1), init_fc_mode(FC_UNSET),
101 rx_queues(0, false), tx_queues(0, false), n_rx_descs(0), n_tx_descs(0),
102 num_pools(0), promisc(false),
103 mq_mode((enum rte_eth_rx_mq_mode)-1), mq_mode_str(""),
104 rx_offload(0), tx_offload(0),
105 flow_isolate(false),
106 vlan_filter(false), vlan_strip(false), vlan_extend(false), vf_vlan(),
107 lro(false), jumbo(false)
108#if RTE_VERSION >= RTE_VERSION_NUM(21, 02, 0, 0)
109 , power_mgmt_mode(-1)
110#endif
111 {
112 rx_queues.reserve(128);
113 tx_queues.reserve(128);
114 }
115
116 void print_device_info() {
117 if (device_id == MY_PCI_ANY_ID) {
118 return;
119 }
120 click_chatter(" Vendor ID: %d", vendor_id);
121 click_chatter(" Vendor Name: %s", vendor_name.c_str());
122 click_chatter(" Device ID: %d", device_id);
123 click_chatter(" Driver Name: %s", driver);
124 click_chatter(" MAC Address: %s", init_mac.unparse().c_str());
125 click_chatter(" Maximum Transfer Unit: %u", init_mtu);
126 click_chatter("Receive Side Scaling queues: %d", init_rss);
127 click_chatter(" RETA Size: %d", init_reta_size);
128 click_chatter(" Flow Control Mode: %d", init_fc_mode);
129 click_chatter(" # of Rx Queues: %d", rx_queues.size());
130 click_chatter(" # of Tx Queues: %d", tx_queues.size());
131 click_chatter(" # of Rx Descs: %d", n_rx_descs);
132 click_chatter(" # of Tx Descs: %d", n_tx_descs);
133 click_chatter(" # of memory pools: %d", num_pools);
134 click_chatter(" Reception Mode: %s", mq_mode_str.c_str());
135 click_chatter(" Promiscuous Mode: %s", promisc? "true":"false");
136 click_chatter(" Flow API Isolation: %s", flow_isolate? "true":"false");
137 click_chatter(" Rx Offloads flag: %" PRIu64, rx_offload);
138 click_chatter(" Tx Offloads flag: %" PRIu64, tx_offload);
139 click_chatter(" VLAN Filtering: %s", vlan_filter? "true":"false");
140 click_chatter(" VLAN Stripping: %s", vlan_strip? "true":"false");
141 click_chatter(" VLAN QinQ(extend): %s", vlan_extend? "true":"false");
142 click_chatter(" Virtual Function VLAN: %d", vf_vlan.size());
143 click_chatter("Large Receive Offload (LRO): %s", lro ? "true":"false");
144 click_chatter(" Rx Jumbo Frames Offload: %s", jumbo ? "true":"false");
145 }
146
147 uint16_t vendor_id;
148 String vendor_name;
149 uint16_t device_id;
150 const char *driver;
151 EtherAddress init_mac;
152 uint16_t init_mtu;
153 int init_rss;
154 int init_reta_size;
155 FlowControlMode init_fc_mode;
156 Vector<bool> rx_queues;
157 Vector<bool> tx_queues;
158 unsigned n_rx_descs;
159 unsigned n_tx_descs;
160 int num_pools;
161 bool promisc;
162 enum rte_eth_rx_mq_mode mq_mode;
163 String mq_mode_str;
164 uint64_t rx_offload;
165 uint64_t tx_offload;
166 bool flow_isolate;
167 bool vlan_filter;
168 bool vlan_strip;
169 bool vlan_extend;
170 Vector<int> vf_vlan;
171 bool lro;
172 bool jumbo;
173
174#if RTE_VERSION >= RTE_VERSION_NUM(21, 02, 0, 0)
175 int power_mgmt_mode;
176#endif
177 };
178
179#if HAVE_FLOW_API
180 void initialize_flow_rule_manager(
181 const portid_t &port_id,
182 ErrorHandler *errh
183 );
184#endif
185
186 portid_t get_port_id() { return port_id; }
187
188 int add_rx_queue(
189 unsigned &queue_id, bool promisc, bool vlan_filter, bool vlan_strip, bool vlan_extend,
190 bool lro, bool jumbo, unsigned n_desc, ErrorHandler *errh
191 ) CLICK_COLD;
192
193 int add_tx_queue(
194 unsigned &queue_id, unsigned n_desc,
195 ErrorHandler *errh
196 ) CLICK_COLD;
197
198 EtherAddress get_mac();
199 void set_init_mac(EtherAddress mac);
200 void set_init_mtu(uint16_t mtu);
201 void set_init_rss_max(int rss_max);
202 void set_init_reta_size(int reta_size);
203 void set_init_fc_mode(FlowControlMode fc);
204 void set_rx_offload(uint64_t offload);
205 void set_tx_offload(uint64_t offload);
206
207#if RTE_VERSION >= RTE_VERSION_NUM(21, 02, 0, 0)
208 void set_power_mgmt(enum rte_power_pmd_mgmt_type mode);
209#endif
210
211#if RTE_VERSION >= RTE_VERSION_NUM(18,05,0,0)
212 void set_init_flow_isolate(const bool &flow_isolate);
213
214 inline void set_isolation_mode(const bool &isolated) {
215 info.flow_isolate = isolated;
216 if (info.flow_isolate) {
217 rte_flow_isolate(port_id, 1, 0);
218 } else {
219 rte_flow_isolate(port_id, 0, 0);
220 }
221 };
222 inline bool isolated() { return info.flow_isolate; };
223#endif
224
225
226 unsigned int get_nb_rxdesc();
227 unsigned int get_nb_txdesc();
228
229 uint16_t get_device_vendor_id();
230 String get_device_vendor_name();
231 uint16_t get_device_id();
232 const char *get_device_driver();
233
234 int dpdk_set_rss_max(int max, unsigned reta_sz = -1);
235 int dpdk_set_rss_reta(unsigned* reta, unsigned reta_sz);
236 int dpdk_get_rss_reta_size() const;
237 Vector<unsigned> dpdk_get_rss_reta() const;
238
239 EthernetDevice* get_eth_device();
240
241 static unsigned int dev_count() {
242#if RTE_VERSION >= RTE_VERSION_NUM(18,05,0,0)
243 return rte_eth_dev_count_avail();
244#else
245 return rte_eth_dev_count();
246#endif
247 }
248
249 static struct rte_mempool *get_mpool(unsigned int);
250
251 static int get_port_numa_node(portid_t port_id);
252
253 static Router::ChildrenFuture all_initialized;
254
255#if HAVE_FLOW_API
256 int set_mode(
257 String mode, int num_pools, Vector<int> vf_vlan,
258 const String &flow_rules_filename, ErrorHandler *errh
259 );
260#else
261 int set_mode(
262 String mode, int num_pools, Vector<int> vf_vlan,
263 ErrorHandler *errh
264 );
265#endif
266 rte_eth_rx_mq_mode get_mode();
267 String get_mode_str();
268
269 static int initialize(ErrorHandler *errh);
270
271 static int static_initialize(ErrorHandler *errh);
272
273 static int static_cleanup();
274
275#if CLICK_PACKET_USE_DPDK
276 inline static bool is_dpdk_packet(Packet* p) {
277 return true;
278 }
279
280 inline static bool is_dpdk_buffer(Packet* p) {
281 return true;
282 }
283#else
284 inline static bool is_dpdk_packet(Packet* p) {
285 return p->buffer_destructor() == DPDKDevice::free_pkt;
286 }
287
288 inline static bool is_dpdk_buffer(Packet* p) {
289 return is_dpdk_packet(p)
290#ifndef CLICK_NOINDIRECT
291 || (p->data_packet() && is_dpdk_packet(p->data_packet()))
292#endif
293 ;
294 }
295#endif
296
297
298 inline void kill_ref(Packet* p);
299
300 inline static rte_mbuf* get_pkt(unsigned numa_node);
301 inline static rte_mbuf* get_pkt();
302 inline static struct rte_mbuf* get_mbuf(Packet* p, bool create, int node, bool reset = true);
303
304 static WritablePacket* make_extbuf(unsigned char *data, uint32_t length,
305 Packet::buffer_destructor_type destructor, void* argument, int headroom, int tailroom, bool clear);
306
307 static void free_pkt(unsigned char *, size_t, void *pktmbuf);
308
309 static unsigned int get_nb_txdesc(const portid_t &port_id);
310
311#if HAVE_FLOW_API
312 static int configure_nic(const portid_t &port_id);
313#endif
314
315 static void cleanup(ErrorHandler *errh);
316
317 static Vector<int> NB_MBUF;
318 static int DEFAULT_NB_MBUF;
319 static int MBUF_DATA_SIZE;
320 static int MBUF_SIZE;
321 static int MBUF_CACHE_SIZE;
322 static int RX_PTHRESH;
323 static int RX_HTHRESH;
324 static int RX_WTHRESH;
325 static int TX_PTHRESH;
326 static int TX_HTHRESH;
327 static int TX_WTHRESH;
328 static String MEMPOOL_PREFIX;
329
330 static unsigned DEF_DEV_RXDESC;
331 static unsigned DEF_DEV_TXDESC;
332
333 static unsigned DEF_RING_NDESC;
334 static unsigned DEF_BURST_SIZE;
335
336 static unsigned RING_FLAGS;
337 static unsigned RING_SIZE;
338 static unsigned RING_POOL_CACHE_SIZE;
339 static unsigned RING_PRIV_DATA_SIZE;
340
341 static struct rte_mempool** _pktmbuf_pools;
342
343 inline struct DevInfo get_info() { return info; };
344 inline int nb_rx_queues();
345 inline int nb_tx_queues();
346 inline int nb_vf_pools();
347
348 struct rte_ether_addr gen_mac(int a, int b);
349
350 /*
351 * TXInternalQueue is a ring of DPDK buffers pointers (rte_mbuf *) awaiting
352 * to be sent. It is used as an internal buffer to be passed to DPDK ring
353 * queue.
354 * |-> index is the index of the first valid packet awaiting to be sent, while
355 * nr_pending is the number of packets.
356 * |-> index + nr_pending may be greater than
357 * _internal_tx_queue_size but index should be wrapped-around.
358 */
359 class TXInternalQueue {
360 public:
361 TXInternalQueue() : pkts(0), index(0), nr_pending(0), timeout() { }
362
363 // Array of DPDK Buffers
364 struct rte_mbuf **pkts;
365 // Index of the first valid packet in the packets array
366 unsigned int index;
367 // Number of valid packets awaiting to be sent after index
368 unsigned int nr_pending;
369
370 // Timer to limit time a batch will take to be completed
371 Timer timeout;
372 } __attribute__((aligned(64)));
373
374 static bool initialized() {
375 return _is_initialized;
376 }
377
378private:
379
380 enum Dir { RX, TX };
381
382 struct DevInfo info;
383
384
385 static int get_nb_mbuf(int socket);
386 static bool _is_initialized;
388 static unsigned _nr_pktmbuf_pools;
389 static bool no_more_buffer_msg_printed;
390
391 int initialize_device(ErrorHandler *errh) CLICK_COLD;
392 int add_queue(Dir dir, unsigned &queue_id,
393 bool promisc, bool vlan_filter, bool vlan_strip, bool vlan_extend,
394 bool lro, bool jumbo, unsigned n_desc, ErrorHandler *errh) CLICK_COLD;
395
396 static int alloc_pktmbufs(ErrorHandler* errh) CLICK_COLD;
397
398 static DPDKDevice *ensure_device(const portid_t &port_id) {
399 auto it = _devs.find_insert(port_id, new DPDKDevice(port_id));
400
401 return it.value();
402 }
403
404 static DPDKDevice* get_device(const portid_t &port_id) {
405 return _devs.find(port_id).value();
406 }
407
408#if RTE_VERSION < RTE_VERSION_NUM(18,05,0,0)
409 static int get_port_from_pci(uint32_t domain, uint8_t bus, uint8_t dev_id, uint8_t function) {
410 struct rte_eth_dev_info dev_info;
411
412 uint16_t count = rte_eth_dev_count();
413 for (portid_t port_id = 0 ; port_id < count; ++port_id) {
414 rte_eth_dev_info_get(port_id, &dev_info);
415 struct rte_pci_addr addr = dev_info.pci_dev->addr;
416 if (addr.domain == domain &&
417 addr.bus == bus &&
418 addr.devid == dev_id &&
419 addr.function == function)
420 return port_id;
421 }
422
423 return -1;
424 }
425#endif
426
427 friend class DPDKDeviceArg;
428 friend class DPDKInfo;
429};
430
431class DPDKRing { public:
432
433 DPDKRing() CLICK_COLD;
434 ~DPDKRing() CLICK_COLD;
435
436 int parse(Args* args);
437
438 struct rte_mempool *_message_pool;
439 String _MEM_POOL;
440 String _PROC_1;
441 String _PROC_2;
442
443 unsigned _ndesc;
444 unsigned _burst_size;
445 short _numa_zone;
446 int _flags;
447
448 struct rte_ring *_ring;
449 counter_t _count;
450
451 bool _force_create;
452 bool _force_lookup;
453
454};
455
458class DPDKDeviceArg { public:
459 static bool parse(const String &str, DPDKDevice* &result, const ArgContext &args = ArgContext());
460 static String unparse(DPDKDevice* dev) {
461 return String(dev->port_id);
462 }
463};
464
465template<> struct DefaultArg<DPDKDevice*> : public DPDKDeviceArg {};
466
469class FlowControlModeArg { public:
470 static bool parse(const String &str, FlowControlMode &result, const ArgContext &args = ArgContext());
471 static String unparse(FlowControlMode mode);
472};
473
474template<> struct DefaultArg<FlowControlMode> : public FlowControlModeArg {};
475
483inline struct rte_mbuf* DPDKDevice::get_mbuf(Packet* p, bool create, int node, bool reset) {
484 struct rte_mbuf* mbuf;
485 #if CLICK_PACKET_USE_DPDK
486 mbuf = p->mb();
487 #elif CLICK_PACKET_INSIDE_DPDK
488 mbuf = ((struct rte_mbuf*)p) - 1;
489 rte_pktmbuf_pkt_len(mbuf) = p->length();
490 rte_pktmbuf_data_len(mbuf) = p->length();
491 mbuf->data_off = p->headroom();
492 #else
493 if (likely(DPDKDevice::is_dpdk_packet(p) && (mbuf = (struct rte_mbuf *)((unsigned char*) p->buffer() - sizeof(rte_mbuf)) ))
494#ifndef CLICK_NOINDIRECT
495 || unlikely(p->data_packet() && DPDKDevice::is_dpdk_packet(p->data_packet()) && (mbuf = (struct rte_mbuf *) p->data_packet()->destructor_argument()))
496#endif
497 ) {
498 /* If the packet is an unshared DPDK packet, we can send
499 * the mbuf as it to DPDK*/
500 rte_pktmbuf_pkt_len(mbuf) = p->length();
501 rte_pktmbuf_data_len(mbuf) = p->length();
502 mbuf->data_off = p->headroom();
503#ifndef CLICK_NOINDIRECT
504 if (p->shared()) {
505 /*Prevent DPDK from freeing the buffer. When all shared packet
506 * are freed, DPDKDevice::free_pkt will effectively destroy it.*/
507 rte_mbuf_refcnt_update(mbuf, 1);
508 } else
509#endif
510 {
511 //Reset buffer, let DPDK free the buffer when it wants
512 if (reset)
513 p->reset_buffer();
514 }
515 } else {
516 if (create) {
517 /*The packet is not a DPDK packet, or it is shared : we need to allocate a mbuf and
518 * copy the packet content to it.*/
519 mbuf = DPDKDevice::get_pkt(node);
520 if (mbuf == 0) {
521 return NULL;
522 }
523 memcpy((void*)rte_pktmbuf_mtod(mbuf, unsigned char *),p->data(),p->length());
524 rte_pktmbuf_pkt_len(mbuf) = p->length();
525 rte_pktmbuf_data_len(mbuf) = p->length();
526 } else
527 return NULL;
528 }
529 #endif
530 return mbuf;
531}
532
533inline void DPDKDevice::kill_ref(Packet* p) {
534 struct rte_mbuf* mbuf = get_mbuf(p,false,-1);
535 if (rte_mbuf_refcnt_read(mbuf) > 1)
536 rte_mbuf_refcnt_update(mbuf, -1);
537 else
538 p->kill();
539}
540
541inline rte_mbuf* DPDKDevice::get_pkt(unsigned numa_node) {
542 struct rte_mbuf* mbuf = rte_pktmbuf_alloc(get_mpool(numa_node));
543 if (unlikely(!mbuf)) {
544 if (!DPDKDevice::no_more_buffer_msg_printed)
545 click_chatter("No more DPDK buffer available ! Try using "
546 "DPDKInfo to allocate more.");
547 else
548 DPDKDevice::no_more_buffer_msg_printed = true;
549 }
550 return mbuf;
551}
552
553inline rte_mbuf* DPDKDevice::get_pkt() {
554 return get_pkt(rte_socket_id());
555}
556
557int DPDKDevice::nb_rx_queues() {
558 return info.rx_queues.size();
559};
560
561int DPDKDevice::nb_tx_queues() {
562 return info.tx_queues.size();
563};
564
565int DPDKDevice::nb_vf_pools() {
566 return info.num_pools;
567};
568
569CLICK_ENDDECLS
570
571#endif
Argument context class.
Definition args.hh:31
Argument parser class.
Definition args.hh:249
Parser class for DPDK Port, either an integer or a PCI address.
Definition dpdkdevice.hh:458
Error reporting class.
Definition error.hh:90
An Ethernet address.
Definition etheraddress.hh:9
Parser class for flow control mode.
Definition dpdkdevice.hh:469
Hash table template.
Definition hashtable.hh:570
iterator find_insert(key_const_reference key)
Ensure an element with key key and return its iterator.
Definition hashtable.hh:778
const_iterator find(key_const_reference key) const
Return an iterator for the element with key key, if any.
Definition hashtable.hh:693
A network packet.
Definition packet.hh:68
void kill()
Delete this packet.
Definition packet.hh:1804
const unsigned char * buffer() const
Return a pointer to the packet's data buffer.
Definition packet.hh:1243
const unsigned char * data() const
Return the packet's data pointer.
Definition packet.hh:1207
uint32_t length() const
Return the packet's length.
Definition packet.hh:1276
uint32_t headroom() const
Return the packet's headroom.
Definition packet.hh:1293
bool shared() const
Test whether this packet's data is shared.
Definition packet.hh:1985
A string of characters.
Definition string.hh:22
Triggers execution at a given time.
Definition timer.hh:14
Vector template.
Definition vector.hh:111
A network packet believed not to be shared.
Definition packet.hh:1004
Flexible error handling classes.
The EtherAddress type for Ethernet addresses.
Click's hash table container template.
The Packet class models packets in Click.
The Router class implementing a router configuration.
Support for Timer, which triggers execution at a given time.
Click's vector container template.