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: [PATCH v2 5/6] pcapng: require per-interface information
Date: Tue,  3 Jan 2023 19:38:14 -0800	[thread overview]
Message-ID: <20230104033815.35496-6-stephen@networkplumber.org> (raw)
In-Reply-To: <20230104033815.35496-1-stephen@networkplumber.org>

This changes the API for how pcapng is used.
Before each interface was automatically added to the capture
file.  Now the application must add each interface.
Note: API changes are allowed because this is an experimental
interface.

This allows application to specify extra meta data like
interface name, description and packet filter.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test/test_pcapng.c  |  7 ++++
 lib/pcapng/rte_pcapng.c | 79 ++++++++++++++++++++++++++---------------
 lib/pcapng/rte_pcapng.h | 25 +++++++++++++
 lib/pcapng/version.map  |  1 +
 4 files changed, 84 insertions(+), 28 deletions(-)

diff --git a/app/test/test_pcapng.c b/app/test/test_pcapng.c
index a7acbdc0586d..edba46d1fe0f 100644
--- a/app/test/test_pcapng.c
+++ b/app/test/test_pcapng.c
@@ -109,6 +109,13 @@ test_setup(void)
 		return -1;
 	}
 
+	/* Add interface to the file */
+	if (rte_pcapng_add_interface(pcapng, port_id,
+				     NULL, NULL, NULL) != 0) {
+		fprintf(stderr, "can not add port %u\n", port_id);
+		return -1;
+	}
+
 	/* Make a pool for cloned packets */
 	mp = rte_pktmbuf_pool_create_by_ops("pcapng_test_pool", IOV_MAX + NUM_PACKETS,
 					    0, 0,
diff --git a/lib/pcapng/rte_pcapng.c b/lib/pcapng/rte_pcapng.c
index 80d08e1a3bde..ea004939e63e 100644
--- a/lib/pcapng/rte_pcapng.c
+++ b/lib/pcapng/rte_pcapng.c
@@ -32,6 +32,9 @@
 /* Format of the capture file handle */
 struct rte_pcapng {
 	int  outfd;		/* output file */
+
+	unsigned int ports;	/* number of interfaces added */
+
 	/* DPDK port id to interface index in file */
 	uint32_t port_index[RTE_MAX_ETHPORTS];
 };
@@ -185,8 +188,10 @@ pcapng_section_block(rte_pcapng_t *self,
 }
 
 /* Write an interface block for a DPDK port */
-static int
-pcapng_add_interface(rte_pcapng_t *self, uint16_t port)
+int
+rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port,
+			 const char *ifname, const char *ifdescr,
+			 const char *filter)
 {
 	struct pcapng_interface_block *hdr;
 	struct rte_eth_dev_info dev_info;
@@ -197,7 +202,7 @@ pcapng_add_interface(rte_pcapng_t *self, uint16_t port)
 	const uint8_t tsresol = 9;	/* nanosecond resolution */
 	uint32_t len;
 	void *buf;
-	char ifname[IF_NAMESIZE];
+	char ifname_buf[IF_NAMESIZE];
 	char ifhw[256];
 	uint64_t speed = 0;
 
@@ -205,8 +210,14 @@ pcapng_add_interface(rte_pcapng_t *self, uint16_t port)
 		return -1;
 
 	/* make something like an interface name */
-	if (if_indextoname(dev_info.if_index, ifname) == NULL)
-		snprintf(ifname, IF_NAMESIZE, "dpdk:%u", port);
+	if (ifname == NULL) {
+		/* Use kernel name if available */
+		ifname = if_indextoname(dev_info.if_index, ifname_buf);
+		if (ifname == NULL) {
+			snprintf(ifname_buf, IF_NAMESIZE, "dpdk:%u", port);
+			ifname = ifname_buf;
+		}
+	}
 
 	/* make a useful device hardware string */
 	dev = dev_info.device;
@@ -230,10 +241,14 @@ pcapng_add_interface(rte_pcapng_t *self, uint16_t port)
 	len += pcapng_optlen(sizeof(tsresol));	/* timestamp */
 	len += pcapng_optlen(strlen(ifname));	/* ifname */
 
+	if (ifdescr)
+		len += pcapng_optlen(strlen(ifdescr));
 	if (ea)
 		len += pcapng_optlen(RTE_ETHER_ADDR_LEN); /* macaddr */
 	if (speed != 0)
 		len += pcapng_optlen(sizeof(uint64_t));
+	if (filter)
+		len += pcapng_optlen(strlen(filter) + 1);
 	if (dev)
 		len += pcapng_optlen(strlen(ifhw));
 
@@ -256,6 +271,9 @@ pcapng_add_interface(rte_pcapng_t *self, uint16_t port)
 				&tsresol, sizeof(tsresol));
 	opt = pcapng_add_option(opt, PCAPNG_IFB_NAME,
 				ifname, strlen(ifname));
+	if (ifdescr)
+		opt = pcapng_add_option(opt, PCAPNG_IFB_DESCRIPTION,
+					ifdescr, strlen(ifdescr));
 	if (ea)
 		opt = pcapng_add_option(opt, PCAPNG_IFB_MACADDR,
 					ea, RTE_ETHER_ADDR_LEN);
@@ -265,31 +283,29 @@ pcapng_add_interface(rte_pcapng_t *self, uint16_t port)
 	if (dev)
 		opt = pcapng_add_option(opt, PCAPNG_IFB_HARDWARE,
 					 ifhw, strlen(ifhw));
+	if (filter) {
+		/* Encoding is that the first octet indicates string vs BPF */
+		size_t len;
+		char *buf;
+
+		len = strlen(filter) + 1;
+		buf = alloca(len);
+		*buf = '\0';
+		memcpy(buf + 1, filter, len);
+
+		opt = pcapng_add_option(opt, PCAPNG_IFB_FILTER,
+					buf, len);
+	}
+
 	opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0);
 
 	/* clone block_length after optionsa */
 	memcpy(opt, &hdr->block_length, sizeof(uint32_t));
 
-	return write(self->outfd, buf, len);
-}
-
-/*
- * Write the list of possible interfaces at the start
- * of the file.
- */
-static int
-pcapng_interfaces(rte_pcapng_t *self)
-{
-	uint16_t port_id;
-	uint16_t index = 0;
+	/* remember the file index */
+	self->port_index[port] = self->ports++;
 
-	RTE_ETH_FOREACH_DEV(port_id) {
-		/* The list if ports in pcapng needs to be contiguous */
-		self->port_index[port_id] = index++;
-		if (pcapng_add_interface(self, port_id) < 0)
-			return -1;
-	}
-	return 0;
+	return write(self->outfd, buf, len);
 }
 
 /*
@@ -598,6 +614,13 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
 			return -1;
 		}
 
+		/* check that this interface was added. */
+		epb->interface_id = self->port_index[m->port];
+		if (unlikely(epb->interface_id > RTE_MAX_ETHPORTS)) {
+			rte_errno = EINVAL;
+			return -1;
+		}
+
 		/*
 		 * Handle case of highly fragmented and large burst size
 		 * Note: this assumes that max segments per mbuf < IOV_MAX
@@ -616,7 +639,6 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
 		 * The DPDK port is recorded during pcapng_copy.
 		 * Map that to PCAPNG interface in file.
 		 */
-		epb->interface_id = self->port_index[m->port];
 		do {
 			iov[cnt].iov_base = rte_pktmbuf_mtod(m, void *);
 			iov[cnt].iov_len = rte_pktmbuf_data_len(m);
@@ -638,6 +660,7 @@ rte_pcapng_fdopen(int fd,
 		  const char *osname, const char *hardware,
 		  const char *appname, const char *comment)
 {
+	unsigned int i;
 	rte_pcapng_t *self;
 
 	self = malloc(sizeof(*self));
@@ -647,13 +670,13 @@ rte_pcapng_fdopen(int fd,
 	}
 
 	self->outfd = fd;
+	self->ports = 0;
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		self->port_index[i] = UINT32_MAX;
 
 	if (pcapng_section_block(self, osname, hardware, appname, comment) < 0)
 		goto fail;
 
-	if (pcapng_interfaces(self) < 0)
-		goto fail;
-
 	return self;
 fail:
 	free(self);
diff --git a/lib/pcapng/rte_pcapng.h b/lib/pcapng/rte_pcapng.h
index 7d2697c647ef..86b7996e291e 100644
--- a/lib/pcapng/rte_pcapng.h
+++ b/lib/pcapng/rte_pcapng.h
@@ -70,6 +70,31 @@ __rte_experimental
 void
 rte_pcapng_close(rte_pcapng_t *self);
 
+/**
+ * Add interface information to the capture file
+ *
+ * @param self
+ *  The handle to the packet capture file
+ * @param port
+ *  The Ethernet port to report stats on.
+ * @param ifname (optional)
+ *  Interface name to record in the file.
+ *  If not specified, name will be constructed from port
+ * @param ifdescr (optional)
+ *  Interface description to record in the file.
+ * @param filter
+ *  Capture filter to record in the file.
+ *
+ * Interfaces must be added to the output file after opening
+ * and before any packet record. All ports used in packet capture
+ * must be added.
+ */
+__rte_experimental
+int
+rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port,
+			 const char *ifname, const char *ifdescr,
+			 const char *filter);
+
 /**
  * Direction flag
  * These should match Enhanced Packet Block flag bits
diff --git a/lib/pcapng/version.map b/lib/pcapng/version.map
index 05a9c86a7d91..e98e71038ee6 100644
--- a/lib/pcapng/version.map
+++ b/lib/pcapng/version.map
@@ -7,6 +7,7 @@ EXPERIMENTAL {
 	rte_pcapng_mbuf_size;
 	rte_pcapng_write_packets;
 	rte_pcapng_write_stats;
+	rte_pcapng_add_interface;
 
 	local: *;
 };
-- 
2.39.0


  parent reply	other threads:[~2023-01-04  3:38 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 ` [RFT] dumpcap: fix multiple interface and promiscious handling Stephen Hemminger
2023-01-04  2:58 ` [PATCH 1/6] app/dumpcap: add additional dump info 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   ` Stephen Hemminger [this message]
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=20230104033815.35496-6-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).