From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 37F2EA00C4; Mon, 25 Jul 2022 21:43:28 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8AD694280B; Mon, 25 Jul 2022 21:43:22 +0200 (CEST) Received: from office2.cesnet.cz (office2.cesnet.cz [195.113.144.244]) by mails.dpdk.org (Postfix) with ESMTP id 6465040684 for ; Mon, 25 Jul 2022 17:29:19 +0200 (CEST) Received: from dpdk-test8.liberouter.org (rt-tmc-kou.liberouter.org [195.113.172.126]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by office2.cesnet.cz (Postfix) with ESMTPSA id BF28140006D; Mon, 25 Jul 2022 17:29:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cesnet.cz; s=office2-2020; t=1658762959; bh=Vrv/jnDpuL08wg40/yjo3OrP483VupEHzh8I8oT/s48=; h=From:To:Cc:Subject:Date; b=OmmXe9Z0wm6yrRtdFxMcPfA5RgcaJAVpKxS/KXFIyvSBJDAeEaEijEzPHXFFJ1ucf 9dW8zRKOKATv8Sa08sg7G7SjoAlpDOJdxqt3Tt+lix4L9c3jOEZnbg5sOpvPbjOqiE mmUKm235MWRQihGlZ8MoK772uzDffOJR7tWK8k7djSNjenuM32bixUsnsaQ6Urp+Is I5YVF2/qJxi+cXDjyoUBLWZYU//cTSD91E+6pgPRdZrNINbPOqFMZhmIZpmd8LbyDa D5+gmvozG+ktAuAmKfSoVdzIfVYjsDZbuKjNhV2/poEykr6Si7+vObcbqJXiOTHVMB Ju/z4xw49ghnA== From: =?UTF-8?q?M=C3=A1rio=20Kuka?= To: Reshma Pattan , Stephen Hemminger , Ray Kinsella Cc: dev@dpdk.org, =?UTF-8?q?M=C3=A1rio=20Kuka?= Subject: [PATCH] pcapng: fix write more packets than IOV_MAX limit Date: Mon, 25 Jul 2022 17:28:11 +0200 Message-Id: <20220725152811.409447-1-kuka@cesnet.cz> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Mailman-Approved-At: Mon, 25 Jul 2022 21:43:21 +0200 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org 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 . 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 --- 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 . + */ +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