On Mon, 25 Jul 2022 17:28:11 +0200 Mário Kuka <k...@cesnet.cz> wrote:
> 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: step...@networkplumber.org > > Signed-off-by: Mário Kuka <k...@cesnet.cz> > --- Something like this (compile tested only). diff --git a/lib/pcapng/rte_pcapng.c b/lib/pcapng/rte_pcapng.c index 06ad712bd1eb..e41cf909e120 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 */