]> The Tcpdump Group git mirrors - libpcap/blobdiff - pcap-dpdk.c
On Linux, return error on interface going away, not just going down.
[libpcap] / pcap-dpdk.c
index 11dd6a9ea65a6b2cedc635d6c8e9c385b5803fcb..6c2f21fca5f052caee17b8e81f4f884198d36836 100644 (file)
@@ -79,7 +79,6 @@ env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so
 #include <config.h>
 #endif
 
-#include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
@@ -208,7 +207,7 @@ static void dpdk_fmt_errmsg_for_rte_errno(char *errbuf, size_t errbuflen,
        size_t errbuflen_remaining;
 
        va_start(ap, fmt);
-       pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
+       vsnprintf(errbuf, errbuflen, fmt, ap);
        va_end(ap);
        msglen = strlen(errbuf);
 
@@ -236,7 +235,7 @@ static void dpdk_fmt_errmsg_for_rte_errno(char *errbuf, size_t errbuflen,
         * buffer (based on the "PER_LCORE" in "RTE_DEFINE_PER_LCORE" used
         * to declare the buffers statically) for DPDK errors.
         */
-       pcap_snprintf(p, errbuflen_remaining, "%s", rte_strerror(errnum));
+       snprintf(p, errbuflen_remaining, "%s", rte_strerror(errnum));
 }
 
 static int dpdk_init_timer(struct pcap_dpdk *pd){
@@ -271,13 +270,13 @@ 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, uint16_t queueid,struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){
+static int dpdk_read_with_timeout(pcap_t *p, uint16_t portid, 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;
        int sleep_ms = 0;
        if (pd->nonblock){
-               // In non-blocking mode, just read once, no mater how many packets are captured.
+               // 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.
@@ -311,12 +310,11 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
        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;
-       int caplen = 0;
+       uint32_t caplen = 0;
        u_char *bp = NULL;
        int i=0;
        unsigned int gather_len =0;
        int pkt_cnt = 0;
-       int is_accepted=0;
        u_char *large_buffer=NULL;
        int timeout_ms = p->opt.timeout;
 
@@ -333,7 +331,7 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
                }
                // 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, 0, pkts_burst, burst_cnt);
+               nb_rx = dpdk_read_with_timeout(p, portid, pkts_burst, burst_cnt);
                if (nb_rx == 0){
                        if (pd->nonblock){
                                RTE_LOG(DEBUG, USER1, "dpdk: no packets available in non-blocking mode.\n");
@@ -356,7 +354,7 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c
                        pkt_len = rte_pktmbuf_pkt_len(m);
                        // caplen = min(pkt_len, p->snapshot);
                        // caplen will not be changed, no matter how long the rte_pktmbuf
-                       caplen = pkt_len < p->snapshot ? pkt_len: p->snapshot;
+                       caplen = pkt_len < (uint32_t)p->snapshot ? pkt_len: (uint32_t)p->snapshot;
                        pcap_header.caplen = caplen;
                        pcap_header.len = pkt_len;
                        // volatile prefetch
@@ -478,7 +476,7 @@ static void eth_addr_str(struct ether_addr *addrp, char* mac_str, int len)
 {
        int offset=0;
        if (addrp == NULL){
-               pcap_snprintf(mac_str, len-1, DPDK_DEF_MAC_ADDR);
+               snprintf(mac_str, len-1, DPDK_DEF_MAC_ADDR);
                return;
        }
        for (int i=0; i<6; i++)
@@ -489,10 +487,10 @@ static void eth_addr_str(struct ether_addr *addrp, char* mac_str, int len)
                }
                if (i==0)
                {
-                       pcap_snprintf(mac_str+offset, len-1-offset, "%02X",addrp->addr_bytes[i]);
+                       snprintf(mac_str+offset, len-1-offset, "%02X",addrp->addr_bytes[i]);
                        offset+=2; // FF
                }else{
-                       pcap_snprintf(mac_str+offset, len-1-offset, ":%02X", addrp->addr_bytes[i]);
+                       snprintf(mac_str+offset, len-1-offset, ":%02X", addrp->addr_bytes[i]);
                        offset+=3; // :FF
                }
        }
@@ -561,7 +559,13 @@ static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv)
 //    meaning "DPDK isn't available";
 //
 //    a PCAP_ERROR_ code for other errors.
-static int dpdk_pre_init(char * ebuf)
+//
+// If eaccess_not_fatal is non-zero, treat "a permissions issue" the way
+// we treat "the EAL cannot initialize on this system".  We use that
+// when trying to find DPDK devices, as we don't want to fail to return
+// *any* devices just because we can't support DPDK; when we're trying
+// to open a device, we need to return a permissions error in that case.
+static int dpdk_pre_init(char * ebuf, int eaccess_not_fatal)
 {
        int dargv_cnt=0;
        char *dargv[DPDK_ARGC_MAX];
@@ -582,16 +586,6 @@ static int dpdk_pre_init(char * ebuf)
                        return 1;
                }
        }
-       // check for root permission
-       // XXX - is it sufficient to call rte_eal_init() and check for
-       // EACCES?
-       if( geteuid() != 0)
-       {
-               RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG);
-               pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                   "DPDK requires that it run as root");
-               return PCAP_ERROR_PERM_DENIED;
-       }
        // init EAL
        ptr_dpdk_cfg = getenv(DPDK_CFG_ENV_NAME);
        // set default log level to debug
@@ -623,7 +617,12 @@ error:
                case EACCES:
                        // This "indicates a permissions issue.".
                        RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG);
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       // If we were told to treat this as just meaning
+                       // DPDK isn't available, do so.
+                       if (eaccess_not_fatal)
+                               return 0;
+                       // Otherwise report a fatal error.
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "DPDK requires that it run as root");
                        return PCAP_ERROR_PERM_DENIED;
 
@@ -633,7 +632,7 @@ error:
                        // be attempted again."
                        // There's no such error in pcap, so I'm
                        // not sure what we should do here.
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "Bus or system resource was not available");
                        break;
 
@@ -650,7 +649,7 @@ error:
                case EFAULT:
                        // This "indicates the tailq configuration
                        // name was not found in memory configuration."
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "The tailq configuration name was not found in the memory configuration");
                        return PCAP_ERROR;
 
@@ -658,20 +657,20 @@ error:
                        // This "indicates invalid parameters were
                        // passed as argv/argc."  Those came from
                        // the configuration file.
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "The configuration file has invalid parameters");
                        break;
 
                case ENOMEM:
                        // This "indicates failure likely caused by
                        // an out-of-memory condition."
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "Out of memory");
                        break;
 
                case ENODEV:
                        // This "indicates memory setup issues."
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "An error occurred setting up memory");
                        break;
 
@@ -697,14 +696,14 @@ error:
                        // as a "not available" case?  If not, we
                        // can't distinguish between the two, so
                        // we're stuck.
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "PCI bus is not present or not readable by the EAL");
                        break;
 
                case ENOEXEC:
                        // This "indicates that a service core
                        // failed to launch successfully."
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "A service core failed to launch successfully");
                        break;
 
@@ -738,13 +737,13 @@ static int pcap_dpdk_activate(pcap_t *p)
        int is_port_up = 0;
        struct rte_eth_link link;
        do{
-               //init EAL
+               //init EAL; fail if we have insufficient permission
                char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
-               ret = dpdk_pre_init(dpdk_pre_init_errbuf);
+               ret = dpdk_pre_init(dpdk_pre_init_errbuf, 0);
                if (ret < 0)
                {
                        // This returns a negative value on an error.
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "Can't open device %s: %s",
                            p->opt.device, dpdk_pre_init_errbuf);
                        // ret is set to the correct error
@@ -753,16 +752,16 @@ static int pcap_dpdk_activate(pcap_t *p)
                if (ret == 0)
                {
                        // This means DPDK isn't available on this machine.
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "Can't open device %s: DPDK is not available on this machine",
                            p->opt.device);
                        return PCAP_ERROR_NO_SUCH_DEVICE;
                }
-                       
+
                ret = dpdk_init_timer(pd);
                if (ret<0)
                {
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                                "dpdk error: Init timer is zero with device %s",
                                p->opt.device);
                        ret = PCAP_ERROR;
@@ -772,7 +771,7 @@ static int pcap_dpdk_activate(pcap_t *p)
                nb_ports = rte_eth_dev_count_avail();
                if (nb_ports == 0)
                {
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "dpdk error: No Ethernet ports");
                        ret = PCAP_ERROR;
                        break;
@@ -780,7 +779,7 @@ static int pcap_dpdk_activate(pcap_t *p)
 
                portid = portid_by_device(p->opt.device);
                if (portid == DPDK_PORTID_MAX){
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "dpdk error: portid is invalid. device %s",
                            p->opt.device);
                        ret = PCAP_ERROR_NO_SUCH_DEVICE;
@@ -875,7 +874,7 @@ static int pcap_dpdk_activate(pcap_t *p)
                                rte_eth_dev_socket_id(portid));
                if (tx_buffer == NULL)
                {
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "dpdk error: Cannot allocate buffer for tx on port %u", portid);
                        ret = PCAP_ERROR;
                        break;
@@ -900,7 +899,7 @@ static int pcap_dpdk_activate(pcap_t *p)
                // check link status
                is_port_up = check_link_status(portid, &link);
                if (!is_port_up){
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "dpdk error: link is down, port=%u",portid);
                        ret = PCAP_ERROR_IFACE_NOT_UP;
                        break;
@@ -978,15 +977,17 @@ int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
        char mac_addr[DPDK_MAC_ADDR_SIZE];
        char pci_addr[DPDK_PCI_ADDR_SIZE];
        do{
+               // init EAL; return "DPDK not available" if we
+               // have insufficient permission
                char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
-               ret = dpdk_pre_init(dpdk_pre_init_errbuf);
+               ret = dpdk_pre_init(dpdk_pre_init_errbuf, 1);
                if (ret < 0)
                {
                        // This returns a negative value on an error.
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-                           "Can't open device %s: %s",
-                           p->opt.device, dpdk_pre_init_errbuf);
-                       ret = PCAP_ERRNO;
+                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                           "Can't look for DPDK devices: %s",
+                           dpdk_pre_init_errbuf);
+                       ret = PCAP_ERROR;
                        break;
                }
                if (ret == 0)
@@ -1003,14 +1004,14 @@ int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
                        break;
                }
                for (unsigned int i=0; i<nb_ports; i++){
-                       pcap_snprintf(dpdk_name, DPDK_DEV_NAME_MAX-1,
+                       snprintf(dpdk_name, DPDK_DEV_NAME_MAX-1,
                            "%s%u", DPDK_PREFIX, i);
                        // mac addr
                        rte_eth_macaddr_get(i, &eth_addr);
                        eth_addr_str(&eth_addr,mac_addr,DPDK_MAC_ADDR_SIZE);
                        // PCI addr
                        rte_eth_dev_get_name_by_port(i,pci_addr);
-                       pcap_snprintf(dpdk_desc,DPDK_DEV_DESC_MAX-1,"%s %s, MAC:%s, PCI:%s", DPDK_DESC, dpdk_name, mac_addr, 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){
                                ret = PCAP_ERROR;
                                break;
@@ -1040,7 +1041,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
 pcap_t *
 pcap_create_interface(const char *device, char *errbuf)
 {
-       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(errbuf, PCAP_ERRBUF_SIZE,
            "This version of libpcap only supports DPDK");
        return NULL;
 }