X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/2ed0710c942d5c8ed166bafee1cea7195ab791e5..HEAD:/pcap-dpdk.c diff --git a/pcap-dpdk.c b/pcap-dpdk.c index 2f866921..76de9b76 100644 --- a/pcap-dpdk.c +++ b/pcap-dpdk.c @@ -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,28 +70,28 @@ 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 -#endif -#include #include #include #include #include #include #include +#include /* for INT_MAX */ #include #include //header for calling dpdk +#include #include +#include #include #include #include @@ -114,7 +114,23 @@ 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 +// successfully initialized it, a negative value, which is the negative +// of the rte_errno from rte_eal_init(), if we tried to initialize it +// and got an error. +// static int is_dpdk_pre_inited=0; #define DPDK_LIB_NAME "libpcap_dpdk" #define DPDK_DESC "Data Plane Development Kit (DPDK) Interface" @@ -145,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; @@ -169,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]; @@ -184,6 +204,9 @@ static struct rte_eth_conf port_conf = { }, }; +static void dpdk_fmt_errmsg_for_rte_errno(char *, size_t, int, + PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); + /* * Generate an error message based on a format, arguments, and an * rte_errno, with a message for the rte_errno after the formatted output. @@ -197,7 +220,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); @@ -225,7 +248,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){ @@ -248,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 ){ @@ -260,16 +283,16 @@ 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, 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. + // 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); @@ -297,38 +320,51 @@ 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; - 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; - 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, 0, 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; @@ -345,7 +381,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 @@ -356,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; @@ -369,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++; @@ -389,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; @@ -408,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) @@ -463,11 +499,11 @@ 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){ - 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++) @@ -478,10 +514,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 } } @@ -491,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: @@ -532,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 } @@ -542,23 +578,40 @@ static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv) } // only called once -static int dpdk_pre_init(void) +// Returns: +// +// 1 on success; +// +// 0 if "the EAL cannot initialize on this system", which we treat as +// meaning "DPDK isn't available"; +// +// a PCAP_ERROR_ code for other errors. +// +// 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]; char *ptr_dpdk_cfg = NULL; - int ret = PCAP_ERROR; - // globale var - if (is_dpdk_pre_inited) - { - // already inited - return 0; - } - // check for root permission - if( geteuid() != 0) + int ret; + // global var + if (is_dpdk_pre_inited != 0) { - RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG); - return PCAP_ERROR_PERM_DENIED; + // already inited; did that succeed? + if (is_dpdk_pre_inited < 0) + { + // failed + goto error; + } + else + { + // succeeded + return 1; + } } // init EAL ptr_dpdk_cfg = getenv(DPDK_CFG_ENV_NAME); @@ -575,12 +628,125 @@ static int dpdk_pre_init(void) ret = rte_eal_init(dargv_cnt,dargv); if (ret == -1) { - // Error. - return PCAP_ERROR; + // Indicate that we've called rte_eal_init() by setting + // is_dpdk_pre_inited to the negative of the error code, + // and process the error. + is_dpdk_pre_inited = -rte_errno; + goto error; } - // init successed, so we do not need to do it again later. + // init succeeded, so we do not need to do it again later. is_dpdk_pre_inited = 1; - return 0; + return 1; + +error: + switch (-is_dpdk_pre_inited) + { + case EACCES: + // This "indicates a permissions issue.". + RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG); + // 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; + + case EAGAIN: + // This "indicates either a bus or system + // resource was not available, setup may + // be attempted again." + // There's no such error in pcap, so I'm + // not sure what we should do here. + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "Bus or system resource was not available"); + break; + + case EALREADY: + // This "indicates that the rte_eal_init + // function has already been called, and + // cannot be called again." + // That's not an error; set the "we've + // been here before" flag and return + // success. + is_dpdk_pre_inited = 1; + return 1; + + case EFAULT: + // This "indicates the tailq configuration + // name was not found in memory configuration." + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "The tailq configuration name was not found in the memory configuration"); + return PCAP_ERROR; + + case EINVAL: + // This "indicates invalid parameters were + // passed as argv/argc." Those came from + // the configuration file. + 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." + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "Out of memory"); + break; + + case ENODEV: + // This "indicates memory setup issues." + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "An error occurred setting up memory"); + break; + + case ENOTSUP: + // This "indicates that the EAL cannot + // initialize on this system." We treat + // that as meaning DPDK isn't available + // on this machine, rather than as a + // fatal error, and let our caller decide + // whether that's a fatal error (if trying + // to activate a DPDK device) or not (if + // trying to enumerate devices). + return 0; + + case EPROTO: + // This "indicates that the PCI bus is + // either not present, or is not readable + // by the eal." Does "the PCI bus is not + // present" mean "this machine has no PCI + // bus", which strikes me as a "not available" + // case? If so, should "is not readable by + // the EAL" also something we should treat + // as a "not available" case? If not, we + // can't distinguish between the two, so + // we're stuck. + 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." + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "A service core failed to launch successfully"); + break; + + default: + // + // That's not in the list of errors in + // the documentation; let it be reported + // as an error. + // + dpdk_fmt_errmsg_for_rte_errno(ebuf, + PCAP_ERRBUF_SIZE, -is_dpdk_pre_inited, + "dpdk error: dpdk_pre_init failed"); + break; + } + // Error. + return PCAP_ERROR; } static int pcap_dpdk_activate(pcap_t *p) @@ -598,38 +764,31 @@ static int pcap_dpdk_activate(pcap_t *p) int is_port_up = 0; struct rte_eth_link link; do{ - //init EAL - ret = dpdk_pre_init(); + //init EAL; fail if we have insufficient permission + char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE]; + ret = dpdk_pre_init(dpdk_pre_init_errbuf, 0); if (ret < 0) { // This returns a negative value on an error. - // That's either PCAP_ERROR_PERM_DENIED if - // you're not running as root, or PCAP_ERROR - // if rte_eal_init() fails. - // - // If it returned PCAP_ERROR, provide an error - // message based on rte_errno. Otherwise, the - // error message has already been filled in. - if (ret == PCAP_ERROR) - { - dpdk_fmt_errmsg_for_rte_errno(p->errbuf, - PCAP_ERRBUF_SIZE, rte_errno, - "dpdk error: Init failed with device %s", - p->opt.device); - } - else - { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Can't open device %s: DPDK requires that it run as root", - p->opt.device); - } + 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 break; } + if (ret == 0) + { + // This means DPDK isn't available on this machine. + 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; @@ -639,7 +798,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; @@ -647,7 +806,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; @@ -742,7 +901,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; @@ -767,7 +926,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; @@ -787,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; @@ -805,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); @@ -817,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; @@ -827,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; @@ -841,53 +1000,46 @@ 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{ - ret = dpdk_pre_init(); + // 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, 1); if (ret < 0) { // This returns a negative value on an error. - // That's either PCAP_ERROR_PERM_DENIED if - // you're not running as root, or PCAP_ERROR - // if rte_eal_init() fails. - // - // If it returned PCAP_ERROR, provide an error - // message based on rte_errno. Otherwise, the - // error message has already been filled in. - if (ret == PCAP_ERROR) - { - dpdk_fmt_errmsg_for_rte_errno(ebuf, - PCAP_ERRBUF_SIZE, rte_errno, - "dpdk error: Init failed"); - } - else - { - pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, - "DPDK requires that it run as root"); - } - // ret is set to the correct error + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "Can't look for DPDK devices: %s", + dpdk_pre_init_errbuf); + ret = PCAP_ERROR; + break; + } + if (ret == 0) + { + // This means DPDK isn't available on this machine. + // That just means "don't return any devices". break; } nb_ports = rte_eth_dev_count_avail(); if (nb_ports == 0) { - pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, - "DPDK error: No Ethernet ports"); - ret = PCAP_ERROR; + // That just means "don't return any devices". + ret = 0; break; } for (unsigned int i=0; i