From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v2 10/14] tap: Split tap_ip6_send() into UDP and ICMP variants
Date: Fri, 10 Oct 2025 10:40:00 +0200 [thread overview]
Message-ID: <20251010104000.2bcbc351@elisabeth> (raw)
In-Reply-To: <20221019004357.1454325-11-david@gibson.dropbear.id.au>
On Wed, 19 Oct 2022 11:43:53 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> tap_ip6_send() has special case logic to compute the checksums for UDP
> and ICMP packets, which is a mild layering violation. By using a suitable
> helper we can split it into tap_udp6_send() and tap_icmp6_send() functions
> without greatly increasing the code size, this removing that layering
> violation.
>
> We make some small changes to the interface while there. In both cases
> we make the destination IPv6 address a parameter, which will be useful
> later. For the UDP variant we make it take just the UDP payload, and it
> will generate the UDP header. For the ICMP variant we pass in the ICMP
> header as before. The inconsistency is because that's what seems to be
> the more natural way to invoke the function in the callers in each case.
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> dhcpv6.c | 21 +++------------
> icmp.c | 3 ++-
> tap.c | 82 ++++++++++++++++++++++++++++++++++++++++++--------------
> tap.h | 9 +++++--
> 4 files changed, 75 insertions(+), 40 deletions(-)
>
> diff --git a/dhcpv6.c b/dhcpv6.c
> index 7829968..e763aed 100644
> --- a/dhcpv6.c
> +++ b/dhcpv6.c
> @@ -208,15 +208,8 @@ struct msg_hdr {
> uint32_t xid:24;
> } __attribute__((__packed__));
>
> -#if __BYTE_ORDER == __BIG_ENDIAN
> -#define UH_RESP {{{ 547, 546, 0, 0, }}}
> -#else
> -#define UH_RESP {{{ __bswap_constant_16(547), __bswap_constant_16(546), 0, 0 }}}
> -#endif
> -
> /**
> * struct resp_t - Normal advertise and reply message
> - * @uh: UDP header
> * @hdr: DHCP message header
> * @server_id: Server Identifier option
> * @ia_na: Non-temporary Address option
> @@ -226,7 +219,6 @@ struct msg_hdr {
> * @dns_search: Domain Search List, here just for storage size
> */
> static struct resp_t {
> - struct udphdr uh;
> struct msg_hdr hdr;
>
> struct opt_server_id server_id;
> @@ -236,7 +228,6 @@ static struct resp_t {
> struct opt_dns_servers dns_servers;
> struct opt_dns_search dns_search;
> } __attribute__((__packed__)) resp = {
> - UH_RESP,
> { 0 },
> SERVER_ID,
>
> @@ -270,13 +261,11 @@ static const struct opt_status_code sc_not_on_link = {
>
> /**
> * struct resp_not_on_link_t - NotOnLink error (mandated by RFC 8415, 18.3.2.)
> - * @uh: UDP header
> * @hdr: DHCP message header
> * @server_id: Server Identifier option
> * @var: Payload: IA_NA from client, status code, client ID
> */
> static struct resp_not_on_link_t {
> - struct udphdr uh;
> struct msg_hdr hdr;
>
> struct opt_server_id server_id;
> @@ -284,7 +273,6 @@ static struct resp_not_on_link_t {
> uint8_t var[sizeof(struct opt_ia_na) + sizeof(struct opt_status_code) +
> sizeof(struct opt_client_id)];
> } __attribute__((__packed__)) resp_not_on_link = {
> - UH_RESP,
> { TYPE_REPLY, 0 },
> SERVER_ID,
> { 0, },
> @@ -527,12 +515,11 @@ int dhcpv6(struct ctx *c, const struct pool *p,
> n += sizeof(struct opt_hdr) + ntohs(client_id->l);
>
> n = offsetof(struct resp_not_on_link_t, var) + n;
> - resp_not_on_link.uh.len = htons(n);
>
> resp_not_on_link.hdr.xid = mh->xid;
>
> - tap_ip6_send(c, src, IPPROTO_UDP,
> - (char *)&resp_not_on_link, n, mh->xid);
> + tap_udp6_send(c, src, 547, tap_ip6_daddr(c, src), 546,
> + mh->xid, &resp_not_on_link, n);
>
> return 1;
> }
> @@ -576,11 +563,11 @@ int dhcpv6(struct ctx *c, const struct pool *p,
> n = offsetof(struct resp_t, client_id) +
> sizeof(struct opt_hdr) + ntohs(client_id->l);
> n = dhcpv6_dns_fill(c, (char *)&resp, n);
> - resp.uh.len = htons(n);
>
> resp.hdr.xid = mh->xid;
>
> - tap_ip6_send(c, src, IPPROTO_UDP, (char *)&resp, n, mh->xid);
> + tap_udp6_send(c, src, 547, tap_ip6_daddr(c, src), 546,
> + mh->xid, &resp, n);
> c->ip6.addr_seen = c->ip6.addr;
>
> return 1;
> diff --git a/icmp.c b/icmp.c
> index 61c2d90..6493ea9 100644
> --- a/icmp.c
> +++ b/icmp.c
> @@ -105,7 +105,8 @@ void icmp_sock_handler(const struct ctx *c, union epoll_ref ref,
> icmp_id_map[V6][id].seq = seq;
> }
>
> - tap_ip6_send(c, &sr6->sin6_addr, IPPROTO_ICMPV6, buf, n, 0);
> + tap_icmp6_send(c, &sr6->sin6_addr,
> + tap_ip6_daddr(c, &sr6->sin6_addr), buf, n);
> } else {
> struct sockaddr_in *sr4 = (struct sockaddr_in *)&sr;
> struct icmphdr *ih = (struct icmphdr *)buf;
> diff --git a/tap.c b/tap.c
> index 0e8c99b..135d799 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -175,21 +175,22 @@ void tap_ip4_send(const struct ctx *c, in_addr_t src, uint8_t proto,
> }
>
> /**
> - * tap_ip6_send() - Send IPv6 packet, with L2 headers, calculating L3/L4 checksums
> + * tap_push_ip6h() - Build IPv6 header for inbound packet
> * @c: Execution context
> * @src: IPv6 source address
> - * @proto: L4 protocol number
> - * @in: Payload
> + * @dst: IPv6 destination address
> * @len: L4 payload length
> - * @flow: Flow label
> + * @proto: L4 protocol number
> + * @flow: IPv6 flow identifier
> + *
> + * Return: pointer at which to write the packet's payload
> */
> -void tap_ip6_send(const struct ctx *c, const struct in6_addr *src,
> - uint8_t proto, const char *in, size_t len, uint32_t flow)
> +static void *tap_push_ip6h(char *buf,
Sorry, I missed this during review, but this function doesn't take @c
anymore, and the comment change didn't cover all the argument changes.
It takes a buffer pointer which is not entirely obvious.
You changed this later in 1ebe787fe460 ("tap: Simplify some casts in
the tap "slow path" functions"), but that commit doesn't update the
comment either.
Same for tap_push_ip4h(). I just realised as I accidentally passed an
"input" header to it.
> + const struct in6_addr *src,
> + const struct in6_addr *dst,
> + size_t len, uint8_t proto, uint32_t flow)
> {
> - char buf[USHRT_MAX];
> - struct ipv6hdr *ip6h =
> - (struct ipv6hdr *)tap_push_l2h(c, buf, ETH_P_IPV6);
> - char *data = (char *)(ip6h + 1);
> + struct ipv6hdr *ip6h = (struct ipv6hdr *)buf;
>
> ip6h->payload_len = htons(len);
> ip6h->priority = 0;
> @@ -197,24 +198,65 @@ void tap_ip6_send(const struct ctx *c, const struct in6_addr *src,
> ip6h->nexthdr = proto;
> ip6h->hop_limit = 255;
> ip6h->saddr = *src;
> - ip6h->daddr = *tap_ip6_daddr(c, src);
> + ip6h->daddr = *dst;
> ip6h->flow_lbl[0] = (flow >> 16) & 0xf;
> ip6h->flow_lbl[1] = (flow >> 8) & 0xff;
> ip6h->flow_lbl[2] = (flow >> 0) & 0xff;
> + return ip6h + 1;
> +}
>
> +/**
> + * tap_udp6_send() - Send UDP over IPv6 packet
> + * @c: Execution context
> + * @src: IPv6 source address
> + * @sport: UDP source port
> + * @dst: IPv6 destination address
> + * @dport: UDP destination port
> + * @flow: Flow label
> + * @in: UDP payload contents (not including UDP header)
> + * @len: UDP payload length (not including UDP header)
> + */
> +void tap_udp6_send(const struct ctx *c,
> + const struct in6_addr *src, in_port_t sport,
> + const struct in6_addr *dst, in_port_t dport,
> + uint32_t flow, const void *in, size_t len)
> +{
> + size_t udplen = len + sizeof(struct udphdr);
> + char buf[USHRT_MAX];
> + void *ip6h = tap_push_l2h(c, buf, ETH_P_IPV6);
> + void *uhp = tap_push_ip6h(ip6h, src, dst, udplen, IPPROTO_UDP, flow);
> + struct udphdr *uh = (struct udphdr *)uhp;
> + char *data = (char *)(uh + 1);
> +
> + uh->source = htons(sport);
> + uh->dest = htons(dport);
> + uh->len = htons(udplen);
> + csum_udp6(uh, src, dst, in, len);
> memcpy(data, in, len);
>
> - if (proto == IPPROTO_UDP) {
> - struct udphdr *uh = (struct udphdr *)(ip6h + 1);
> + if (tap_send(c, buf, len + (data - buf)) < 1)
> + debug("tap: failed to send %lu bytes (IPv6)", len);
> +}
>
> - csum_udp6(uh, &ip6h->saddr, &ip6h->daddr,
> - uh + 1, len - sizeof(*uh));
> - } else if (proto == IPPROTO_ICMPV6) {
> - struct icmp6hdr *ih = (struct icmp6hdr *)(ip6h + 1);
> +/**
> + * tap_icmp6_send() - Send ICMPv6 packet
> + * @c: Execution context
> + * @src: IPv6 source address
> + * @dst: IPv6 destination address
> + * @in: ICMP packet, including ICMP header
> + * @len: ICMP packet length, including ICMP header
> + */
> +void tap_icmp6_send(const struct ctx *c,
> + const struct in6_addr *src, const struct in6_addr *dst,
> + void *in, size_t len)
> +{
> + char buf[USHRT_MAX];
> + void *ip6h = tap_push_l2h(c, buf, ETH_P_IPV6);
> + char *data = tap_push_ip6h(ip6h, src, dst, len, IPPROTO_ICMPV6, 0);
> + struct icmp6hdr *icmp6h = (struct icmp6hdr *)data;
>
> - csum_icmp6(ih, &ip6h->saddr, &ip6h->daddr,
> - ih + 1, len - sizeof(*ih));
> - }
> + memcpy(data, in, len);
> + csum_icmp6(icmp6h, src, dst, icmp6h + 1, len - sizeof(*icmp6h));
>
> if (tap_send(c, buf, len + (data - buf)) < 1)
> debug("tap: failed to send %lu bytes (IPv6)", len);
> diff --git a/tap.h b/tap.h
> index 011ba8e..d43c7a0 100644
> --- a/tap.h
> +++ b/tap.h
> @@ -11,8 +11,13 @@ const struct in6_addr *tap_ip6_daddr(const struct ctx *c,
> const struct in6_addr *src);
> void tap_ip4_send(const struct ctx *c, in_addr_t src, uint8_t proto,
> const char *in, size_t len);
> -void tap_ip6_send(const struct ctx *c, const struct in6_addr *src,
> - uint8_t proto, const char *in, size_t len, uint32_t flow);
> +void tap_udp6_send(const struct ctx *c,
> + const struct in6_addr *src, in_port_t sport,
> + const struct in6_addr *dst, in_port_t dport,
> + uint32_t flow, const void *in, size_t len);
> +void tap_icmp6_send(const struct ctx *c,
> + const struct in6_addr *src, const struct in6_addr *dst,
> + void *in, size_t len);
> int tap_send(const struct ctx *c, const void *data, size_t len);
> void tap_handler(struct ctx *c, int fd, uint32_t events,
> const struct timespec *now);
--
Stefano
next prev parent reply other threads:[~2025-10-10 8:40 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-19 0:43 [PATCH v2 00/14] Clean up checksum and header generation for inbound packets David Gibson
2022-10-19 0:43 ` [PATCH v2 01/14] Add csum_icmp6() helper for calculating ICMPv6 checksums David Gibson
2022-10-19 0:43 ` [PATCH v2 02/14] Add csum_icmp4() helper for calculating ICMP checksums David Gibson
2022-10-19 0:43 ` [PATCH v2 03/14] Add csum_udp6() helper for calculating UDP over IPv6 checksums David Gibson
2022-10-19 0:43 ` [PATCH v2 04/14] Add csum_udp4() helper for calculating UDP over IPv4 checksums David Gibson
2022-10-19 0:43 ` [PATCH v2 05/14] Add csum_ip4_header() helper to calculate IPv4 header checksums David Gibson
2022-10-19 0:43 ` [PATCH v2 06/14] Add helpers for normal inbound packet destination addresses David Gibson
2022-10-19 0:43 ` [PATCH v2 07/14] Remove support for TCP packets from tap_ip_send() David Gibson
2022-10-19 0:43 ` [PATCH v2 08/14] tap: Remove unhelpeful vnet_pre optimization from tap_send() David Gibson
2022-10-19 0:43 ` [PATCH v2 09/14] Split tap_ip_send() into IPv4 and IPv6 specific functions David Gibson
2022-10-19 0:43 ` [PATCH v2 10/14] tap: Split tap_ip6_send() into UDP and ICMP variants David Gibson
2025-10-10 8:40 ` Stefano Brivio [this message]
2022-10-19 0:43 ` [PATCH v2 11/14] ndp: Remove unneeded eh_source parameter David Gibson
2022-10-19 0:43 ` [PATCH v2 12/14] ndp: Use tap_icmp6_send() helper David Gibson
2022-10-19 0:43 ` [PATCH v2 13/14] tap: Split tap_ip4_send() into UDP and ICMP variants David Gibson
2022-10-19 0:43 ` [PATCH v2 14/14] dhcp: Use tap_udp4_send() helper in dhcp() David Gibson
2022-10-19 9:07 ` [PATCH v2 00/14] Clean up checksum and header generation for inbound packets Stefano Brivio
2022-10-22 8:21 ` Stefano Brivio
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=20251010104000.2bcbc351@elisabeth \
--to=sbrivio@redhat.com \
--cc=david@gibson.dropbear.id.au \
--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).