From: Laurent Vivier <lvivier@redhat.com>
To: passt-dev@passt.top
Cc: Laurent Vivier <lvivier@redhat.com>
Subject: [PATCH v5 29/29] packet: use buf to store iovec array
Date: Thu, 17 Apr 2025 18:51:36 +0200 [thread overview]
Message-ID: <20250417165136.2688884-30-lvivier@redhat.com> (raw)
In-Reply-To: <20250417165136.2688884-1-lvivier@redhat.com>
When we use vhost-user we don't use the memory buffer
of the pool to store the packet, so we can use it to
store iovec array that points to the memory provided
by vhost-user.
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
packet.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 147 insertions(+), 16 deletions(-)
diff --git a/packet.c b/packet.c
index 0a2ad28d3d25..ccd98ff3aa36 100644
--- a/packet.c
+++ b/packet.c
@@ -84,6 +84,121 @@ bool pool_full(const struct pool *p)
return p->count >= p->size;
}
+/**
+ * packet_iov_max_cnt() - Return the maximum number of iovec we can store
+ * @p: Pointer to packet pool
+ *
+ * Return: the maximum number of iovec we can store in the memory of
+ * the pool buffer
+ */
+static size_t packet_iov_max_cnt(const struct pool *p)
+{
+ return p->buf_size / sizeof(struct iovec);
+}
+
+/**
+ * packet_iov_idx() - For a given packet index, return the iovec index and
+ * the number of iovec entry of the packet
+ * @p: Pointer to packet pool
+ * @idx: Index of packet descriptor in pool
+ * @iov_cnt: Pointer to store the number of the iovec entry of the packet
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ *
+ * Return: the iovec index for the given packet index, @iov_cnt is set
+ * to the number of the iovec entry of the packet
+ */
+static int packet_iov_idx(const struct pool *p, size_t idx, size_t *iov_cnt,
+ const char *func, int line)
+{
+ size_t iov_idx, max = packet_iov_max_cnt(p);
+
+ iov_idx = (size_t)p->pkt[idx].iov_base;
+ *iov_cnt = p->pkt[idx].iov_len;
+
+ ASSERT_WITH_MSG(iov_idx + *iov_cnt <= max,
+ "Corrupt iov entry: (%zu, %zu), max: %zu, %s:%i",
+ iov_idx, *iov_cnt, max, func, line);
+
+ return iov_idx;
+}
+
+/**
+ * packet_iov_next_idx() - Give the the next available iovec index
+ * @p: Pointer to packet pool
+ * @idx: Index of packet descriptor in pool
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ *
+ * Return: the next available iovec index
+ */
+static size_t packet_iov_next_idx(const struct pool *p, size_t idx,
+ const char *func, int line)
+{
+ size_t iov_idx, iov_cnt;
+
+ if (idx == 0)
+ return 0;
+
+ iov_idx = packet_iov_idx(p, idx - 1, &iov_cnt, func, line);
+
+ return iov_idx + iov_cnt;
+}
+
+/**
+ * packet_iov_data() - For a given packet index, provide the iovec array
+ * @p: Pointer to packet pool
+ * @idx: Index of packet descriptor in pool
+ * @data: iov_tail to store iovec array and count
+ * (offset is always set to 0)
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ */
+static void packet_iov_data(const struct pool *p, size_t idx,
+ struct iov_tail *data,
+ const char *func, int line)
+{
+ struct iovec *iov = (struct iovec *)p->buf;
+ size_t iov_idx, iov_cnt;
+
+ iov_idx = packet_iov_idx(p, idx, &iov_cnt, func, line);
+
+ data->iov = &iov[iov_idx];
+ data->cnt = iov_cnt;
+ data->off = 0;
+}
+
+/**
+ * packet_iov_check_range() - Check if iovec array is valid for a pool
+ * @p: Pointer to packet pool
+ * @data: iov_tail that stores the iovec array to check
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ *
+ * Return: 0 if the range is valid, -1 otherwise
+ */
+static int packet_iov_check_range(const struct pool *p,
+ const struct iov_tail *data,
+ const char *func, int line)
+{
+ size_t offset, i;
+
+ offset = data->off;
+ for (i = 0; i < data->cnt; i++) {
+ int ret;
+
+ ret = packet_check_range(p,
+ (char *)data->iov[i].iov_base + offset,
+ data->iov[i].iov_len - offset,
+ func, line);
+ if (ret)
+ return ret;
+ offset = 0;
+ }
+
+ return 0;
+}
+
/**
* packet_add_do() - Add data as packet descriptor to given pool
* @p: Existing pool
@@ -107,14 +222,32 @@ void packet_add_do(struct pool *p, struct iov_tail *data,
if (!iov_tail_prune(data))
return;
- ASSERT(data->cnt == 1); /* we don't support iovec */
+ if (packet_iov_check_range(p, data, func, line))
+ return;
+
+ if (p->memory) {
+ size_t iov_max_cnt = packet_iov_max_cnt(p);
+ struct iovec *iov = (struct iovec *)p->buf;
+ size_t iov_idx;
+ int iov_cnt;
- len = data->iov[0].iov_len - data->off;
- start = (char *)data->iov[0].iov_base + data->off;
+ iov_idx = packet_iov_next_idx(p, idx, func, line);
- if (packet_check_range(p, start, len, func, line))
- return;
+ iov_cnt = iov_tail_slice(&iov[iov_idx], iov_max_cnt - iov_idx,
+ data, NULL);
+ if (iov_cnt < 0) {
+ debug("add iov (%zu,%zu) to buf with size %zu, %s:%i",
+ iov_idx, data->cnt, iov_max_cnt, func, line);
+ return;
+ }
+ len = iov_cnt;
+ /* NOLINTNEXTLINE(performance-no-int-to-ptr) */
+ start = (char *)iov_idx;
+ } else {
+ len = data->iov[0].iov_len - data->off;
+ start = (char *)data->iov[0].iov_base + data->off;
+ }
p->pkt[idx].iov_base = (void *)start;
p->pkt[idx].iov_len = len;
@@ -135,8 +268,6 @@ bool packet_data_do(const struct pool *p, size_t idx,
struct iov_tail *data,
const char *func, int line)
{
- size_t i;
-
ASSERT_WITH_MSG(p->count <= p->size,
"Corrupt pool count: %zu, size: %zu, %s:%i",
p->count, p->size, func, line);
@@ -147,17 +278,17 @@ bool packet_data_do(const struct pool *p, size_t idx,
return false;
}
- data->cnt = 1;
- data->off = 0;
- data->iov = &p->pkt[idx];
-
- for (i = 0; i < data->cnt; i++) {
- ASSERT_WITH_MSG(!packet_check_range(p, data->iov[i].iov_base,
- data->iov[i].iov_len,
- func, line),
- "Corrupt packet pool, %s:%i", func, line);
+ if (p->memory) {
+ packet_iov_data(p, idx, data, func, line);
+ } else {
+ data->cnt = 1;
+ data->off = 0;
+ data->iov = &p->pkt[idx];
}
+ ASSERT_WITH_MSG(!packet_iov_check_range(p, data, func, line),
+ "Corrupt packet pool, %s:%i", func, line);
+
return true;
}
--
@@ -84,6 +84,121 @@ bool pool_full(const struct pool *p)
return p->count >= p->size;
}
+/**
+ * packet_iov_max_cnt() - Return the maximum number of iovec we can store
+ * @p: Pointer to packet pool
+ *
+ * Return: the maximum number of iovec we can store in the memory of
+ * the pool buffer
+ */
+static size_t packet_iov_max_cnt(const struct pool *p)
+{
+ return p->buf_size / sizeof(struct iovec);
+}
+
+/**
+ * packet_iov_idx() - For a given packet index, return the iovec index and
+ * the number of iovec entry of the packet
+ * @p: Pointer to packet pool
+ * @idx: Index of packet descriptor in pool
+ * @iov_cnt: Pointer to store the number of the iovec entry of the packet
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ *
+ * Return: the iovec index for the given packet index, @iov_cnt is set
+ * to the number of the iovec entry of the packet
+ */
+static int packet_iov_idx(const struct pool *p, size_t idx, size_t *iov_cnt,
+ const char *func, int line)
+{
+ size_t iov_idx, max = packet_iov_max_cnt(p);
+
+ iov_idx = (size_t)p->pkt[idx].iov_base;
+ *iov_cnt = p->pkt[idx].iov_len;
+
+ ASSERT_WITH_MSG(iov_idx + *iov_cnt <= max,
+ "Corrupt iov entry: (%zu, %zu), max: %zu, %s:%i",
+ iov_idx, *iov_cnt, max, func, line);
+
+ return iov_idx;
+}
+
+/**
+ * packet_iov_next_idx() - Give the the next available iovec index
+ * @p: Pointer to packet pool
+ * @idx: Index of packet descriptor in pool
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ *
+ * Return: the next available iovec index
+ */
+static size_t packet_iov_next_idx(const struct pool *p, size_t idx,
+ const char *func, int line)
+{
+ size_t iov_idx, iov_cnt;
+
+ if (idx == 0)
+ return 0;
+
+ iov_idx = packet_iov_idx(p, idx - 1, &iov_cnt, func, line);
+
+ return iov_idx + iov_cnt;
+}
+
+/**
+ * packet_iov_data() - For a given packet index, provide the iovec array
+ * @p: Pointer to packet pool
+ * @idx: Index of packet descriptor in pool
+ * @data: iov_tail to store iovec array and count
+ * (offset is always set to 0)
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ */
+static void packet_iov_data(const struct pool *p, size_t idx,
+ struct iov_tail *data,
+ const char *func, int line)
+{
+ struct iovec *iov = (struct iovec *)p->buf;
+ size_t iov_idx, iov_cnt;
+
+ iov_idx = packet_iov_idx(p, idx, &iov_cnt, func, line);
+
+ data->iov = &iov[iov_idx];
+ data->cnt = iov_cnt;
+ data->off = 0;
+}
+
+/**
+ * packet_iov_check_range() - Check if iovec array is valid for a pool
+ * @p: Pointer to packet pool
+ * @data: iov_tail that stores the iovec array to check
+ * @func: For tracing: name of calling function
+ * @line: For tracing: caller line of function call
+ *
+ * Return: 0 if the range is valid, -1 otherwise
+ */
+static int packet_iov_check_range(const struct pool *p,
+ const struct iov_tail *data,
+ const char *func, int line)
+{
+ size_t offset, i;
+
+ offset = data->off;
+ for (i = 0; i < data->cnt; i++) {
+ int ret;
+
+ ret = packet_check_range(p,
+ (char *)data->iov[i].iov_base + offset,
+ data->iov[i].iov_len - offset,
+ func, line);
+ if (ret)
+ return ret;
+ offset = 0;
+ }
+
+ return 0;
+}
+
/**
* packet_add_do() - Add data as packet descriptor to given pool
* @p: Existing pool
@@ -107,14 +222,32 @@ void packet_add_do(struct pool *p, struct iov_tail *data,
if (!iov_tail_prune(data))
return;
- ASSERT(data->cnt == 1); /* we don't support iovec */
+ if (packet_iov_check_range(p, data, func, line))
+ return;
+
+ if (p->memory) {
+ size_t iov_max_cnt = packet_iov_max_cnt(p);
+ struct iovec *iov = (struct iovec *)p->buf;
+ size_t iov_idx;
+ int iov_cnt;
- len = data->iov[0].iov_len - data->off;
- start = (char *)data->iov[0].iov_base + data->off;
+ iov_idx = packet_iov_next_idx(p, idx, func, line);
- if (packet_check_range(p, start, len, func, line))
- return;
+ iov_cnt = iov_tail_slice(&iov[iov_idx], iov_max_cnt - iov_idx,
+ data, NULL);
+ if (iov_cnt < 0) {
+ debug("add iov (%zu,%zu) to buf with size %zu, %s:%i",
+ iov_idx, data->cnt, iov_max_cnt, func, line);
+ return;
+ }
+ len = iov_cnt;
+ /* NOLINTNEXTLINE(performance-no-int-to-ptr) */
+ start = (char *)iov_idx;
+ } else {
+ len = data->iov[0].iov_len - data->off;
+ start = (char *)data->iov[0].iov_base + data->off;
+ }
p->pkt[idx].iov_base = (void *)start;
p->pkt[idx].iov_len = len;
@@ -135,8 +268,6 @@ bool packet_data_do(const struct pool *p, size_t idx,
struct iov_tail *data,
const char *func, int line)
{
- size_t i;
-
ASSERT_WITH_MSG(p->count <= p->size,
"Corrupt pool count: %zu, size: %zu, %s:%i",
p->count, p->size, func, line);
@@ -147,17 +278,17 @@ bool packet_data_do(const struct pool *p, size_t idx,
return false;
}
- data->cnt = 1;
- data->off = 0;
- data->iov = &p->pkt[idx];
-
- for (i = 0; i < data->cnt; i++) {
- ASSERT_WITH_MSG(!packet_check_range(p, data->iov[i].iov_base,
- data->iov[i].iov_len,
- func, line),
- "Corrupt packet pool, %s:%i", func, line);
+ if (p->memory) {
+ packet_iov_data(p, idx, data, func, line);
+ } else {
+ data->cnt = 1;
+ data->off = 0;
+ data->iov = &p->pkt[idx];
}
+ ASSERT_WITH_MSG(!packet_iov_check_range(p, data, func, line),
+ "Corrupt packet pool, %s:%i", func, line);
+
return true;
}
--
2.49.0
prev parent reply other threads:[~2025-04-17 16:52 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-17 16:51 [PATCH v5 00/29] Introduce discontiguous frames management Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 01/29] arp: Don't mix incoming and outgoing buffers Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 02/29] iov: Introduce iov_slice(), iov_tail_slice() and iov_tail_drop() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 03/29] iov: Update IOV_REMOVE_HEADER() and IOV_PEEK_HEADER() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 04/29] tap: Use iov_tail with tap_add_packet() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 05/29] packet: Use iov_tail with packet_add() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 06/29] packet: Add packet_data() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 07/29] arp: Convert to iov_tail Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 08/29] ndp: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 09/29] icmp: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 10/29] udp: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 11/29] tcp: Convert tcp_tap_handler() to use iov_tail Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 12/29] tcp: Convert tcp_data_from_tap() " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 13/29] dhcpv6: move offset initialization out of dhcpv6_opt() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 14/29] dhcpv6: Extract sending of NotOnLink status Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 15/29] dhcpv6: Convert to iov_tail Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 16/29] dhcpv6: Use iov_tail in dhcpv6_opt() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 17/29] dhcp: Convert to iov_tail Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 18/29] ip: Use iov_tail in ipv6_l4hdr() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 19/29] tap: Convert tap4_handler() to iov_tail Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 20/29] tap: Convert tap6_handler() " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 21/29] arp: use iov_tail rather than pool Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 22/29] dhcp: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 23/29] dhcpv6: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 24/29] icmp: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 25/29] ndp: " Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 26/29] packet: remove PACKET_POOL() and PACKET_POOL_P() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 27/29] packet: remove unused parameter from PACKET_POOL_DECL() Laurent Vivier
2025-04-17 16:51 ` [PATCH v5 28/29] packet: add memory regions information into pool Laurent Vivier
2025-04-17 16:51 ` Laurent Vivier [this message]
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=20250417165136.2688884-30-lvivier@redhat.com \
--to=lvivier@redhat.com \
--cc=passt-dev@passt.top \
/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.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
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 IMAP folder(s).