DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Mário Kuka" <kuka@cesnet.cz>
To: kuka@cesnet.cz
Cc: dev@dpdk.org, mdr@ashroe.eu, reshma.pattan@intel.com,
	stephen@networkplumber.org
Subject: [PATCH v3] pcapng: fix write more packets than IOV_MAX limit
Date: Mon,  1 Aug 2022 10:40:56 +0200	[thread overview]
Message-ID: <20220801084056.17418-1-kuka@cesnet.cz> (raw)
In-Reply-To: <20220729071841.18198-1-kuka@cesnet.cz>

The rte_pcapng_write_packets() function fails when we try to write more
packets than the IOV_MAX limit. writev() system call is limited by the
IOV_MAX limit. The iovcnt argument is valid if it is greater than 0 and
less than or equal to IOV_MAX as defined in <limits.h>.

To avoid this problem, we can check that all segments of the next
packet will fit into the iovec buffer, whose capacity will be limited
by the IOV_MAX limit. If not, we flush the current iovec buffer to the
file by calling writev() and, if successful, fit the current packet at
the beginning of the flushed iovec buffer.

Fixes: 8d23ce8f5ee9 ("pcapng: add new library for writing pcapng files")
Cc: stephen@networkplumber.org

Signed-off-by: Mário Kuka <kuka@cesnet.cz>
---
v3:
* Remove unwanted changes to check for partial writes from the writev().

 app/test/test_pcapng.c  | 42 +++++++++++++++++++++++++++++++++++-
 lib/pcapng/rte_pcapng.c | 47 ++++++++++++++++++++---------------------
 2 files changed, 64 insertions(+), 25 deletions(-)

diff --git a/app/test/test_pcapng.c b/app/test/test_pcapng.c
index 320dacea34..7f51946fff 100644
--- a/app/test/test_pcapng.c
+++ b/app/test/test_pcapng.c
@@ -110,7 +110,7 @@ test_setup(void)
 	}
 
 	/* Make a pool for cloned packets */
-	mp = rte_pktmbuf_pool_create_by_ops("pcapng_test_pool", NUM_PACKETS,
+	mp = rte_pktmbuf_pool_create_by_ops("pcapng_test_pool", IOV_MAX + NUM_PACKETS,
 					    0, 0,
 					    rte_pcapng_mbuf_size(pkt_len),
 					    SOCKET_ID_ANY, "ring_mp_sc");
@@ -237,6 +237,45 @@ test_validate(void)
 	return ret;
 }
 
+static int
+test_write_over_limit_iov_max(void)
+{
+	struct rte_mbuf *orig;
+	struct rte_mbuf *clones[IOV_MAX + NUM_PACKETS] = { };
+	struct dummy_mbuf mbfs;
+	unsigned int i;
+	ssize_t len;
+
+	/* make a dummy packet */
+	mbuf1_prepare(&mbfs, pkt_len);
+
+	/* clone them */
+	orig  = &mbfs.mb[0];
+	for (i = 0; i < IOV_MAX + NUM_PACKETS; i++) {
+		struct rte_mbuf *mc;
+
+		mc = rte_pcapng_copy(port_id, 0, orig, mp, pkt_len,
+				rte_get_tsc_cycles(), 0);
+		if (mc == NULL) {
+			fprintf(stderr, "Cannot copy packet\n");
+			return -1;
+		}
+		clones[i] = mc;
+	}
+
+	/* write it to capture file */
+	len = rte_pcapng_write_packets(pcapng, clones, IOV_MAX + NUM_PACKETS);
+
+	rte_pktmbuf_free_bulk(clones, IOV_MAX + NUM_PACKETS);
+
+	if (len <= 0) {
+		fprintf(stderr, "Write of packets failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 static void
 test_cleanup(void)
 {
@@ -256,6 +295,7 @@ unit_test_suite test_pcapng_suite  = {
 		TEST_CASE(test_write_packets),
 		TEST_CASE(test_write_stats),
 		TEST_CASE(test_validate),
+		TEST_CASE(test_write_over_limit_iov_max),
 		TEST_CASES_END()
 	}
 };
diff --git a/lib/pcapng/rte_pcapng.c b/lib/pcapng/rte_pcapng.c
index 06ad712bd1..e41cf909e1 100644
--- a/lib/pcapng/rte_pcapng.c
+++ b/lib/pcapng/rte_pcapng.c
@@ -551,33 +551,16 @@ rte_pcapng_copy(uint16_t port_id, uint32_t queue,
 	return NULL;
 }
 
-/* Count how many segments are in this array of mbufs */
-static unsigned int
-mbuf_burst_segs(struct rte_mbuf *pkts[], unsigned int n)
-{
-	unsigned int i, iovcnt;
-
-	for (iovcnt = 0, i = 0; i < n; i++) {
-		const struct rte_mbuf *m = pkts[i];
-
-		__rte_mbuf_sanity_check(m, 1);
-
-		iovcnt += m->nb_segs;
-	}
-	return iovcnt;
-}
-
 /* Write pre-formatted packets to file. */
 ssize_t
 rte_pcapng_write_packets(rte_pcapng_t *self,
 			 struct rte_mbuf *pkts[], uint16_t nb_pkts)
 {
-	int iovcnt = mbuf_burst_segs(pkts, nb_pkts);
-	struct iovec iov[iovcnt];
-	unsigned int i, cnt;
-	ssize_t ret;
+	struct iovec iov[IOV_MAX];
+	unsigned int i, cnt = 0;
+	ssize_t ret, total = 0;
 
-	for (i = cnt = 0; i < nb_pkts; i++) {
+	for (i = 0; i < nb_pkts; i++) {
 		struct rte_mbuf *m = pkts[i];
 		struct pcapng_enhance_packet_block *epb;
 
@@ -589,6 +572,20 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
 			return -1;
 		}
 
+		/*
+		 * Handle case of highly fragmented and large burst size
+		 * Note: this assumes that max segments per mbuf < IOV_MAX
+		 */
+		if (unlikely(cnt + m->nb_segs >= IOV_MAX)) {
+			ret = writev(self->outfd, iov, cnt);
+			if (unlikely(ret < 0)) {
+				rte_errno = errno;
+				return -1;
+			}
+			total += ret;
+			cnt = 0;
+		}
+
 		/*
 		 * The DPDK port is recorded during pcapng_copy.
 		 * Map that to PCAPNG interface in file.
@@ -601,10 +598,12 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
 		} while ((m = m->next));
 	}
 
-	ret = writev(self->outfd, iov, iovcnt);
-	if (unlikely(ret < 0))
+	ret = writev(self->outfd, iov, cnt);
+	if (unlikely(ret < 0)) {
 		rte_errno = errno;
-	return ret;
+		return -1;
+	}
+	return total + ret;
 }
 
 /* Create new pcapng writer handle */
-- 
2.31.1


  parent reply	other threads:[~2022-08-01  8:41 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-25 15:28 [PATCH] " Mário Kuka
2022-07-25 15:57 ` Stephen Hemminger
2022-07-25 16:10 ` Stephen Hemminger
2022-07-29  7:18 ` [PATCH v2 0/2] pcapng: fix some issues with writing packets Mário Kuka
2022-07-29  7:18   ` [PATCH v2 1/2] pcapng: fix write more packets than IOV_MAX limit Mário Kuka
2022-07-29  7:18   ` [PATCH v2 2/2] pcapng: check if writev() returns a partial write Mário Kuka
2022-07-29 16:00     ` Stephen Hemminger
2022-07-29 17:08       ` Mário Kuka
2022-07-29 18:14         ` Stephen Hemminger
2022-08-01  8:42           ` Mário Kuka
2022-07-29 15:58   ` [PATCH v2 0/2] pcapng: fix some issues with writing packets Stephen Hemminger
2022-07-29 17:33     ` Mário Kuka
2022-08-01  8:40   ` Mário Kuka [this message]
2022-08-01 15:33     ` [PATCH v3] pcapng: fix write more packets than IOV_MAX limit Stephen Hemminger
2022-10-10  0:40       ` 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=20220801084056.17418-1-kuka@cesnet.cz \
    --to=kuka@cesnet.cz \
    --cc=dev@dpdk.org \
    --cc=mdr@ashroe.eu \
    --cc=reshma.pattan@intel.com \
    --cc=stephen@networkplumber.org \
    /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).