The code to handle multiple interfaces needs to setup the interface list when command line is parsed, otherwise multiple interfaces won't work.
Dumpcap enables promiscuous on a port, and then always resets it on exit. If the device was already in promiscuous mode, then don't change it. The handling of the -p flag should match what dumpcap does. Fixes: 499b1cbcf9d3 ("app/dumpcap: check for failure to set promiscuous") Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- app/dumpcap/main.c | 98 ++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c index 2eb8414efaa5..33125710428e 100644 --- a/app/dumpcap/main.c +++ b/app/dumpcap/main.c @@ -65,8 +65,6 @@ static const char *file_prefix; static uint32_t snaplen = RTE_MBUF_DEFAULT_BUF_SIZE; static bool dump_bpf; static bool show_interfaces; -static bool select_interfaces; -const char *interface_arg; static struct { uint64_t duration; /* nanoseconds */ @@ -83,6 +81,7 @@ static size_t file_size; struct interface { TAILQ_ENTRY(interface) next; uint16_t port; + bool promisc_mode; char name[RTE_ETH_NAME_MAX_LEN]; struct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT]; @@ -90,7 +89,6 @@ struct interface { TAILQ_HEAD(interface_list, interface); static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces); -static struct interface *port2intf[RTE_MAX_ETHPORTS]; /* Can do either pcap or pcapng format output */ typedef union { @@ -197,29 +195,36 @@ static void add_interface(uint16_t port, const char *name) { struct interface *intf; + if (strlen(name) >= RTE_ETH_NAME_MAX_LEN) + rte_exit(EXIT_FAILURE, "invalid name for interface: '%s'\n", name); + intf = malloc(sizeof(*intf)); if (!intf) rte_exit(EXIT_FAILURE, "no memory for interface\n"); memset(intf, 0, sizeof(*intf)); rte_strscpy(intf->name, name, sizeof(intf->name)); + intf->promisc_mode = promiscuous_mode; + intf->port = port; /* set later */ - printf("Capturing on '%s'\n", name); - - port2intf[port] = intf; TAILQ_INSERT_TAIL(&interfaces, intf, next); } -/* Select all valid DPDK interfaces */ -static void select_all_interfaces(void) +/* Name has been set but need to lookup port after eal_init */ +static void find_interfaces(void) { - char name[RTE_ETH_NAME_MAX_LEN]; - uint16_t p; + struct interface *intf; - RTE_ETH_FOREACH_DEV(p) { - if (rte_eth_dev_get_name_by_port(p, name) < 0) + TAILQ_FOREACH(intf, &interfaces, next) { + /* if name is valid then just record port */ + if (rte_eth_dev_get_port_by_name(intf->name, &intf->port) == 0) continue; - add_interface(p, name); + + /* maybe got passed port number string as name */ + intf->port = get_uint(intf->name, "port_number", UINT16_MAX); + if (rte_eth_dev_get_name_by_port(intf->port, intf->name) < 0) + rte_exit(EXIT_FAILURE, "Invalid port number %u\n", + intf->port); } } @@ -235,32 +240,13 @@ static void set_default_interface(void) RTE_ETH_FOREACH_DEV(p) { if (rte_eth_dev_get_name_by_port(p, name) < 0) continue; + add_interface(p, name); return; } rte_exit(EXIT_FAILURE, "No usable interfaces found\n"); } -/* Lookup interface by name or port and add it to the list */ -static void select_interface(const char *arg) -{ - uint16_t port; - - if (strcmp(arg, "*") == 0) - select_all_interfaces(); - else if (rte_eth_dev_get_port_by_name(arg, &port) == 0) - add_interface(port, arg); - else { - char name[RTE_ETH_NAME_MAX_LEN]; - - port = get_uint(arg, "port_number", UINT16_MAX); - if (rte_eth_dev_get_name_by_port(port, name) < 0) - rte_exit(EXIT_FAILURE, "Invalid port number %u\n", - port); - add_interface(port, name); - } -} - /* Display list of possible interfaces that can be used. */ static void dump_interfaces(void) { @@ -377,8 +363,7 @@ static void parse_opts(int argc, char **argv) usage(); exit(0); case 'i': - select_interfaces = true; - interface_arg = optarg; + add_interface(-1, optarg); break; case 'n': use_pcapng = true; @@ -387,7 +372,22 @@ static void parse_opts(int argc, char **argv) ring_size = get_uint(optarg, "packet_limit", 0); break; case 'p': - promiscuous_mode = false; + /* Like dumpcap this option can occur multiple times. + * + * If used before the first occurrence of the -i option, + * no interface will be put into the promiscuous mode. + * If used after an -i option, the interface specified + * by the last -i option occurring before this option + * will not be put into the promiscuous mode. + */ + if (TAILQ_EMPTY(&interfaces)) { + promiscuous_mode = false; + } else { + struct interface *intf; + + intf = TAILQ_LAST(&interfaces, interface_list); + intf->promisc_mode = false; + } break; case 'P': use_pcapng = false; @@ -436,7 +436,7 @@ cleanup_pdump_resources(void) TAILQ_FOREACH(intf, &interfaces, next) { rte_pdump_disable(intf->port, RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX); - if (promiscuous_mode) + if (intf->promisc_mode) rte_eth_promiscuous_disable(intf->port); } } @@ -696,12 +696,17 @@ static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp) flags |= RTE_PDUMP_FLAG_PCAPNG; TAILQ_FOREACH(intf, &interfaces, next) { - if (promiscuous_mode) { - ret = rte_eth_promiscuous_enable(intf->port); - if (ret != 0) - fprintf(stderr, - "port %u set promiscuous enable failed: %d\n", - intf->port, ret); + if (intf->promisc_mode) { + if (rte_eth_promiscuous_get(intf->port) == 1) { + /* promiscuous already enabled */ + intf->promisc_mode = false; + } else { + ret = rte_eth_promiscuous_enable(intf->port); + if (ret != 0) + fprintf(stderr, + "port %u set promiscuous enable failed: %d\n", + intf->port, ret); + } } ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES, @@ -711,6 +716,8 @@ static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp) rte_exit(EXIT_FAILURE, "Packet dump enable failed: %s\n", rte_strerror(-ret)); + + printf("Capturing on '%s'\n", intf->name); } } @@ -817,14 +824,13 @@ int main(int argc, char **argv) if (rte_eth_dev_count_avail() == 0) rte_exit(EXIT_FAILURE, "No Ethernet ports found\n"); - if (select_interfaces) - select_interface(interface_arg); - if (filter_str) compile_filter(); if (TAILQ_EMPTY(&interfaces)) set_default_interface(); + else + find_interfaces(); r = create_ring(); mp = create_mempool(); -- 2.39.0