DPDK patches and discussions
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: Ben Magistro <koncept1@gmail.com>
Cc: dev@dpdk.org, Stephen Hemminger <stephen@networkplumber.org>
Subject: [RFT] dumpcap: fix multiple interface and promiscious handling
Date: Mon,  2 Jan 2023 09:01:53 -0800	[thread overview]
Message-ID: <20230102170153.29308-1-stephen@networkplumber.org> (raw)
In-Reply-To: <20230102162441.6205-1-koncept1@gmail.com>

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 <stephen@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


  parent reply	other threads:[~2023-01-02 17:01 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-02 16:24 [PATCH 1/6] app/dumpcap: add additional dump info Ben Magistro
2023-01-02 16:24 ` [PATCH 2/6] app/dumpcap: fix storing port identifier Ben Magistro
2023-01-02 16:58   ` Stephen Hemminger
2023-01-04  3:04   ` Stephen Hemminger
2023-01-02 16:24 ` [PATCH 3/6] app/dumpcap: fix preserving promiscuous mode Ben Magistro
2023-01-02 16:58   ` Stephen Hemminger
2023-01-04  3:04   ` Stephen Hemminger
2023-01-02 16:24 ` [PATCH 4/6] app/dumpcap: fix capturing on multiple interfaces Ben Magistro
2023-01-04  3:01   ` Stephen Hemminger
2023-01-02 16:24 ` [PATCH 5/6] app/dumpcap: improve per interface arg parsing Ben Magistro
2023-01-04  3:04   ` Stephen Hemminger
2023-01-02 16:24 ` [PATCH 6/6] app/dumpcap: refactor add all and default Ben Magistro
2023-01-02 16:57 ` [PATCH 1/6] app/dumpcap: add additional dump info Stephen Hemminger
2023-01-02 17:01 ` Stephen Hemminger [this message]
2023-01-04  2:58 ` Stephen Hemminger
2023-01-04  3:38 ` [PATCH v2 0/6] dumpcap support multiple interfaces Stephen Hemminger
2023-01-04  3:38   ` [PATCH v2 1/6] app/dumpcap: fix storing port identifier Stephen Hemminger
2023-01-04  3:38   ` [PATCH v2 2/6] app/dumpcap: remove unused variable Stephen Hemminger
2023-01-04  3:38   ` [PATCH v2 3/6] app/dumpcap: check for invalid interface name Stephen Hemminger
2023-01-04  3:38   ` [PATCH v2 4/6] app/dumpcap: support multiple interfaces Stephen Hemminger
2023-01-04  3:38   ` [PATCH v2 5/6] pcapng: require per-interface information Stephen Hemminger
2023-01-04  3:38   ` [PATCH v2 6/6] app/dumpcap: support interface name and description Stephen Hemminger
2023-02-06 11:18   ` [PATCH v2 0/6] dumpcap support multiple interfaces Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230102170153.29308-1-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=dev@dpdk.org \
    --cc=koncept1@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).