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 B1476A00C3; Mon, 1 Aug 2022 10:41:03 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 599A941101; Mon, 1 Aug 2022 10:41:03 +0200 (CEST) Received: from office2.cesnet.cz (office2.cesnet.cz [195.113.144.244]) by mails.dpdk.org (Postfix) with ESMTP id 0D1484067B for ; Mon, 1 Aug 2022 10:41:02 +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 D825840006C; Mon, 1 Aug 2022 10:41:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cesnet.cz; s=office2-2020; t=1659343261; bh=3uDR5h1RjaH0qgw+EIWd6B7FkKgAyqxjfL15nAFBZQo=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=NLdav1zUoWaqwIKXlu45FC18WFc3S+o8bBXkhkUaTeDK2mZ6LRI/0JQoVp9iZwGcD Do6bE2kCm1naSUIsaqctrW6GxAlXJzMTlDk+fcOUi7APmCakIxZhwvaGF4V19Miw8k 3W3X6it39673vQYSoKs3SSDI1yTD/oAG1J1hFNs7FQd+7RxJ/AYspHaxDQ23aBB1cb GU1y7VZgje4+AIBb3vhofxQleMtSje7FhDYwaBJ2bHpd0wfUegx5AcVtULURltrWeC vvKhM1ggIUe4vpQGlol97jzf/7LnIoC8npvyec1oQm/lPsW5BBzVAwPBV5JVscISnG ahdGzbNvb8S0w== From: =?UTF-8?q?M=C3=A1rio=20Kuka?= 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 Message-Id: <20220801084056.17418-1-kuka@cesnet.cz> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220729071841.18198-1-kuka@cesnet.cz> References: <20220729071841.18198-1-kuka@cesnet.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. 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 . 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 --- 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