aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorLaurent Vivier <lvivier@redhat.com>2026-05-20 17:18:25 +0200
committerStefano Brivio <sbrivio@redhat.com>2026-05-26 12:17:16 +0200
commitf8cace2fa5a743b33c4100c5b959d66d14f45a11 (patch)
tree95c7603ba85d2971c4ececf2e914c04a6e8ef959
parent92845dd9f0450d54c135ccef6b118fc259ea8dad (diff)
downloadpasst-f8cace2fa5a743b33c4100c5b959d66d14f45a11.tar
passt-f8cace2fa5a743b33c4100c5b959d66d14f45a11.tar.gz
passt-f8cace2fa5a743b33c4100c5b959d66d14f45a11.tar.bz2
passt-f8cace2fa5a743b33c4100c5b959d66d14f45a11.tar.lz
passt-f8cace2fa5a743b33c4100c5b959d66d14f45a11.tar.xz
passt-f8cace2fa5a743b33c4100c5b959d66d14f45a11.tar.zst
passt-f8cace2fa5a743b33c4100c5b959d66d14f45a11.zip
tcp_vu: Build headers on the stack and write them into the iovec
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> Reviewed-by: Jon Maloy <jmaloy@redhat.com> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--tcp_vu.c64
1 files changed, 28 insertions, 36 deletions
diff --git a/tcp_vu.c b/tcp_vu.c
index 65e7dfe..c13c45f 100644
--- a/tcp_vu.c
+++ b/tcp_vu.c
@@ -298,49 +298,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);
-
- eh = vu_eth(base);
-
- memcpy(eh->h_dest, c->guest_mac, sizeof(eh->h_dest));
+ struct tcphdr th = {
+ .doff = sizeof(th) / 4,
+ .ack = 1,
+ .psh = push,
+ };
+ struct iov_tail l2frame;
+ struct ipv6hdr ip6h;
+ struct iphdr ip4h;
+ struct ethhdr eh;
+
+ 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);
-
- ip6h = vu_ip(base);
- *ip6h = (struct ipv6hdr)L2_BUF_IP6_INIT(IPPROTO_TCP);
+ if (!v6)
+ ip4h = (struct iphdr)L2_BUF_IP4_INIT(IPPROTO_TCP);
+ else
+ ip6h = (struct ipv6hdr)L2_BUF_IP6_INIT(IPPROTO_TCP);
- th = vu_payloadv6(base);
- }
+ tcp_fill_headers(c, conn, &eh, v6 ? NULL : &ip4h, v6 ? &ip6h : NULL, &th,
+ &payload, dlen, *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, dlen,
- *csum_flags, conn->seq_to_tap);
+ /* write headers */
+ l2frame = 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(&l2frame, eh);
+ if (!v6)
+ IOV_PUSH_HEADER(&l2frame, ip4h);
+ else
+ IOV_PUSH_HEADER(&l2frame, ip6h);
+ IOV_PUSH_HEADER(&l2frame, th);
}
/**