From: Laurent Vivier <lvivier@redhat.com>
To: passt-dev@passt.top
Cc: Laurent Vivier <lvivier@redhat.com>
Subject: [PATCH 5/7] tcp: Use iov_tail to access headers in tcp_prepare_flags()
Date: Mon, 23 Mar 2026 17:52:57 +0100 [thread overview]
Message-ID: <20260323165259.1253482-6-lvivier@redhat.com> (raw)
In-Reply-To: <20260323165259.1253482-1-lvivier@redhat.com>
Instead of passing separate pointers to the TCP header and SYN options,
pass an iov_tail pointing to the start of the TCP payload area.
tcp_prepare_flags() then uses with_header() and IOV_DROP_HEADER() to
access the TCP header and SYN options directly within the iov, matching
the iov_tail-based approach already used by tcp_fill_headers().
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
tcp.c | 71 +++++++++++++++++++++++++++-----------------------
tcp_buf.c | 8 +++---
tcp_internal.h | 2 +-
tcp_vu.c | 9 +++----
4 files changed, 48 insertions(+), 42 deletions(-)
diff --git a/tcp.c b/tcp.c
index 058792d5b184..ad601567d39f 100644
--- a/tcp.c
+++ b/tcp.c
@@ -1295,8 +1295,7 @@ static int tcp_rewind_seq(const struct ctx *c, struct tcp_tap_conn *conn)
* @c: Execution context
* @conn: Connection pointer
* @flags: TCP flags: if not set, send segment only if ACK is due
- * @th: TCP header to update
- * @opts: TCP option buffer (output parameter)
+ * @payload: TCP payload including TCP header
* @optlen: size of the TCP option buffer (output parameter)
*
* Return: < 0 error code on connection reset,
@@ -1304,10 +1303,11 @@ static int tcp_rewind_seq(const struct ctx *c, struct tcp_tap_conn *conn)
* 1 otherwise
*/
int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
- int flags, struct tcphdr *th, struct tcp_syn_opts *opts,
+ int flags, const struct iov_tail *payload,
size_t *optlen)
{
struct tcp_info_linux tinfo = { 0 };
+ struct iov_tail current = *payload;
socklen_t sl = sizeof(tinfo);
int s = conn->sock;
@@ -1330,6 +1330,40 @@ int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
*optlen = 0;
if (flags & SYN) {
+ conn->ws_to_tap = MIN(MAX_WS, tinfo.tcpi_snd_wscale);
+
+ *optlen = sizeof(struct tcp_syn_opts);
+ } else {
+ flags |= ACK;
+ }
+
+ with_header(struct tcphdr, th, ¤t) {
+ th->doff = (sizeof(*th) + *optlen) / 4;
+
+ th->ack = !!(flags & ACK);
+ th->psh = !!(flags & PSH);
+ th->rst = !!(flags & RST);
+ th->syn = !!(flags & SYN);
+ th->fin = !!(flags & FIN);
+
+ if (th->ack) {
+ if (SEQ_GE(conn->seq_ack_to_tap, conn->seq_from_tap) &&
+ conn->wnd_to_tap)
+ conn_flag(c, conn, ~ACK_TO_TAP_DUE);
+ else
+ conn_flag(c, conn, ACK_TO_TAP_DUE);
+ }
+
+ if (th->fin)
+ conn_flag(c, conn, ACK_FROM_TAP_DUE);
+
+ /* RFC 793, 3.1: "[...] and the first data octet is ISN+1." */
+ if (th->fin || th->syn)
+ conn->seq_to_tap++;
+ }
+ IOV_DROP_HEADER(¤t, struct tcphdr);
+
+ if (*optlen) {
int mss;
if (!c->mtu) {
@@ -1348,37 +1382,10 @@ int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
mss = ROUND_DOWN(mss, PAGE_SIZE);
}
- conn->ws_to_tap = MIN(MAX_WS, tinfo.tcpi_snd_wscale);
-
- *opts = TCP_SYN_OPTS(mss, conn->ws_to_tap);
- *optlen = sizeof(*opts);
- } else {
- flags |= ACK;
+ with_header(struct tcp_syn_opts, opts, ¤t)
+ *opts = TCP_SYN_OPTS(mss, conn->ws_to_tap);
}
- th->doff = (sizeof(*th) + *optlen) / 4;
-
- th->ack = !!(flags & ACK);
- th->psh = !!(flags & PSH);
- th->rst = !!(flags & RST);
- th->syn = !!(flags & SYN);
- th->fin = !!(flags & FIN);
-
- if (th->ack) {
- if (SEQ_GE(conn->seq_ack_to_tap, conn->seq_from_tap) &&
- conn->wnd_to_tap)
- conn_flag(c, conn, ~ACK_TO_TAP_DUE);
- else
- conn_flag(c, conn, ACK_TO_TAP_DUE);
- }
-
- if (th->fin)
- conn_flag(c, conn, ACK_FROM_TAP_DUE);
-
- /* RFC 793, 3.1: "[...] and the first data octet is ISN+1." */
- if (th->fin || th->syn)
- conn->seq_to_tap++;
-
return 1;
}
diff --git a/tcp_buf.c b/tcp_buf.c
index 891043c96dcb..ffd250c8798f 100644
--- a/tcp_buf.c
+++ b/tcp_buf.c
@@ -197,7 +197,7 @@ static void tcp_l2_buf_fill_headers(const struct ctx *c,
*/
int tcp_buf_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
{
- struct tcp_payload_t *payload;
+ struct iov_tail tail;
struct iovec *iov;
size_t optlen;
size_t l4len;
@@ -211,10 +211,10 @@ int tcp_buf_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
iov[TCP_IOV_IP] = IOV_OF_LVALUE(tcp6_payload_ip[tcp_payload_used]);
iov[TCP_IOV_ETH] = IOV_OF_LVALUE(tcp_eth_hdr[tcp_payload_used]);
- payload = iov[TCP_IOV_PAYLOAD].iov_base;
+ iov[TCP_IOV_PAYLOAD].iov_len = sizeof(struct tcp_payload_t);
+ tail = IOV_TAIL(&iov[TCP_IOV_PAYLOAD], 1, 0);
seq = conn->seq_to_tap;
- ret = tcp_prepare_flags(c, conn, flags, &payload->th,
- (struct tcp_syn_opts *)&payload->data, &optlen);
+ ret = tcp_prepare_flags(c, conn, flags, &tail, &optlen);
if (ret <= 0)
return ret;
diff --git a/tcp_internal.h b/tcp_internal.h
index 136e947f6e70..9f745d0752ff 100644
--- a/tcp_internal.h
+++ b/tcp_internal.h
@@ -190,7 +190,7 @@ size_t tcp_fill_headers(const struct ctx *c, struct tcp_tap_conn *conn,
int tcp_update_seqack_wnd(const struct ctx *c, struct tcp_tap_conn *conn,
bool force_seq, struct tcp_info_linux *tinfo);
int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
- int flags, struct tcphdr *th, struct tcp_syn_opts *opts,
+ int flags, const struct iov_tail *payload,
size_t *optlen);
int tcp_set_peek_offset(const struct tcp_tap_conn *conn, int offset);
diff --git a/tcp_vu.c b/tcp_vu.c
index 96cd9da1caae..d6bd6a34d6da 100644
--- a/tcp_vu.c
+++ b/tcp_vu.c
@@ -90,7 +90,6 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
struct ipv6hdr *ip6h = NULL;
struct iphdr *ip4h = NULL;
struct iovec flags_iov[2];
- struct tcp_syn_opts *opts;
struct iov_tail payload;
size_t optlen, hdrlen;
struct tcphdr *th;
@@ -104,13 +103,13 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
elem_cnt = vu_collect(vdev, vq, &flags_elem[0], 1,
&flags_iov[0], 1, NULL,
- hdrlen + sizeof(*opts), NULL);
+ hdrlen + sizeof(struct tcp_syn_opts), NULL);
if (elem_cnt != 1)
return -1;
assert(flags_elem[0].in_num == 1);
assert(flags_elem[0].in_sg[0].iov_len >=
- MAX(hdrlen + sizeof(*opts), ETH_ZLEN + VNET_HLEN));
+ MAX(hdrlen + sizeof(struct tcp_syn_opts), ETH_ZLEN + VNET_HLEN));
vu_set_vnethdr(flags_elem[0].in_sg[0].iov_base, 1);
@@ -139,8 +138,8 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
th->ack = 1;
seq = conn->seq_to_tap;
- opts = (struct tcp_syn_opts *)(th + 1);
- ret = tcp_prepare_flags(c, conn, flags, th, opts, &optlen);
+ payload = IOV_TAIL(flags_elem[0].in_sg, 1, hdrlen - sizeof(*th));
+ ret = tcp_prepare_flags(c, conn, flags, &payload, &optlen);
if (ret <= 0) {
vu_queue_rewind(vq, 1);
return ret;
--
2.53.0
next prev parent reply other threads:[~2026-03-23 16:53 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 16:52 [PATCH 0/7] vhost-user,tcp: Handle multiple iovec entries per virtqueue element Laurent Vivier
2026-03-23 16:52 ` [PATCH 1/7] tcp: pass ipv4h checksum, not a pointer to the checksum Laurent Vivier
2026-03-24 3:53 ` David Gibson
2026-03-24 7:56 ` Laurent Vivier
2026-03-24 23:49 ` David Gibson
2026-03-23 16:52 ` [PATCH 2/7] tcp: use iov_tail to access headers in tcp_fill_headers() Laurent Vivier
2026-03-24 3:58 ` David Gibson
2026-03-23 16:52 ` [PATCH 3/7] tcp_vu: Use iov_tail helpers to build headers in tcp_vu_prepare() Laurent Vivier
2026-03-25 4:46 ` David Gibson
2026-03-23 16:52 ` [PATCH 4/7] tcp_vu: Support multibuffer frames in tcp_vu_sock_recv() Laurent Vivier
2026-03-25 5:06 ` David Gibson
2026-03-23 16:52 ` Laurent Vivier [this message]
2026-03-23 16:52 ` [PATCH 6/7] iov: introduce iov_memcopy() Laurent Vivier
2026-03-23 16:52 ` [PATCH 7/7] tcp_vu: Use iov_tail helpers to build headers in tcp_vu_send_flag() Laurent Vivier
2026-03-25 5:07 ` [PATCH 0/7] vhost-user,tcp: Handle multiple iovec entries per virtqueue element David Gibson
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=20260323165259.1253482-6-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).