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