]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpcap/pcap-dpdk.c
sqlite3: Vendor import of sqlite3 3.45.0
[FreeBSD/FreeBSD.git] / contrib / libpcap / pcap-dpdk.c
1 /*
2  * Copyright (C) 2018 jingle YANG. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   1. Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  *   2. Redistributions in binary form must reproduce the above copyright
11  *      notice, this list of conditions and the following disclaimer in the
12  *      documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28 Date: Dec 16, 2018
29
30 Description:
31 1. Pcap-dpdk provides libpcap the ability to use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
32 2. DPDK is a set of libraries and drivers for fast packet processing. (https://www.dpdk.org/)
33 3. The testprogs/capturetest provides 6.4Gbps/800,000 pps on Intel 10-Gigabit X540-AT2 with DPDK 18.11.
34
35 Limitations:
36 1. DPDK support will be on if DPDK is available. Please set DIR for --with-dpdk[=DIR] with ./configure or -DDPDK_DIR[=DIR] with cmake if DPDK is installed manually.
37 2. Only support link libdpdk.so dynamically, because the libdpdk.a will not work correctly.
38 3. Only support read operation, and packet injection has not been supported yet.
39
40 Usage:
41 1. Compile DPDK as shared library and install.(https://github.com/DPDK/dpdk.git)
42
43 You shall modify the file $RTE_SDK/$RTE_TARGET/.config and set:
44 CONFIG_RTE_BUILD_SHARED_LIB=y
45 By the following command:
46 sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/' $RTE_SDK/$RTE_TARGET/.config
47
48 2. Launch l2fwd that is one of DPDK examples correctly, and get device information.
49
50 You shall learn how to bind nic with DPDK-compatible driver by $RTE_SDK/usertools/dpdk-devbind.py, such as igb_uio.
51 And enable hugepages by dpdk-setup.sh
52
53 Then launch the l2fwd with dynamic driver support. For example:
54 $RTE_SDK/examples/l2fwd/$RTE_TARGET/l2fwd -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so -- -p 0x1
55
56 3. Compile libpcap with dpdk options.
57
58 If DPDK has not been found automatically, you shall export DPDK environment variable which are used for compiling DPDK. And then pass $RTE_SDK/$RTE_TARGET to --with-dpdk or -DDPDK_DIR
59
60 export RTE_SDK={your DPDK base directory}
61 export RTE_TARGET={your target name}
62
63 3.1 With configure
64
65 ./configure --with-dpdk=$RTE_SDK/$RTE_TARGET && make -s all && make -s testprogs && make install
66
67 3.2 With cmake
68
69 mkdir -p build && cd build && cmake -DDPDK_DIR=$RTE_SDK/$RTE_TARGET ../ && make -s all && make -s testprogs && make install
70
71 4. Link your own program with libpcap, and use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
72 And you shall set DPDK configure options by environment variable DPDK_CFG
73 For example, the testprogs/capturetest could be lanched by:
74
75 env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so" ./capturetest -i dpdk:0
76 */
77
78 #ifdef HAVE_CONFIG_H
79 #include <config.h>
80 #endif
81
82 #include <errno.h>
83 #include <netdb.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88 #include <limits.h> /* for INT_MAX */
89 #include <time.h>
90
91 #include <sys/time.h>
92
93 //header for calling dpdk
94 #include <rte_config.h>
95 #include <rte_common.h>
96 #include <rte_errno.h>
97 #include <rte_log.h>
98 #include <rte_malloc.h>
99 #include <rte_memory.h>
100 #include <rte_eal.h>
101 #include <rte_launch.h>
102 #include <rte_atomic.h>
103 #include <rte_cycles.h>
104 #include <rte_lcore.h>
105 #include <rte_per_lcore.h>
106 #include <rte_branch_prediction.h>
107 #include <rte_interrupts.h>
108 #include <rte_random.h>
109 #include <rte_debug.h>
110 #include <rte_ether.h>
111 #include <rte_ethdev.h>
112 #include <rte_mempool.h>
113 #include <rte_mbuf.h>
114 #include <rte_bus.h>
115
116 #include "pcap-int.h"
117 #include "pcap-dpdk.h"
118
119 /*
120  * Deal with API changes that break source compatibility.
121  */
122
123 #ifdef HAVE_STRUCT_RTE_ETHER_ADDR
124 #define ETHER_ADDR_TYPE struct rte_ether_addr
125 #else
126 #define ETHER_ADDR_TYPE struct ether_addr
127 #endif
128
129 #define DPDK_DEF_LOG_LEV RTE_LOG_ERR
130 //
131 // This is set to 0 if we haven't initialized DPDK yet, 1 if we've
132 // successfully initialized it, a negative value, which is the negative
133 // of the rte_errno from rte_eal_init(), if we tried to initialize it
134 // and got an error.
135 //
136 static int is_dpdk_pre_inited=0;
137 #define DPDK_LIB_NAME "libpcap_dpdk"
138 #define DPDK_DESC "Data Plane Development Kit (DPDK) Interface"
139 #define DPDK_ERR_PERM_MSG "permission denied, DPDK needs root permission"
140 #define DPDK_ARGC_MAX 64
141 #define DPDK_CFG_MAX_LEN 1024
142 #define DPDK_DEV_NAME_MAX 32
143 #define DPDK_DEV_DESC_MAX 512
144 #define DPDK_CFG_ENV_NAME "DPDK_CFG"
145 #define DPDK_DEF_MIN_SLEEP_MS 1
146 static char dpdk_cfg_buf[DPDK_CFG_MAX_LEN];
147 #define DPDK_MAC_ADDR_SIZE 32
148 #define DPDK_DEF_MAC_ADDR "00:00:00:00:00:00"
149 #define DPDK_PCI_ADDR_SIZE 16
150 #define DPDK_DEF_CFG "--log-level=error -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so"
151 #define DPDK_PREFIX "dpdk:"
152 #define DPDK_PORTID_MAX 65535U
153 #define MBUF_POOL_NAME "mbuf_pool"
154 #define DPDK_TX_BUF_NAME "tx_buffer"
155 //The number of elements in the mbuf pool.
156 #define DPDK_NB_MBUFS 8192U
157 #define MEMPOOL_CACHE_SIZE 256
158 #define MAX_PKT_BURST 32
159 // Configurable number of RX/TX ring descriptors
160 #define RTE_TEST_RX_DESC_DEFAULT 1024
161 #define RTE_TEST_TX_DESC_DEFAULT 1024
162
163 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
164 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
165
166 #ifdef RTE_ETHER_MAX_JUMBO_FRAME_LEN
167 #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
168 #else
169 #define RTE_ETH_PCAP_SNAPLEN ETHER_MAX_JUMBO_FRAME_LEN
170 #endif
171
172 static struct rte_eth_dev_tx_buffer *tx_buffer;
173
174 struct dpdk_ts_helper{
175         struct timeval start_time;
176         uint64_t start_cycles;
177         uint64_t hz;
178 };
179 struct pcap_dpdk{
180         pcap_t * orig;
181         uint16_t portid; // portid of DPDK
182         int must_clear_promisc;
183         uint64_t bpf_drop;
184         int nonblock;
185         struct timeval required_select_timeout;
186         struct timeval prev_ts;
187         struct rte_eth_stats prev_stats;
188         struct timeval curr_ts;
189         struct rte_eth_stats curr_stats;
190         uint64_t pps;
191         uint64_t bps;
192         struct rte_mempool * pktmbuf_pool;
193         struct dpdk_ts_helper ts_helper;
194         ETHER_ADDR_TYPE eth_addr;
195         char mac_addr[DPDK_MAC_ADDR_SIZE];
196         char pci_addr[DPDK_PCI_ADDR_SIZE];
197         unsigned char pcap_tmp_buf[RTE_ETH_PCAP_SNAPLEN];
198 };
199
200 static struct rte_eth_conf port_conf = {
201         .rxmode = {
202                 .split_hdr_size = 0,
203         },
204         .txmode = {
205                 .mq_mode = ETH_MQ_TX_NONE,
206         },
207 };
208
209 static void     dpdk_fmt_errmsg_for_rte_errno(char *, size_t, int,
210     PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
211
212 /*
213  * Generate an error message based on a format, arguments, and an
214  * rte_errno, with a message for the rte_errno after the formatted output.
215  */
216 static void dpdk_fmt_errmsg_for_rte_errno(char *errbuf, size_t errbuflen,
217     int errnum, const char *fmt, ...)
218 {
219         va_list ap;
220         size_t msglen;
221         char *p;
222         size_t errbuflen_remaining;
223
224         va_start(ap, fmt);
225         vsnprintf(errbuf, errbuflen, fmt, ap);
226         va_end(ap);
227         msglen = strlen(errbuf);
228
229         /*
230          * Do we have enough space to append ": "?
231          * Including the terminating '\0', that's 3 bytes.
232          */
233         if (msglen + 3 > errbuflen) {
234                 /* No - just give them what we've produced. */
235                 return;
236         }
237         p = errbuf + msglen;
238         errbuflen_remaining = errbuflen - msglen;
239         *p++ = ':';
240         *p++ = ' ';
241         *p = '\0';
242         msglen += 2;
243         errbuflen_remaining -= 2;
244
245         /*
246          * Now append the string for the error code.
247          * rte_strerror() is thread-safe, at least as of dpdk 18.11,
248          * unlike strerror() - it uses strerror_r() rather than strerror()
249          * for UN*X errno values, and prints to what I assume is a per-thread
250          * buffer (based on the "PER_LCORE" in "RTE_DEFINE_PER_LCORE" used
251          * to declare the buffers statically) for DPDK errors.
252          */
253         snprintf(p, errbuflen_remaining, "%s", rte_strerror(errnum));
254 }
255
256 static int dpdk_init_timer(struct pcap_dpdk *pd){
257         gettimeofday(&(pd->ts_helper.start_time),NULL);
258         pd->ts_helper.start_cycles = rte_get_timer_cycles();
259         pd->ts_helper.hz = rte_get_timer_hz();
260         if (pd->ts_helper.hz == 0){
261                 return -1;
262         }
263         return 0;
264 }
265 static inline void calculate_timestamp(struct dpdk_ts_helper *helper,struct timeval *ts)
266 {
267         uint64_t cycles;
268         // delta
269         struct timeval cur_time;
270         cycles = rte_get_timer_cycles() - helper->start_cycles;
271         cur_time.tv_sec = (time_t)(cycles/helper->hz);
272         cur_time.tv_usec = (suseconds_t)((cycles%helper->hz)*1e6/helper->hz);
273         timeradd(&(helper->start_time), &cur_time, ts);
274 }
275
276 static uint32_t dpdk_gather_data(unsigned char *data, uint32_t len, struct rte_mbuf *mbuf)
277 {
278         uint32_t total_len = 0;
279         while (mbuf && (total_len+mbuf->data_len) < len ){
280                 rte_memcpy(data+total_len, rte_pktmbuf_mtod(mbuf,void *),mbuf->data_len);
281                 total_len+=mbuf->data_len;
282                 mbuf=mbuf->next;
283         }
284         return total_len;
285 }
286
287
288 static int dpdk_read_with_timeout(pcap_t *p, struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){
289         struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
290         int nb_rx = 0;
291         int timeout_ms = p->opt.timeout;
292         int sleep_ms = 0;
293         if (pd->nonblock){
294                 // In non-blocking mode, just read once, no matter how many packets are captured.
295                 nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
296         }else{
297                 // In blocking mode, read many times until packets are captured or timeout or break_loop is set.
298                 // if timeout_ms == 0, it may be blocked forever.
299                 while (timeout_ms == 0 || sleep_ms < timeout_ms){
300                         nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
301                         if (nb_rx){ // got packets within timeout_ms
302                                 break;
303                         }else{ // no packet arrives at this round.
304                                 if (p->break_loop){
305                                         break;
306                                 }
307                                 // sleep for a very short while.
308                                 // block sleep is the only choice, since usleep() will impact performance dramatically.
309                                 rte_delay_us_block(DPDK_DEF_MIN_SLEEP_MS*1000);
310                                 sleep_ms += DPDK_DEF_MIN_SLEEP_MS;
311                         }
312                 }
313         }
314         return nb_rx;
315 }
316
317 static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *cb_arg)
318 {
319         struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
320         int burst_cnt = 0;
321         int nb_rx = 0;
322         struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
323         struct rte_mbuf *m;
324         struct pcap_pkthdr pcap_header;
325         // In DPDK, pkt_len is sum of lengths for all segments. And data_len is for one segment
326         uint32_t pkt_len = 0;
327         uint32_t caplen = 0;
328         u_char *bp = NULL;
329         int i=0;
330         unsigned int gather_len =0;
331         int pkt_cnt = 0;
332         u_char *large_buffer=NULL;
333         int timeout_ms = p->opt.timeout;
334
335         /*
336          * This can conceivably process more than INT_MAX packets,
337          * which would overflow the packet count, causing it either
338          * to look like a negative number, and thus cause us to
339          * return a value that looks like an error, or overflow
340          * back into positive territory, and thus cause us to
341          * return a too-low count.
342          *
343          * Therefore, if the packet count is unlimited, we clip
344          * it at INT_MAX; this routine is not expected to
345          * process packets indefinitely, so that's not an issue.
346          */
347         if (PACKET_COUNT_IS_UNLIMITED(max_cnt))
348                 max_cnt = INT_MAX;
349
350         if (max_cnt < MAX_PKT_BURST){
351                 burst_cnt = max_cnt;
352         }else{
353                 burst_cnt = MAX_PKT_BURST;
354         }
355
356         while( pkt_cnt < max_cnt){
357                 if (p->break_loop){
358                         p->break_loop = 0;
359                         return PCAP_ERROR_BREAK;
360                 }
361                 // read once in non-blocking mode, or try many times waiting for timeout_ms.
362                 // if timeout_ms == 0, it will be blocked until one packet arrives or break_loop is set.
363                 nb_rx = dpdk_read_with_timeout(p, pkts_burst, burst_cnt);
364                 if (nb_rx == 0){
365                         if (pd->nonblock){
366                                 RTE_LOG(DEBUG, USER1, "dpdk: no packets available in non-blocking mode.\n");
367                         }else{
368                                 if (p->break_loop){
369                                         RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is set in blocking mode.\n");
370                                         p->break_loop = 0;
371                                         return PCAP_ERROR_BREAK;
372
373                                 }
374                                 RTE_LOG(DEBUG, USER1, "dpdk: no packets available for timeout %d ms in blocking mode.\n", timeout_ms);
375                         }
376                         // break if dpdk reads 0 packet, no matter in blocking(timeout) or non-blocking mode.
377                         break;
378                 }
379                 pkt_cnt += nb_rx;
380                 for ( i = 0; i < nb_rx; i++) {
381                         m = pkts_burst[i];
382                         calculate_timestamp(&(pd->ts_helper),&(pcap_header.ts));
383                         pkt_len = rte_pktmbuf_pkt_len(m);
384                         // caplen = min(pkt_len, p->snapshot);
385                         // caplen will not be changed, no matter how long the rte_pktmbuf
386                         caplen = pkt_len < (uint32_t)p->snapshot ? pkt_len: (uint32_t)p->snapshot;
387                         pcap_header.caplen = caplen;
388                         pcap_header.len = pkt_len;
389                         // volatile prefetch
390                         rte_prefetch0(rte_pktmbuf_mtod(m, void *));
391                         bp = NULL;
392                         if (m->nb_segs == 1)
393                         {
394                                 bp = rte_pktmbuf_mtod(m, u_char *);
395                         }else{
396                                 // use fast buffer pcap_tmp_buf if pkt_len is small, no need to call malloc and free
397                                 if ( pkt_len <= RTE_ETH_PCAP_SNAPLEN)
398                                 {
399                                         gather_len = dpdk_gather_data(pd->pcap_tmp_buf, RTE_ETH_PCAP_SNAPLEN, m);
400                                         bp = pd->pcap_tmp_buf;
401                                 }else{
402                                         // need call free later
403                                         large_buffer = (u_char *)malloc(caplen*sizeof(u_char));
404                                         gather_len = dpdk_gather_data(large_buffer, caplen, m);
405                                         bp = large_buffer;
406                                 }
407
408                         }
409                         if (bp){
410                                 if (p->fcode.bf_insns==NULL || pcap_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){
411                                         cb(cb_arg, &pcap_header, bp);
412                                 }else{
413                                         pd->bpf_drop++;
414                                 }
415                         }
416                         //free all pktmbuf
417                         rte_pktmbuf_free(m);
418                         if (large_buffer){
419                                 free(large_buffer);
420                                 large_buffer=NULL;
421                         }
422                 }
423         }
424         return pkt_cnt;
425 }
426
427 static int pcap_dpdk_inject(pcap_t *p, const void *buf _U_, int size _U_)
428 {
429         //not implemented yet
430         pcap_strlcpy(p->errbuf,
431             "dpdk error: Inject function has not been implemented yet",
432             PCAP_ERRBUF_SIZE);
433         return PCAP_ERROR;
434 }
435
436 static void pcap_dpdk_close(pcap_t *p)
437 {
438         struct pcap_dpdk *pd = p->priv;
439         if (pd==NULL)
440         {
441                 return;
442         }
443         if (pd->must_clear_promisc)
444         {
445                 rte_eth_promiscuous_disable(pd->portid);
446         }
447         rte_eth_dev_stop(pd->portid);
448         rte_eth_dev_close(pd->portid);
449         pcap_cleanup_live_common(p);
450 }
451
452 static void nic_stats_display(struct pcap_dpdk *pd)
453 {
454         uint16_t portid = pd->portid;
455         struct rte_eth_stats stats;
456         rte_eth_stats_get(portid, &stats);
457         RTE_LOG(INFO,USER1, "portid:%d, RX-packets: %-10"PRIu64"  RX-errors:  %-10"PRIu64
458                "  RX-bytes:  %-10"PRIu64"  RX-Imissed:  %-10"PRIu64"\n", portid, stats.ipackets, stats.ierrors,
459                stats.ibytes,stats.imissed);
460         RTE_LOG(INFO,USER1, "portid:%d, RX-PPS: %-10"PRIu64" RX-Mbps: %.2lf\n", portid, pd->pps, pd->bps/1e6f );
461 }
462
463 static int pcap_dpdk_stats(pcap_t *p, struct pcap_stat *ps)
464 {
465         struct pcap_dpdk *pd = p->priv;
466         calculate_timestamp(&(pd->ts_helper), &(pd->curr_ts));
467         rte_eth_stats_get(pd->portid,&(pd->curr_stats));
468         if (ps){
469                 ps->ps_recv = pd->curr_stats.ipackets;
470                 ps->ps_drop = pd->curr_stats.ierrors;
471                 ps->ps_drop += pd->bpf_drop;
472                 ps->ps_ifdrop = pd->curr_stats.imissed;
473         }
474         uint64_t delta_pkt = pd->curr_stats.ipackets - pd->prev_stats.ipackets;
475         struct timeval delta_tm;
476         timersub(&(pd->curr_ts),&(pd->prev_ts), &delta_tm);
477         uint64_t delta_usec = delta_tm.tv_sec*1e6+delta_tm.tv_usec;
478         uint64_t delta_bit = (pd->curr_stats.ibytes-pd->prev_stats.ibytes)*8;
479         RTE_LOG(DEBUG, USER1, "delta_usec: %-10"PRIu64" delta_pkt: %-10"PRIu64" delta_bit: %-10"PRIu64"\n", delta_usec, delta_pkt, delta_bit);
480         pd->pps = (uint64_t)(delta_pkt*1e6f/delta_usec);
481         pd->bps = (uint64_t)(delta_bit*1e6f/delta_usec);
482         nic_stats_display(pd);
483         pd->prev_stats = pd->curr_stats;
484         pd->prev_ts = pd->curr_ts;
485         return 0;
486 }
487
488 static int pcap_dpdk_setnonblock(pcap_t *p, int nonblock){
489         struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
490         pd->nonblock = nonblock;
491         return 0;
492 }
493
494 static int pcap_dpdk_getnonblock(pcap_t *p){
495         struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
496         return pd->nonblock;
497 }
498 static int check_link_status(uint16_t portid, struct rte_eth_link *plink)
499 {
500         // wait up to 9 seconds to get link status
501         rte_eth_link_get(portid, plink);
502         return plink->link_status == ETH_LINK_UP;
503 }
504 static void eth_addr_str(ETHER_ADDR_TYPE *addrp, char* mac_str, int len)
505 {
506         int offset=0;
507         if (addrp == NULL){
508                 snprintf(mac_str, len-1, DPDK_DEF_MAC_ADDR);
509                 return;
510         }
511         for (int i=0; i<6; i++)
512         {
513                 if (offset >= len)
514                 { // buffer overflow
515                         return;
516                 }
517                 if (i==0)
518                 {
519                         snprintf(mac_str+offset, len-1-offset, "%02X",addrp->addr_bytes[i]);
520                         offset+=2; // FF
521                 }else{
522                         snprintf(mac_str+offset, len-1-offset, ":%02X", addrp->addr_bytes[i]);
523                         offset+=3; // :FF
524                 }
525         }
526         return;
527 }
528 // return portid by device name, otherwise return -1
529 static uint16_t portid_by_device(char * device)
530 {
531         uint16_t ret = DPDK_PORTID_MAX;
532         int len = strlen(device);
533         int prefix_len = strlen(DPDK_PREFIX);
534         unsigned long ret_ul = 0L;
535         char *pEnd;
536         if (len<=prefix_len || strncmp(device, DPDK_PREFIX, prefix_len)) // check prefix dpdk:
537         {
538                 return ret;
539         }
540         //check all chars are digital
541         for (int i=prefix_len; device[i]; i++){
542                 if (device[i]<'0' || device[i]>'9'){
543                         return ret;
544                 }
545         }
546         ret_ul = strtoul(&(device[prefix_len]), &pEnd, 10);
547         if (pEnd == &(device[prefix_len]) || *pEnd != '\0'){
548                 return ret;
549         }
550         // too large for portid
551         if (ret_ul >= DPDK_PORTID_MAX){
552                 return ret;
553         }
554         ret = (uint16_t)ret_ul;
555         return ret;
556 }
557
558 static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv)
559 {
560         int cnt=0;
561         memset(dargv,0,sizeof(dargv[0])*DPDK_ARGC_MAX);
562         //current process name
563         int skip_space = 1;
564         int i=0;
565         RTE_LOG(INFO, USER1,"dpdk cfg: %s\n",dpdk_cfg);
566         // find first non space char
567         // The last opt is NULL
568         for (i=0;dpdk_cfg[i] && cnt<DPDK_ARGC_MAX-1;i++){
569                 if (skip_space && dpdk_cfg[i]!=' '){ // not space
570                         skip_space=!skip_space; // skip normal char
571                         dargv[cnt++] = dpdk_cfg+i;
572                 }
573                 if (!skip_space && dpdk_cfg[i]==' '){ // fint a space
574                         dpdk_cfg[i]=0x00; // end of this opt
575                         skip_space=!skip_space; // skip space char
576                 }
577         }
578         dargv[cnt]=NULL;
579         return cnt;
580 }
581
582 // only called once
583 // Returns:
584 //
585 //    1 on success;
586 //
587 //    0 if "the EAL cannot initialize on this system", which we treat as
588 //    meaning "DPDK isn't available";
589 //
590 //    a PCAP_ERROR_ code for other errors.
591 //
592 // If eaccess_not_fatal is non-zero, treat "a permissions issue" the way
593 // we treat "the EAL cannot initialize on this system".  We use that
594 // when trying to find DPDK devices, as we don't want to fail to return
595 // *any* devices just because we can't support DPDK; when we're trying
596 // to open a device, we need to return a permissions error in that case.
597 static int dpdk_pre_init(char * ebuf, int eaccess_not_fatal)
598 {
599         int dargv_cnt=0;
600         char *dargv[DPDK_ARGC_MAX];
601         char *ptr_dpdk_cfg = NULL;
602         int ret;
603         // globale var
604         if (is_dpdk_pre_inited != 0)
605         {
606                 // already inited; did that succeed?
607                 if (is_dpdk_pre_inited < 0)
608                 {
609                         // failed
610                         goto error;
611                 }
612                 else
613                 {
614                         // succeeded
615                         return 1;
616                 }
617         }
618         // init EAL
619         ptr_dpdk_cfg = getenv(DPDK_CFG_ENV_NAME);
620         // set default log level to debug
621         rte_log_set_global_level(DPDK_DEF_LOG_LEV);
622         if (ptr_dpdk_cfg == NULL)
623         {
624                 RTE_LOG(INFO,USER1,"env $DPDK_CFG is unset, so using default: %s\n",DPDK_DEF_CFG);
625                 ptr_dpdk_cfg = DPDK_DEF_CFG;
626         }
627         memset(dpdk_cfg_buf,0,sizeof(dpdk_cfg_buf));
628         snprintf(dpdk_cfg_buf,DPDK_CFG_MAX_LEN-1,"%s %s",DPDK_LIB_NAME,ptr_dpdk_cfg);
629         dargv_cnt = parse_dpdk_cfg(dpdk_cfg_buf,dargv);
630         ret = rte_eal_init(dargv_cnt,dargv);
631         if (ret == -1)
632         {
633                 // Indicate that we've called rte_eal_init() by setting
634                 // is_dpdk_pre_inited to the negative of the error code,
635                 // and process the error.
636                 is_dpdk_pre_inited = -rte_errno;
637                 goto error;
638         }
639         // init succeeded, so we do not need to do it again later.
640         is_dpdk_pre_inited = 1;
641         return 1;
642
643 error:
644         switch (-is_dpdk_pre_inited)
645         {
646                 case EACCES:
647                         // This "indicates a permissions issue.".
648                         RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG);
649                         // If we were told to treat this as just meaning
650                         // DPDK isn't available, do so.
651                         if (eaccess_not_fatal)
652                                 return 0;
653                         // Otherwise report a fatal error.
654                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
655                             "DPDK requires that it run as root");
656                         return PCAP_ERROR_PERM_DENIED;
657
658                 case EAGAIN:
659                         // This "indicates either a bus or system
660                         // resource was not available, setup may
661                         // be attempted again."
662                         // There's no such error in pcap, so I'm
663                         // not sure what we should do here.
664                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
665                             "Bus or system resource was not available");
666                         break;
667
668                 case EALREADY:
669                         // This "indicates that the rte_eal_init
670                         // function has already been called, and
671                         // cannot be called again."
672                         // That's not an error; set the "we've
673                         // been here before" flag and return
674                         // success.
675                         is_dpdk_pre_inited = 1;
676                         return 1;
677
678                 case EFAULT:
679                         // This "indicates the tailq configuration
680                         // name was not found in memory configuration."
681                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
682                             "The tailq configuration name was not found in the memory configuration");
683                         return PCAP_ERROR;
684
685                 case EINVAL:
686                         // This "indicates invalid parameters were
687                         // passed as argv/argc."  Those came from
688                         // the configuration file.
689                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
690                             "The configuration file has invalid parameters");
691                         break;
692
693                 case ENOMEM:
694                         // This "indicates failure likely caused by
695                         // an out-of-memory condition."
696                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
697                             "Out of memory");
698                         break;
699
700                 case ENODEV:
701                         // This "indicates memory setup issues."
702                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
703                             "An error occurred setting up memory");
704                         break;
705
706                 case ENOTSUP:
707                         // This "indicates that the EAL cannot
708                         // initialize on this system."  We treat
709                         // that as meaning DPDK isn't available
710                         // on this machine, rather than as a
711                         // fatal error, and let our caller decide
712                         // whether that's a fatal error (if trying
713                         // to activate a DPDK device) or not (if
714                         // trying to enumerate devices).
715                         return 0;
716
717                 case EPROTO:
718                         // This "indicates that the PCI bus is
719                         // either not present, or is not readable
720                         // by the eal."  Does "the PCI bus is not
721                         // present" mean "this machine has no PCI
722                         // bus", which strikes me as a "not available"
723                         // case?  If so, should "is not readable by
724                         // the EAL" also something we should treat
725                         // as a "not available" case?  If not, we
726                         // can't distinguish between the two, so
727                         // we're stuck.
728                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
729                             "PCI bus is not present or not readable by the EAL");
730                         break;
731
732                 case ENOEXEC:
733                         // This "indicates that a service core
734                         // failed to launch successfully."
735                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
736                             "A service core failed to launch successfully");
737                         break;
738
739                 default:
740                         //
741                         // That's not in the list of errors in
742                         // the documentation; let it be reported
743                         // as an error.
744                         //
745                         dpdk_fmt_errmsg_for_rte_errno(ebuf,
746                             PCAP_ERRBUF_SIZE, -is_dpdk_pre_inited,
747                             "dpdk error: dpdk_pre_init failed");
748                         break;
749         }
750         // Error.
751         return PCAP_ERROR;
752 }
753
754 static int pcap_dpdk_activate(pcap_t *p)
755 {
756         struct pcap_dpdk *pd = p->priv;
757         pd->orig = p;
758         int ret = PCAP_ERROR;
759         uint16_t nb_ports=0;
760         uint16_t portid= DPDK_PORTID_MAX;
761         unsigned nb_mbufs = DPDK_NB_MBUFS;
762         struct rte_eth_rxconf rxq_conf;
763         struct rte_eth_txconf txq_conf;
764         struct rte_eth_conf local_port_conf = port_conf;
765         struct rte_eth_dev_info dev_info;
766         int is_port_up = 0;
767         struct rte_eth_link link;
768         do{
769                 //init EAL; fail if we have insufficient permission
770                 char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
771                 ret = dpdk_pre_init(dpdk_pre_init_errbuf, 0);
772                 if (ret < 0)
773                 {
774                         // This returns a negative value on an error.
775                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
776                             "Can't open device %s: %s",
777                             p->opt.device, dpdk_pre_init_errbuf);
778                         // ret is set to the correct error
779                         break;
780                 }
781                 if (ret == 0)
782                 {
783                         // This means DPDK isn't available on this machine.
784                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
785                             "Can't open device %s: DPDK is not available on this machine",
786                             p->opt.device);
787                         return PCAP_ERROR_NO_SUCH_DEVICE;
788                 }
789
790                 ret = dpdk_init_timer(pd);
791                 if (ret<0)
792                 {
793                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
794                                 "dpdk error: Init timer is zero with device %s",
795                                 p->opt.device);
796                         ret = PCAP_ERROR;
797                         break;
798                 }
799
800                 nb_ports = rte_eth_dev_count_avail();
801                 if (nb_ports == 0)
802                 {
803                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
804                             "dpdk error: No Ethernet ports");
805                         ret = PCAP_ERROR;
806                         break;
807                 }
808
809                 portid = portid_by_device(p->opt.device);
810                 if (portid == DPDK_PORTID_MAX){
811                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
812                             "dpdk error: portid is invalid. device %s",
813                             p->opt.device);
814                         ret = PCAP_ERROR_NO_SUCH_DEVICE;
815                         break;
816                 }
817
818                 pd->portid = portid;
819
820                 if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
821                 {
822                         p->snapshot = MAXIMUM_SNAPLEN;
823                 }
824                 // create the mbuf pool
825                 pd->pktmbuf_pool = rte_pktmbuf_pool_create(MBUF_POOL_NAME, nb_mbufs,
826                         MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
827                         rte_socket_id());
828                 if (pd->pktmbuf_pool == NULL)
829                 {
830                         dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
831                             PCAP_ERRBUF_SIZE, rte_errno,
832                             "dpdk error: Cannot init mbuf pool");
833                         ret = PCAP_ERROR;
834                         break;
835                 }
836                 // config dev
837                 rte_eth_dev_info_get(portid, &dev_info);
838                 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
839                 {
840                         local_port_conf.txmode.offloads |=DEV_TX_OFFLOAD_MBUF_FAST_FREE;
841                 }
842                 // only support 1 queue
843                 ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
844                 if (ret < 0)
845                 {
846                         dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
847                             PCAP_ERRBUF_SIZE, -ret,
848                             "dpdk error: Cannot configure device: port=%u",
849                             portid);
850                         ret = PCAP_ERROR;
851                         break;
852                 }
853                 // adjust rx tx
854                 ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd);
855                 if (ret < 0)
856                 {
857                         dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
858                             PCAP_ERRBUF_SIZE, -ret,
859                             "dpdk error: Cannot adjust number of descriptors: port=%u",
860                             portid);
861                         ret = PCAP_ERROR;
862                         break;
863                 }
864                 // get MAC addr
865                 rte_eth_macaddr_get(portid, &(pd->eth_addr));
866                 eth_addr_str(&(pd->eth_addr), pd->mac_addr, DPDK_MAC_ADDR_SIZE-1);
867
868                 // init one RX queue
869                 rxq_conf = dev_info.default_rxconf;
870                 rxq_conf.offloads = local_port_conf.rxmode.offloads;
871                 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
872                                              rte_eth_dev_socket_id(portid),
873                                              &rxq_conf,
874                                              pd->pktmbuf_pool);
875                 if (ret < 0)
876                 {
877                         dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
878                             PCAP_ERRBUF_SIZE, -ret,
879                             "dpdk error: rte_eth_rx_queue_setup:port=%u",
880                             portid);
881                         ret = PCAP_ERROR;
882                         break;
883                 }
884
885                 // init one TX queue
886                 txq_conf = dev_info.default_txconf;
887                 txq_conf.offloads = local_port_conf.txmode.offloads;
888                 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
889                                 rte_eth_dev_socket_id(portid),
890                                 &txq_conf);
891                 if (ret < 0)
892                 {
893                         dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
894                             PCAP_ERRBUF_SIZE, -ret,
895                             "dpdk error: rte_eth_tx_queue_setup:port=%u",
896                             portid);
897                         ret = PCAP_ERROR;
898                         break;
899                 }
900                 // Initialize TX buffers
901                 tx_buffer = rte_zmalloc_socket(DPDK_TX_BUF_NAME,
902                                 RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
903                                 rte_eth_dev_socket_id(portid));
904                 if (tx_buffer == NULL)
905                 {
906                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
907                             "dpdk error: Cannot allocate buffer for tx on port %u", portid);
908                         ret = PCAP_ERROR;
909                         break;
910                 }
911                 rte_eth_tx_buffer_init(tx_buffer, MAX_PKT_BURST);
912                 // Start device
913                 ret = rte_eth_dev_start(portid);
914                 if (ret < 0)
915                 {
916                         dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
917                             PCAP_ERRBUF_SIZE, -ret,
918                             "dpdk error: rte_eth_dev_start:port=%u",
919                             portid);
920                         ret = PCAP_ERROR;
921                         break;
922                 }
923                 // set promiscuous mode
924                 if (p->opt.promisc){
925                         pd->must_clear_promisc=1;
926                         rte_eth_promiscuous_enable(portid);
927                 }
928                 // check link status
929                 is_port_up = check_link_status(portid, &link);
930                 if (!is_port_up){
931                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
932                             "dpdk error: link is down, port=%u",portid);
933                         ret = PCAP_ERROR_IFACE_NOT_UP;
934                         break;
935                 }
936                 // reset statistics
937                 rte_eth_stats_reset(pd->portid);
938                 calculate_timestamp(&(pd->ts_helper), &(pd->prev_ts));
939                 rte_eth_stats_get(pd->portid,&(pd->prev_stats));
940                 // format pcap_t
941                 pd->portid = portid;
942                 p->fd = pd->portid;
943                 if (p->snapshot <=0 || p->snapshot> MAXIMUM_SNAPLEN)
944                 {
945                         p->snapshot = MAXIMUM_SNAPLEN;
946                 }
947                 p->linktype = DLT_EN10MB; // Ethernet, the 10MB is historical.
948                 p->selectable_fd = p->fd;
949                 p->read_op = pcap_dpdk_dispatch;
950                 p->inject_op = pcap_dpdk_inject;
951                 // using pcap_filter currently, though DPDK provides their own BPF function. Because DPDK BPF needs load a ELF file as a filter.
952                 p->setfilter_op = install_bpf_program;
953                 p->setdirection_op = NULL;
954                 p->set_datalink_op = NULL;
955                 p->getnonblock_op = pcap_dpdk_getnonblock;
956                 p->setnonblock_op = pcap_dpdk_setnonblock;
957                 p->stats_op = pcap_dpdk_stats;
958                 p->cleanup_op = pcap_dpdk_close;
959                 p->breakloop_op = pcap_breakloop_common;
960                 // set default timeout
961                 pd->required_select_timeout.tv_sec = 0;
962                 pd->required_select_timeout.tv_usec = DPDK_DEF_MIN_SLEEP_MS*1000;
963                 p->required_select_timeout = &pd->required_select_timeout;
964                 ret = 0; // OK
965         }while(0);
966
967         if (ret <= PCAP_ERROR) // all kinds of error code
968         {
969                 pcap_cleanup_live_common(p);
970         }else{
971                 rte_eth_dev_get_name_by_port(portid,pd->pci_addr);
972                 RTE_LOG(INFO, USER1,"Port %d device: %s, MAC:%s, PCI:%s\n", portid, p->opt.device, pd->mac_addr, pd->pci_addr);
973                 RTE_LOG(INFO, USER1,"Port %d Link Up. Speed %u Mbps - %s\n",
974                                                         portid, link.link_speed,
975                                         (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
976                                                 ("full-duplex") : ("half-duplex\n"));
977         }
978         return ret;
979 }
980
981 // device name for dpdk should be in the form as dpdk:number, such as dpdk:0
982 pcap_t * pcap_dpdk_create(const char *device, char *ebuf, int *is_ours)
983 {
984         pcap_t *p=NULL;
985         *is_ours = 0;
986
987         *is_ours = !strncmp(device, "dpdk:", 5);
988         if (! *is_ours)
989                 return NULL;
990         //memset will happen
991         p = PCAP_CREATE_COMMON(ebuf, struct pcap_dpdk);
992
993         if (p == NULL)
994                 return NULL;
995         p->activate_op = pcap_dpdk_activate;
996         return p;
997 }
998
999 int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
1000 {
1001         int ret=0;
1002         unsigned int nb_ports = 0;
1003         char dpdk_name[DPDK_DEV_NAME_MAX];
1004         char dpdk_desc[DPDK_DEV_DESC_MAX];
1005         ETHER_ADDR_TYPE eth_addr;
1006         char mac_addr[DPDK_MAC_ADDR_SIZE];
1007         char pci_addr[DPDK_PCI_ADDR_SIZE];
1008         do{
1009                 // init EAL; return "DPDK not available" if we
1010                 // have insufficient permission
1011                 char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
1012                 ret = dpdk_pre_init(dpdk_pre_init_errbuf, 1);
1013                 if (ret < 0)
1014                 {
1015                         // This returns a negative value on an error.
1016                         snprintf(ebuf, PCAP_ERRBUF_SIZE,
1017                             "Can't look for DPDK devices: %s",
1018                             dpdk_pre_init_errbuf);
1019                         ret = PCAP_ERROR;
1020                         break;
1021                 }
1022                 if (ret == 0)
1023                 {
1024                         // This means DPDK isn't available on this machine.
1025                         // That just means "don't return any devices".
1026                         break;
1027                 }
1028                 nb_ports = rte_eth_dev_count_avail();
1029                 if (nb_ports == 0)
1030                 {
1031                         // That just means "don't return any devices".
1032                         ret = 0;
1033                         break;
1034                 }
1035                 for (unsigned int i=0; i<nb_ports; i++){
1036                         snprintf(dpdk_name, DPDK_DEV_NAME_MAX-1,
1037                             "%s%u", DPDK_PREFIX, i);
1038                         // mac addr
1039                         rte_eth_macaddr_get(i, &eth_addr);
1040                         eth_addr_str(&eth_addr,mac_addr,DPDK_MAC_ADDR_SIZE);
1041                         // PCI addr
1042                         rte_eth_dev_get_name_by_port(i,pci_addr);
1043                         snprintf(dpdk_desc,DPDK_DEV_DESC_MAX-1,"%s %s, MAC:%s, PCI:%s", DPDK_DESC, dpdk_name, mac_addr, pci_addr);
1044                         if (add_dev(devlistp, dpdk_name, 0, dpdk_desc, ebuf)==NULL){
1045                                 ret = PCAP_ERROR;
1046                                 break;
1047                         }
1048                 }
1049         }while(0);
1050         return ret;
1051 }
1052
1053 #ifdef DPDK_ONLY
1054 /*
1055  * This libpcap build supports only DPDK, not regular network interfaces.
1056  */
1057
1058 /*
1059  * There are no regular interfaces, just DPDK interfaces.
1060  */
1061 int
1062 pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
1063 {
1064         return (0);
1065 }
1066
1067 /*
1068  * Attempts to open a regular interface fail.
1069  */
1070 pcap_t *
1071 pcap_create_interface(const char *device, char *errbuf)
1072 {
1073         snprintf(errbuf, PCAP_ERRBUF_SIZE,
1074             "This version of libpcap only supports DPDK");
1075         return NULL;
1076 }
1077
1078 /*
1079  * Libpcap version string.
1080  */
1081 const char *
1082 pcap_lib_version(void)
1083 {
1084         return (PCAP_VERSION_STRING " (DPDK-only)");
1085 }
1086 #endif