On Mon, Mar 23, 2026 at 05:52:54PM +0100, Laurent Vivier wrote: > Instead of receiving individual pointers to each protocol header (eh, > ip4h, ip6h, th), have tcp_fill_headers() take an iov_tail starting at > the Ethernet header and walk through it using with_header() and > IOV_DROP_HEADER() to access each header in turn. > > Replace the ip4h/ip6h NULL-pointer convention with a bool ipv4 > parameter, and move Ethernet header filling (MAC address and ethertype) > into tcp_fill_headers() as well, since the function now owns the full > header chain. > > This simplifies callers, which no longer need to extract and pass > individual header pointers. > > Signed-off-by: Laurent Vivier > --- > tcp.c | 106 +++++++++++++++++++++++++++---------------------- > tcp_buf.c | 16 ++------ > tcp_internal.h | 4 +- > tcp_vu.c | 12 +++--- > 4 files changed, 70 insertions(+), 68 deletions(-) > > diff --git a/tcp.c b/tcp.c > index 158a5be0327e..058792d5b184 100644 > --- a/tcp.c > +++ b/tcp.c > @@ -938,11 +938,8 @@ static void tcp_fill_header(struct tcphdr *th, > * tcp_fill_headers() - Fill 802.3, IP, TCP headers > * @c: Execution context > * @conn: Connection pointer > - * @eh: Pointer to Ethernet header > - * @ip4h: Pointer to IPv4 header, or NULL > - * @ip6h: Pointer to IPv6 header, or NULL > - * @th: Pointer to TCP header > - * @payload: TCP payload > + * @ipv4: True for IPv4, false for IPv6 > + * @payload: IOV tail starting at the Ethernet header As UDP I'm not sure I like removing the separater parameters. A little more so, since this doesn't (any more) have the ugly udp_payload_t equivalent. At minimum @payload is no longer a good name. > * @ip4_check: IPv4 checksum, if already known > * @seq: Sequence number for this segment > * @no_tcp_csum: Do not set TCP checksum > @@ -950,74 +947,89 @@ static void tcp_fill_header(struct tcphdr *th, > * Return: frame length (including L2 headers) > */ > size_t tcp_fill_headers(const struct ctx *c, struct tcp_tap_conn *conn, > - struct ethhdr *eh, > - struct iphdr *ip4h, struct ipv6hdr *ip6h, > - struct tcphdr *th, struct iov_tail *payload, > + bool ipv4, const struct iov_tail *payload, > int ip4_check, uint32_t seq, bool no_tcp_csum) > { > const struct flowside *tapside = TAPFLOW(conn); > - size_t l4len = iov_tail_size(payload) + sizeof(*th); > + struct iov_tail current = *payload; > uint8_t *omac = conn->f.tap_omac; > - size_t l3len = l4len; > + size_t l3len, l4len; > uint32_t psum = 0; > > - if (ip4h) { > + with_header(struct ethhdr, eh, ¤t) { > + if (ipv4) > + eh->h_proto = htons_constant(ETH_P_IP); > + else > + eh->h_proto = htons_constant(ETH_P_IPV6); > + > + /* Find if neighbour table has a recorded MAC address */ > + if (MAC_IS_UNDEF(omac)) > + fwd_neigh_mac_get(c, &tapside->oaddr, omac); > + eth_update_mac(eh, NULL, omac); > + } > + IOV_DROP_HEADER(¤t, struct ethhdr); > + > + l3len = iov_tail_size(¤t); > + > + if (ipv4) { > const struct in_addr *src4 = inany_v4(&tapside->oaddr); > const struct in_addr *dst4 = inany_v4(&tapside->eaddr); > > assert(src4 && dst4); > > - l3len += + sizeof(*ip4h); > + l4len = l3len - sizeof(struct iphdr); > > - ip4h->tot_len = htons(l3len); > - ip4h->saddr = src4->s_addr; > - ip4h->daddr = dst4->s_addr; > + with_header(struct iphdr, ip4h, ¤t) { > + ip4h->tot_len = htons(l3len); > + ip4h->saddr = src4->s_addr; > + ip4h->daddr = dst4->s_addr; > > - if (ip4_check != -1) > - ip4h->check = ip4_check; > - else > - ip4h->check = csum_ip4_header(l3len, IPPROTO_TCP, > - *src4, *dst4); > + if (ip4_check != -1) > + ip4h->check = ip4_check; > + else > + ip4h->check = csum_ip4_header(l3len, > + IPPROTO_TCP, > + *src4, *dst4); > + } > + IOV_DROP_HEADER(¤t, struct iphdr); > > if (!no_tcp_csum) { > psum = proto_ipv4_header_psum(l4len, IPPROTO_TCP, > *src4, *dst4); > } > - eh->h_proto = htons_constant(ETH_P_IP); > - } > - > - if (ip6h) { > - l3len += sizeof(*ip6h); > + } else { > + l4len = l3len - sizeof(struct ipv6hdr); > > - ip6h->payload_len = htons(l4len); > - ip6h->saddr = tapside->oaddr.a6; > - ip6h->daddr = tapside->eaddr.a6; > + with_header(struct ipv6hdr, ip6h, ¤t) { > + ip6h->payload_len = htons(l4len); > + ip6h->saddr = tapside->oaddr.a6; > + ip6h->daddr = tapside->eaddr.a6; > > - ip6h->hop_limit = 255; > - ip6h->version = 6; > - ip6h->nexthdr = IPPROTO_TCP; > + ip6h->hop_limit = 255; > + ip6h->version = 6; > + ip6h->nexthdr = IPPROTO_TCP; > > - ip6_set_flow_lbl(ip6h, conn->sock); > + ip6_set_flow_lbl(ip6h, conn->sock); > > - if (!no_tcp_csum) { > - psum = proto_ipv6_header_psum(l4len, IPPROTO_TCP, > - &ip6h->saddr, > - &ip6h->daddr); > + if (!no_tcp_csum) { > + psum = proto_ipv6_header_psum(l4len, > + IPPROTO_TCP, > + &ip6h->saddr, > + &ip6h->daddr); > + } > } > - eh->h_proto = htons_constant(ETH_P_IPV6); > + IOV_DROP_HEADER(¤t, struct ipv6hdr); > } > > - /* Find if neighbour table has a recorded MAC address */ > - if (MAC_IS_UNDEF(omac)) > - fwd_neigh_mac_get(c, &tapside->oaddr, omac); > - eth_update_mac(eh, NULL, omac); > - > - tcp_fill_header(th, conn, seq); > - > - if (no_tcp_csum) > + with_header(struct tcphdr, th, ¤t) { > + tcp_fill_header(th, conn, seq); > th->check = 0; > - else > - tcp_update_csum(psum, th, payload); > + } > + > + if (!no_tcp_csum) { > + with_header(struct tcphdr, th, ¤t) > + th->check = csum_iov_tail(¤t, psum); > + } > > return MAX(l3len + sizeof(struct ethhdr), ETH_ZLEN); > } > diff --git a/tcp_buf.c b/tcp_buf.c > index bc0f58dd7a5e..891043c96dcb 100644 > --- a/tcp_buf.c > +++ b/tcp_buf.c > @@ -175,23 +175,15 @@ static void tcp_l2_buf_fill_headers(const struct ctx *c, > struct iovec *iov, int check, > uint32_t seq, bool no_tcp_csum) > { > - struct iov_tail tail = IOV_TAIL(&iov[TCP_IOV_PAYLOAD], 1, 0); > - struct tcphdr th_storage, *th = IOV_REMOVE_HEADER(&tail, th_storage); > + struct iov_tail tail = IOV_TAIL(&iov[TCP_IOV_ETH], > + TCP_IOV_PAYLOAD + 1 - TCP_IOV_ETH, 0); > struct tap_hdr *taph = iov[TCP_IOV_TAP].iov_base; > const struct flowside *tapside = TAPFLOW(conn); > - const struct in_addr *a4 = inany_v4(&tapside->oaddr); > - struct ethhdr *eh = iov[TCP_IOV_ETH].iov_base; > - struct ipv6hdr *ip6h = NULL; > - struct iphdr *ip4h = NULL; > + bool ipv4 = inany_v4(&tapside->oaddr) != NULL; > size_t l2len; > > - if (a4) > - ip4h = iov[TCP_IOV_IP].iov_base; > - else > - ip6h = iov[TCP_IOV_IP].iov_base; > + l2len = tcp_fill_headers(c, conn, ipv4, &tail, check, seq, no_tcp_csum); > > - l2len = tcp_fill_headers(c, conn, eh, ip4h, ip6h, th, &tail, check, seq, > - no_tcp_csum); > tap_hdr_update(taph, l2len); > } > > diff --git a/tcp_internal.h b/tcp_internal.h > index bb7a6629839c..136e947f6e70 100644 > --- a/tcp_internal.h > +++ b/tcp_internal.h > @@ -184,9 +184,7 @@ void tcp_rst_do(const struct ctx *c, struct tcp_tap_conn *conn); > struct tcp_info_linux; > > size_t tcp_fill_headers(const struct ctx *c, struct tcp_tap_conn *conn, > - struct ethhdr *eh, > - struct iphdr *ip4h, struct ipv6hdr *ip6h, > - struct tcphdr *th, struct iov_tail *payload, > + bool ipv4, const struct iov_tail *payload, > int ip4_check, uint32_t seq, bool no_tcp_csum); > > int tcp_update_seqack_wnd(const struct ctx *c, struct tcp_tap_conn *conn, > diff --git a/tcp_vu.c b/tcp_vu.c > index a21ee3499aed..c6206b7a689c 100644 > --- a/tcp_vu.c > +++ b/tcp_vu.c > @@ -132,13 +132,12 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) > } > > vu_pad(&flags_iov[0], 1, 0, hdrlen + optlen); > - payload = IOV_TAIL(flags_elem[0].in_sg, 1, hdrlen); > > if (flags & KEEPALIVE) > seq--; > > - tcp_fill_headers(c, conn, eh, ip4h, ip6h, th, &payload, > - -1, seq, !*c->pcap); > + payload = IOV_TAIL(flags_elem[0].in_sg, 1, VNET_HLEN); > + tcp_fill_headers(c, conn, CONN_V4(conn), &payload, -1, seq, !*c->pcap); > > if (*c->pcap) > pcap_iov(&flags_elem[0].in_sg[0], 1, VNET_HLEN); > @@ -288,10 +287,10 @@ static void tcp_vu_prepare(const struct ctx *c, struct tcp_tap_conn *conn, > const struct flowside *toside = TAPFLOW(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 iov_tail payload; > struct tcphdr *th; > struct ethhdr *eh; > > @@ -326,8 +325,9 @@ static void tcp_vu_prepare(const struct ctx *c, struct tcp_tap_conn *conn, > th->ack = 1; > th->psh = push; > > - tcp_fill_headers(c, conn, eh, ip4h, ip6h, th, &payload, > - *check, conn->seq_to_tap, no_tcp_csum); > + payload = IOV_TAIL(iov, iov_cnt, VNET_HLEN); > + tcp_fill_headers(c, conn, !v6, &payload, *check, conn->seq_to_tap, > + no_tcp_csum); > if (ip4h) > *check = ip4h->check; > } > -- > 2.53.0 > -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson