From: "Mário Kuka" <kuka@cesnet.cz>
To: Reshma Pattan <reshma.pattan@intel.com>,
Stephen Hemminger <stephen@networkplumber.org>,
Ray Kinsella <mdr@ashroe.eu>
Cc: dev@dpdk.org, "Mário Kuka" <kuka@cesnet.cz>
Subject: [PATCH] pcapng: fix write more packets than IOV_MAX limit
Date: Mon, 25 Jul 2022 17:28:11 +0200 [thread overview]
Message-ID: <20220725152811.409447-1-kuka@cesnet.cz> (raw)
The rte_pcapng_write_packets() function fails when we try to write more
packets than the IOV_MAX limit. The error is caused by the writev()
system call, which 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 split the iovec buffer into smaller
chunks with a maximum size of IOV_MAX and write them sequentially by
calling the writev() repeatedly.
Fixes: 8d23ce8f5ee9 ("pcapng: add new library for writing pcapng files")
Cc: stephen@networkplumber.org
Signed-off-by: Mário Kuka <kuka@cesnet.cz>
---
app/test/test_pcapng.c | 42 ++++++++++++++++++++++++++++-
lib/pcapng/rte_pcapng.c | 58 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 98 insertions(+), 2 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..5762f89cb9 100644
--- a/lib/pcapng/rte_pcapng.c
+++ b/lib/pcapng/rte_pcapng.c
@@ -567,6 +567,62 @@ mbuf_burst_segs(struct rte_mbuf *pkts[], unsigned int n)
return iovcnt;
}
+/*
+ * Update iov after writev() has returned written. We must find how many iov
+ * buffers (from beginning) have been written. The first buffer that was not
+ * written fully is to be updated accordingly.
+ *
+ * Returns offset of buffer that was not written fully.
+ */
+static int
+pcapng_update_iov(struct iovec *iov, const int count, size_t written)
+{
+ for (int i = 0; written > 0 && i < count; ++i) {
+ if (written < iov[i].iov_len) {
+ /* found buffer that was not written fully */
+ iov[i].iov_base = RTE_PTR_ADD(iov[i].iov_base, written);
+ iov[i].iov_len -= written;
+
+ return i;
+ }
+
+ /* buffer fully written, zero it and skip */
+ written -= iov[i].iov_len;
+
+ iov[i].iov_base = NULL;
+ iov[i].iov_len = 0;
+ }
+
+ return count;
+}
+
+/*
+ * Writes all iovcnt buffers of data described by iov to the file associated with
+ * the file descriptor fd.
+ *
+ * Note: POSIX.1-2001 allows an implementation to place a limit on the number
+ * of items that can be passed in iov. An implementation can advertise
+ * its limit by defining IOV_MAX in <limits.h>.
+ */
+static ssize_t
+pcapng_writev(int fd, struct iovec *iov, const int count)
+{
+ size_t total = 0;
+ int at = 0;
+
+ while (at < count) {
+ const int iov_cnt = RTE_MIN(count - at, IOV_MAX);
+ ssize_t wlen = writev(fd, &iov[at], iov_cnt);
+ if (unlikely(wlen < 0))
+ return wlen;
+
+ total += wlen;
+ at += pcapng_update_iov(&iov[at], iov_cnt, wlen);
+ }
+
+ return total;
+}
+
/* Write pre-formatted packets to file. */
ssize_t
rte_pcapng_write_packets(rte_pcapng_t *self,
@@ -601,7 +657,7 @@ rte_pcapng_write_packets(rte_pcapng_t *self,
} while ((m = m->next));
}
- ret = writev(self->outfd, iov, iovcnt);
+ ret = pcapng_writev(self->outfd, iov, iovcnt);
if (unlikely(ret < 0))
rte_errno = errno;
return ret;
--
2.31.1
next reply other threads:[~2022-07-25 19:43 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-25 15:28 Mário Kuka [this message]
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 ` [PATCH v3] pcapng: fix write more packets than IOV_MAX limit Mário Kuka
2022-08-01 15:33 ` 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=20220725152811.409447-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).