]> The Tcpdump Group git mirrors - libpcap/blobdiff - pcap-dpdk.c
CI: Call print_so_deps() on rpcapd in remote enabled build
[libpcap] / pcap-dpdk.c
index 3a8158d7a563a41967b56cd03b9cf69fbbe66a65..76de9b769084c2aef5728db3eb0b01ee433fe374 100644 (file)
@@ -34,7 +34,7 @@ Description:
 
 Limitations:
 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.
-2. Only support link libdpdk.so dynamicly, because the libdpdk.a will not work correctly.
+2. Only support link libdpdk.so dynamically, because the libdpdk.a will not work correctly.
 3. Only support read operation, and packet injection has not been supported yet.
 
 Usage:
@@ -50,12 +50,12 @@ sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/' $RTE_SDK
 You shall learn how to bind nic with DPDK-compatible driver by $RTE_SDK/usertools/dpdk-devbind.py, such as igb_uio.
 And enable hugepages by dpdk-setup.sh
 
-Then launch the l2fwd with dynamic dirver support. For example:
+Then launch the l2fwd with dynamic driver support. For example:
 $RTE_SDK/examples/l2fwd/$RTE_TARGET/l2fwd -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so -- -p 0x1
 
 3. Compile libpcap with dpdk options.
 
-If DPDK has not been found automatically, you shall export DPDK envionment variable which are used for compiling DPDK. And then pass $RTE_SDK/$RTE_TARGET to --with-dpdk or -DDPDK_DIR
+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
 
 export RTE_SDK={your DPDK base directory}
 export RTE_TARGET={your target name}
@@ -70,22 +70,20 @@ mkdir -p build && cd build && cmake -DDPDK_DIR=$RTE_SDK/$RTE_TARGET ../ && make
 
 4. Link your own program with libpcap, and use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
 And you shall set DPDK configure options by environment variable DPDK_CFG
-For example, the testprogs/capturetest could be lanched by:
+For example, the testprogs/capturetest could be launched by:
 
 env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so" ./capturetest -i dpdk:0
 */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
 
-#include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h> /* for INT_MAX */
 #include <time.h>
 
 #include <sys/time.h>
@@ -116,6 +114,16 @@ env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so
 #include "pcap-int.h"
 #include "pcap-dpdk.h"
 
+/*
+ * Deal with API changes that break source compatibility.
+ */
+
+#ifdef HAVE_STRUCT_RTE_ETHER_ADDR
+#define ETHER_ADDR_TYPE        struct rte_ether_addr
+#else
+#define ETHER_ADDR_TYPE        struct ether_addr
+#endif
+
 #define DPDK_DEF_LOG_LEV RTE_LOG_ERR
 //
 // This is set to 0 if we haven't initialized DPDK yet, 1 if we've
@@ -153,7 +161,11 @@ static char dpdk_cfg_buf[DPDK_CFG_MAX_LEN];
 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
 
+#ifdef RTE_ETHER_MAX_JUMBO_FRAME_LEN
+#define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
+#else
 #define RTE_ETH_PCAP_SNAPLEN ETHER_MAX_JUMBO_FRAME_LEN
+#endif
 
 static struct rte_eth_dev_tx_buffer *tx_buffer;
 
@@ -177,7 +189,7 @@ struct pcap_dpdk{
        uint64_t bps;
        struct rte_mempool * pktmbuf_pool;
        struct dpdk_ts_helper ts_helper;
-       struct ether_addr eth_addr;
+       ETHER_ADDR_TYPE eth_addr;
        char mac_addr[DPDK_MAC_ADDR_SIZE];
        char pci_addr[DPDK_PCI_ADDR_SIZE];
        unsigned char pcap_tmp_buf[RTE_ETH_PCAP_SNAPLEN];
@@ -259,7 +271,7 @@ static inline void calculate_timestamp(struct dpdk_ts_helper *helper,struct time
        timeradd(&(helper->start_time), &cur_time, ts);
 }
 
-static uint32_t dpdk_gather_data(unsigned char *data, int len, struct rte_mbuf *mbuf)
+static uint32_t dpdk_gather_data(unsigned char *data, uint32_t len, struct rte_mbuf *mbuf)
 {
        uint32_t total_len = 0;
        while (mbuf && (total_len+mbuf->data_len) < len ){
@@ -271,7 +283,7 @@ static uint32_t dpdk_gather_data(unsigned char *data, int len, struct rte_mbuf *
 }
 
 
-static int dpdk_read_with_timeout(pcap_t *p, uint16_t portid, struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){
+static int dpdk_read_with_timeout(pcap_t *p, struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){
        struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
        int nb_rx = 0;
        int timeout_ms = p->opt.timeout;
@@ -280,7 +292,7 @@ static int dpdk_read_with_timeout(pcap_t *p, uint16_t portid, struct rte_mbuf **
                // In non-blocking mode, just read once, no matter how many packets are captured.
                nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
        }else{
-               // In blocking mode, read many times until packets are captured or timeout or break_loop is setted.
+               // In blocking mode, read many times until packets are captured or timeout or break_loop is set.
                // if timeout_ms == 0, it may be blocked forever.
                while (timeout_ms == 0 || sleep_ms < timeout_ms){
                        nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
@@ -308,7 +320,6 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
        struct rte_mbuf *m;
        struct pcap_pkthdr pcap_header;
-       uint16_t portid = pd->portid;
        // In DPDK, pkt_len is sum of lengths for all segments. And data_len is for one segment
        uint32_t pkt_len = 0;
        uint32_t caplen = 0;
@@ -319,26 +330,41 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
        u_char *large_buffer=NULL;
        int timeout_ms = p->opt.timeout;
 
-       if ( !PACKET_COUNT_IS_UNLIMITED(max_cnt) && max_cnt < MAX_PKT_BURST){
+       /*
+        * This can conceivably process more than INT_MAX packets,
+        * which would overflow the packet count, causing it either
+        * to look like a negative number, and thus cause us to
+        * return a value that looks like an error, or overflow
+        * back into positive territory, and thus cause us to
+        * return a too-low count.
+        *
+        * Therefore, if the packet count is unlimited, we clip
+        * it at INT_MAX; this routine is not expected to
+        * process packets indefinitely, so that's not an issue.
+        */
+       if (PACKET_COUNT_IS_UNLIMITED(max_cnt))
+               max_cnt = INT_MAX;
+
+       if (max_cnt < MAX_PKT_BURST){
                burst_cnt = max_cnt;
        }else{
                burst_cnt = MAX_PKT_BURST;
        }
 
-       while( PACKET_COUNT_IS_UNLIMITED(max_cnt) || pkt_cnt < max_cnt){
+       while( pkt_cnt < max_cnt){
                if (p->break_loop){
                        p->break_loop = 0;
                        return PCAP_ERROR_BREAK;
                }
                // read once in non-blocking mode, or try many times waiting for timeout_ms.
-               // if timeout_ms == 0, it will be blocked until one packet arrives or break_loop is setted.
-               nb_rx = dpdk_read_with_timeout(p, portid, pkts_burst, burst_cnt);
+               // if timeout_ms == 0, it will be blocked until one packet arrives or break_loop is set.
+               nb_rx = dpdk_read_with_timeout(p, pkts_burst, burst_cnt);
                if (nb_rx == 0){
                        if (pd->nonblock){
                                RTE_LOG(DEBUG, USER1, "dpdk: no packets available in non-blocking mode.\n");
                        }else{
                                if (p->break_loop){
-                                       RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is setted in blocking mode.\n");
+                                       RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is set in blocking mode.\n");
                                        p->break_loop = 0;
                                        return PCAP_ERROR_BREAK;
 
@@ -366,7 +392,7 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
                                bp = rte_pktmbuf_mtod(m, u_char *);
                        }else{
                                // use fast buffer pcap_tmp_buf if pkt_len is small, no need to call malloc and free
-                               if ( pkt_len <= ETHER_MAX_JUMBO_FRAME_LEN)
+                               if ( pkt_len <= RTE_ETH_PCAP_SNAPLEN)
                                {
                                        gather_len = dpdk_gather_data(pd->pcap_tmp_buf, RTE_ETH_PCAP_SNAPLEN, m);
                                        bp = pd->pcap_tmp_buf;
@@ -379,7 +405,7 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
 
                        }
                        if (bp){
-                               if (p->fcode.bf_insns==NULL || pcap_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){
+                               if (p->fcode.bf_insns==NULL || pcapint_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){
                                        cb(cb_arg, &pcap_header, bp);
                                }else{
                                        pd->bpf_drop++;
@@ -399,7 +425,7 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
 static int pcap_dpdk_inject(pcap_t *p, const void *buf _U_, int size _U_)
 {
        //not implemented yet
-       pcap_strlcpy(p->errbuf,
+       pcapint_strlcpy(p->errbuf,
            "dpdk error: Inject function has not been implemented yet",
            PCAP_ERRBUF_SIZE);
        return PCAP_ERROR;
@@ -418,7 +444,7 @@ static void pcap_dpdk_close(pcap_t *p)
        }
        rte_eth_dev_stop(pd->portid);
        rte_eth_dev_close(pd->portid);
-       pcap_cleanup_live_common(p);
+       pcapint_cleanup_live_common(p);
 }
 
 static void nic_stats_display(struct pcap_dpdk *pd)
@@ -473,7 +499,7 @@ static int check_link_status(uint16_t portid, struct rte_eth_link *plink)
        rte_eth_link_get(portid, plink);
        return plink->link_status == ETH_LINK_UP;
 }
-static void eth_addr_str(struct ether_addr *addrp, char* mac_str, int len)
+static void eth_addr_str(ETHER_ADDR_TYPE *addrp, char* mac_str, int len)
 {
        int offset=0;
        if (addrp == NULL){
@@ -501,8 +527,8 @@ static void eth_addr_str(struct ether_addr *addrp, char* mac_str, int len)
 static uint16_t portid_by_device(char * device)
 {
        uint16_t ret = DPDK_PORTID_MAX;
-       int len = strlen(device);
-       int prefix_len = strlen(DPDK_PREFIX);
+       size_t len = strlen(device);
+       size_t prefix_len = strlen(DPDK_PREFIX);
        unsigned long ret_ul = 0L;
        char *pEnd;
        if (len<=prefix_len || strncmp(device, DPDK_PREFIX, prefix_len)) // check prefix dpdk:
@@ -542,7 +568,7 @@ static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv)
                        skip_space=!skip_space; // skip normal char
                        dargv[cnt++] = dpdk_cfg+i;
                }
-               if (!skip_space && dpdk_cfg[i]==' '){ // fint a space
+               if (!skip_space && dpdk_cfg[i]==' '){ // find a space
                        dpdk_cfg[i]=0x00; // end of this opt
                        skip_space=!skip_space; // skip space char
                }
@@ -572,7 +598,7 @@ static int dpdk_pre_init(char * ebuf, int eaccess_not_fatal)
        char *dargv[DPDK_ARGC_MAX];
        char *ptr_dpdk_cfg = NULL;
        int ret;
-       // globale var
+       // global var
        if (is_dpdk_pre_inited != 0)
        {
                // already inited; did that succeed?
@@ -920,15 +946,15 @@ static int pcap_dpdk_activate(pcap_t *p)
                p->selectable_fd = p->fd;
                p->read_op = pcap_dpdk_dispatch;
                p->inject_op = pcap_dpdk_inject;
-               // using pcap_filter currently, though DPDK provides their own BPF function. Because DPDK BPF needs load a ELF file as a filter.
-               p->setfilter_op = install_bpf_program;
+               // using pcapint_filter currently, though DPDK provides their own BPF function. Because DPDK BPF needs load a ELF file as a filter.
+               p->setfilter_op = pcapint_install_bpf_program;
                p->setdirection_op = NULL;
                p->set_datalink_op = NULL;
                p->getnonblock_op = pcap_dpdk_getnonblock;
                p->setnonblock_op = pcap_dpdk_setnonblock;
                p->stats_op = pcap_dpdk_stats;
                p->cleanup_op = pcap_dpdk_close;
-               p->breakloop_op = pcap_breakloop_common;
+               p->breakloop_op = pcapint_breakloop_common;
                // set default timeout
                pd->required_select_timeout.tv_sec = 0;
                pd->required_select_timeout.tv_usec = DPDK_DEF_MIN_SLEEP_MS*1000;
@@ -938,7 +964,7 @@ static int pcap_dpdk_activate(pcap_t *p)
 
        if (ret <= PCAP_ERROR) // all kinds of error code
        {
-               pcap_cleanup_live_common(p);
+               pcapint_cleanup_live_common(p);
        }else{
                rte_eth_dev_get_name_by_port(portid,pd->pci_addr);
                RTE_LOG(INFO, USER1,"Port %d device: %s, MAC:%s, PCI:%s\n", portid, p->opt.device, pd->mac_addr, pd->pci_addr);
@@ -950,7 +976,7 @@ static int pcap_dpdk_activate(pcap_t *p)
        return ret;
 }
 
-// device name for dpdk shoud be in the form as dpdk:number, such as dpdk:0
+// device name for dpdk should be in the form as dpdk:number, such as dpdk:0
 pcap_t * pcap_dpdk_create(const char *device, char *ebuf, int *is_ours)
 {
        pcap_t *p=NULL;
@@ -960,7 +986,7 @@ pcap_t * pcap_dpdk_create(const char *device, char *ebuf, int *is_ours)
        if (! *is_ours)
                return NULL;
        //memset will happen
-       p = pcap_create_common(ebuf, sizeof(struct pcap_dpdk));
+       p = PCAP_CREATE_COMMON(ebuf, struct pcap_dpdk);
 
        if (p == NULL)
                return NULL;
@@ -974,7 +1000,7 @@ int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
        unsigned int nb_ports = 0;
        char dpdk_name[DPDK_DEV_NAME_MAX];
        char dpdk_desc[DPDK_DEV_DESC_MAX];
-       struct ether_addr eth_addr;
+       ETHER_ADDR_TYPE eth_addr;
        char mac_addr[DPDK_MAC_ADDR_SIZE];
        char pci_addr[DPDK_PCI_ADDR_SIZE];
        do{
@@ -1013,7 +1039,7 @@ int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
                        // PCI addr
                        rte_eth_dev_get_name_by_port(i,pci_addr);
                        snprintf(dpdk_desc,DPDK_DEV_DESC_MAX-1,"%s %s, MAC:%s, PCI:%s", DPDK_DESC, dpdk_name, mac_addr, pci_addr);
-                       if (add_dev(devlistp, dpdk_name, 0, dpdk_desc, ebuf)==NULL){
+                       if (pcapint_add_dev(devlistp, dpdk_name, 0, dpdk_desc, ebuf)==NULL){
                                ret = PCAP_ERROR;
                                break;
                        }
@@ -1031,7 +1057,7 @@ int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
  * There are no regular interfaces, just DPDK interfaces.
  */
 int
-pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
+pcapint_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
 {
        return (0);
 }
@@ -1040,10 +1066,9 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
  * Attempts to open a regular interface fail.
  */
 pcap_t *
-pcap_create_interface(const char *device, char *errbuf)
+pcapint_create_interface(const char *device, char *errbuf)
 {
-       snprintf(errbuf, PCAP_ERRBUF_SIZE,
-           "This version of libpcap only supports DPDK");
+       snprintf(errbuf, PCAP_ERRBUF_SIZE, PCAP_ENODEV_MESSAGE, "DPDK");
        return NULL;
 }