public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Laurent Vivier <lvivier@redhat.com>
To: passt-dev@passt.top
Cc: Laurent Vivier <lvivier@redhat.com>
Subject: [PATCH v2 2/5] tcp_vu: Build headers on the stack and write them into the iovec
Date: Fri, 27 Mar 2026 19:09:55 +0100	[thread overview]
Message-ID: <20260327180958.833430-3-lvivier@redhat.com> (raw)
In-Reply-To: <20260327180958.833430-1-lvivier@redhat.com>

tcp_vu_prepare() currently assumes the first iovec element provided by
the guest is large enough to hold all L2-L4 headers, and builds them
in place via pointer casts into iov[0].iov_base.  This assumption is
enforced by an assert().

Since the headers in the buffer are uninitialized anyway, we can just
as well build the Ethernet, IP, and TCP headers on the stack instead,
and write them into the iovec with IOV_PUSH_HEADER().  This mirrors the
approach already used in udp_vu_prepare(), and prepares for support of
elements with multiple iovecs.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
 tcp_vu.c | 60 ++++++++++++++++++++++++--------------------------------
 1 file changed, 26 insertions(+), 34 deletions(-)

diff --git a/tcp_vu.c b/tcp_vu.c
index 67b11e28118a..56d80317cc83 100644
--- a/tcp_vu.c
+++ b/tcp_vu.c
@@ -288,49 +288,41 @@ static void tcp_vu_prepare(const struct ctx *c, struct tcp_tap_conn *conn,
 	bool v6 = !(inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr));
 	size_t hdrlen = tcp_vu_hdrlen(v6);
 	struct iov_tail payload = IOV_TAIL(iov, iov_cnt, hdrlen);
-	char *base = iov[0].iov_base;
-	struct ipv6hdr *ip6h = NULL;
-	struct iphdr *ip4h = NULL;
-	struct tcphdr *th;
-	struct ethhdr *eh;
-
-	/* we guess the first iovec provided by the guest can embed
-	 * all the headers needed by L2 frame, including any padding
-	 */
-	assert(iov[0].iov_len >= hdrlen);
+	struct ipv6hdr ip6h;
+	struct iphdr ip4h;
+	struct tcphdr th;
+	struct ethhdr eh;
 
-	eh = vu_eth(base);
-
-	memcpy(eh->h_dest, c->guest_mac, sizeof(eh->h_dest));
+	memcpy(eh.h_dest, c->guest_mac, sizeof(eh.h_dest));
 
 	/* initialize header */
 
-	if (!v6) {
-		eh->h_proto = htons(ETH_P_IP);
-
-		ip4h = vu_ip(base);
-		*ip4h = (struct iphdr)L2_BUF_IP4_INIT(IPPROTO_TCP);
-		th = vu_payloadv4(base);
-	} else {
-		eh->h_proto = htons(ETH_P_IPV6);
+	if (!v6)
+		ip4h = (struct iphdr)L2_BUF_IP4_INIT(IPPROTO_TCP);
+	else
+		ip6h = (struct ipv6hdr)L2_BUF_IP6_INIT(IPPROTO_TCP);
 
-		ip6h = vu_ip(base);
-		*ip6h = (struct ipv6hdr)L2_BUF_IP6_INIT(IPPROTO_TCP);
+	memset(&th, 0, sizeof(th));
+	th.doff = sizeof(th) / 4;
+	th.ack = 1;
+	th.psh = push;
 
-		th = vu_payloadv6(base);
-	}
+	tcp_fill_headers(c, conn, &eh, v6 ? NULL : &ip4h, v6 ? &ip6h : NULL, &th,
+			 &payload, *csum_flags, conn->seq_to_tap);
 
-	memset(th, 0, sizeof(*th));
-	th->doff = sizeof(*th) / 4;
-	th->ack = 1;
-	th->psh = push;
+	/* Preserve TCP_CSUM, overwrite IP4_CSUM as we set the checksum */
+	if (!v6)
+		*csum_flags = (*csum_flags & TCP_CSUM) | ip4h.check;
 
-	tcp_fill_headers(c, conn, eh, ip4h, ip6h, th, &payload,
-			 *csum_flags, conn->seq_to_tap);
+	/* write headers */
+	payload = IOV_TAIL(iov, iov_cnt, VNET_HLEN);
 
-	/* Preserve TCP_CSUM, overwrite IP4_CSUM as we set the checksum */
-	if (ip4h)
-		*csum_flags = (*csum_flags & TCP_CSUM) | ip4h->check;
+	IOV_PUSH_HEADER(&payload, eh);
+	if (!v6)
+		IOV_PUSH_HEADER(&payload, ip4h);
+	else
+		IOV_PUSH_HEADER(&payload, ip6h);
+	IOV_PUSH_HEADER(&payload, th);
 }
 
 /**
-- 
2.53.0


  parent reply	other threads:[~2026-03-27 18:10 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-27 18:09 [PATCH v2 0/5] vhost-user,tcp: Handle multiple iovec entries per virtqueue element Laurent Vivier
2026-03-27 18:09 ` [PATCH v2 1/5] tcp: Encode checksum computation flags in a single parameter Laurent Vivier
2026-03-27 18:09 ` Laurent Vivier [this message]
2026-03-27 18:09 ` [PATCH v2 3/5] tcp_vu: Support multibuffer frames in tcp_vu_sock_recv() Laurent Vivier
2026-03-27 18:09 ` [PATCH v2 4/5] iov: Add iov_memcopy() to copy data between iovec arrays Laurent Vivier
2026-03-27 18:09 ` [PATCH v2 5/5] tcp_vu: Support multibuffer frames in tcp_vu_send_flag() Laurent Vivier

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=20260327180958.833430-3-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).