From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: Eric Dumazet <edumazet@kernel.org>,
"David S . Miller" <davem@davemloft.net>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
Willem de Bruijn <willemb@google.com>
Cc: "Michael S . Tsirkin" <mst@redhat.com>,
Simon Horman <horms@kernel.org>,
netdev@vger.kernel.org, edumazet@google.com,
Eric Dumazet <edumazet@kernel.org>
Subject: Re: [PATCH v3 net 3/3] selftests: net: tun: add test for VLAN-tagged GSO without NEEDS_CSUM
Date: Thu, 01 Oct 2026 19:37:15 -0400 [thread overview]
Message-ID: <willemdebruijn.kernel.e759da52def9@gmail.com> (raw)
In-Reply-To: <20261001191140.2818991-4-edumazet@kernel.org>
Eric Dumazet wrote:
> Add selftests in tun.c verifying that a VLAN-tagged (802.1Q) TCPv4 GSO
> packet without VIRTIO_NET_HDR_F_NEEDS_CSUM (both flags = 0 and
> flags = VIRTIO_NET_HDR_F_DATA_VALID) is accepted when written to a TAP
> device (/dev/net/tun with IFF_TAP | IFF_NO_PI | IFF_VNET_HDR).
>
> Also verify that the following are rejected with -EINVAL:
> - a mismatched GSO type (VIRTIO_NET_HDR_GSO_TCPV6 on a VLAN-tagged IPv4
> packet).
> - a frame whose TCP header is truncated after 10 bytes. Pulling only
> sizeof(struct iphdr) + sizeof(struct tcphdr) bytes would accept it,
> so this requires the transport offset found by flow dissection.
>
> Finally, verify that a 65540-byte frame is accepted. Its skb->len is
> above U16_MAX while it is flow-dissected, before eth_type_trans() pulls
> the Ethernet header.
>
> Based on a reproducer by Michael S. Tsirkin <mst@redhat.com>.
>
> Assisted-by: LLM
> Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
> ---
> tools/testing/selftests/net/tun.c | 136 ++++++++++++++++++++++++++++++
> 1 file changed, 136 insertions(+)
>
> diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c
> index abe488bac50bb3b05df5c446836c1c3dfa9ea604..afaa81c9bac5311944c9a70a20de05bffb683f26 100644
> --- a/tools/testing/selftests/net/tun.c
> +++ b/tools/testing/selftests/net/tun.c
> @@ -9,6 +9,7 @@
> #include <string.h>
> #include <unistd.h>
> #include <linux/if_tun.h>
> +#include <netinet/tcp.h>
> #include <sys/ioctl.h>
> #include <sys/socket.h>
>
> @@ -542,6 +543,141 @@ TEST_F(tun, reattach_close_delete)
> EXPECT_EQ(tun_delete(self->ifname), 0);
> }
>
> +FIXTURE(tun_vnet_gso)
> +{
> + char ifname[IFNAMSIZ];
> + int fd;
> +};
> +
> +FIXTURE_SETUP(tun_vnet_gso)
> +{
> + int flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
> +
> + memset(self->ifname, 0, sizeof(self->ifname));
> + self->fd = tun_open(self->ifname, flags, 0, 0, NULL);
> + ASSERT_GE(self->fd, 0);
> +}
> +
> +FIXTURE_TEARDOWN(tun_vnet_gso)
> +{
> + if (self->fd >= 0)
> + close(self->fd);
> +}
> +
> +static int build_vlan_tcpv4_gso_packet(uint8_t *buf, int payload_len)
> +{
> + uint16_t vlan_tag[2] = { htons(100), htons(ETH_P_IP) };
> + uint8_t *cur = buf + sizeof(struct virtio_net_hdr);
> + struct virtio_net_hdr vh = { 0 };
> + struct tcphdr tcph = { 0 };
> + uint32_t sum;
> +
> + cur += build_eth(cur, ETH_P_8021Q, param_hwaddr_outer_src,
> + param_hwaddr_outer_dst);
> +
> + /* 802.1Q tag: VID=100, inner protocol=ETH_P_IP */
> + memcpy(cur, vlan_tag, sizeof(vlan_tag));
> + cur += sizeof(vlan_tag);
> +
> + cur += build_ipv4_header(cur, IPPROTO_TCP,
> + sizeof(tcph) + payload_len,
> + ¶m_ipaddr4_outer_src,
> + ¶m_ipaddr4_outer_dst);
> +
> + tcph.source = htons(12345);
> + tcph.dest = htons(80);
> + tcph.seq = htonl(1);
> + tcph.doff = sizeof(tcph) / 4;
> + tcph.ack = 1;
> + tcph.window = htons(65535);
> + memcpy(cur, &tcph, sizeof(tcph));
> + memset(cur + sizeof(tcph), PKT_DATA, payload_len);
> +
> + sum = add_csum((const uint8_t *)¶m_ipaddr4_outer_src,
> + sizeof(param_ipaddr4_outer_src));
> + sum += add_csum((const uint8_t *)¶m_ipaddr4_outer_dst,
> + sizeof(param_ipaddr4_outer_dst));
> + sum += htons(IPPROTO_TCP) + htons(sizeof(tcph) + payload_len);
> + sum += add_csum(cur, sizeof(tcph) + payload_len);
> + tcph.check = finish_ip_csum(sum);
> + memcpy(cur, &tcph, sizeof(tcph));
> + cur += sizeof(tcph) + payload_len;
> +
> + vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> + vh.gso_size = 1400;
> + vh.hdr_len = (cur - buf) - sizeof(vh) - payload_len;
> + memcpy(buf, &vh, sizeof(vh));
> +
> + return cur - buf;
> +}
> +
> +TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum)
> +{
> + struct virtio_net_hdr vh;
> + uint8_t pkt[4096] = { 0 };
> + int len, ret;
> +
> + len = build_vlan_tcpv4_gso_packet(pkt, 2800);
> + memcpy(&vh, pkt, sizeof(vh));
> +
> + /* Valid VLAN-tagged TCPv4 GSO with flags = 0 (no NEEDS_CSUM) */
iff respinning and not relevant for this fix, which targets the
!VIRTIO_NET_HDR_F_NEEDS_CSUM branch.
But would it be worthwhile to also run this test with
VIRTIO_NET_HDR_F_NEEDS_CSUM? Adds coverage of the other branch.
> + vh.flags = 0;
> + memcpy(pkt, &vh, sizeof(vh));
> + ret = write(self->fd, pkt, len);
> + ASSERT_EQ(ret, len);
> +
> + /* Valid VLAN-tagged TCPv4 GSO with flags = DATA_VALID */
> + vh.flags = VIRTIO_NET_HDR_F_DATA_VALID;
> + memcpy(pkt, &vh, sizeof(vh));
> + ret = write(self->fd, pkt, len);
> + ASSERT_EQ(ret, len);
> +
> + /* Mismatched GSO type (TCPV6 on VLAN-tagged IPv4 packet) */
> + vh.flags = 0;
> + vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> + memcpy(pkt, &vh, sizeof(vh));
> + ret = write(self->fd, pkt, len);
> + ASSERT_EQ(ret, -1);
> + ASSERT_EQ(errno, EINVAL);
> +
> + /* TCP header truncated after 10 bytes, without NEEDS_CSUM.
> + * Requires the transport header offset found by flow dissection:
> + * pulling only sizeof(struct iphdr) + sizeof(struct tcphdr) bytes
> + * from the mac header would accept this frame.
> + */
> + vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> + vh.hdr_len = ETH_HLEN + 4 + sizeof(struct iphdr) + 10;
> + memcpy(pkt, &vh, sizeof(vh));
> + ret = write(self->fd, pkt, sizeof(vh) + vh.hdr_len);
> + ASSERT_EQ(ret, -1);
> + ASSERT_EQ(errno, EINVAL);
> +}
> +
> +TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum_64k)
> +{
> + /* Ethernet frame of 65540 bytes: skb->len is above U16_MAX when the
> + * frame is flow-dissected, before eth_type_trans() pulls ETH_HLEN.
> + */
> + const int payload_len = 65540 - ETH_HLEN - 4 -
> + sizeof(struct iphdr) - sizeof(struct tcphdr);
> + struct virtio_net_hdr vh;
> + uint8_t *pkt;
> + int len, ret;
> +
> + pkt = calloc(1, sizeof(vh) + 65540);
> + ASSERT_NE(pkt, NULL);
> +
> + len = build_vlan_tcpv4_gso_packet(pkt, payload_len);
> + ASSERT_EQ(len, sizeof(vh) + 65540);
> + memcpy(&vh, pkt, sizeof(vh));
> +
> + vh.flags = 0;
> + memcpy(pkt, &vh, sizeof(vh));
> + ret = write(self->fd, pkt, len);
> + free(pkt);
> + ASSERT_EQ(ret, len);
> +}
> +
> FIXTURE(tun_vnet_udptnl)
> {
> char ifname[IFNAMSIZ];
> --
> 2.56.0.rc1.315.gc6ed9934b7-goog
>
next prev parent reply other threads:[~2026-10-01 23:37 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 19:11 [PATCH v3 net 0/3] net: always dissect GSO packets in __virtio_net_hdr_to_skb() Eric Dumazet
2026-10-01 19:11 ` [PATCH v3 net 1/3] flow_dissector: avoid u16 truncation of skb->len when computing thoff Eric Dumazet
2026-10-01 23:30 ` Willem de Bruijn
2026-10-05 15:30 ` netdev-bot+sashiko
2026-10-05 19:38 ` Eric Dumazet
2026-10-01 19:11 ` [PATCH v3 net 2/3] net: always dissect GSO packets in __virtio_net_hdr_to_skb() Eric Dumazet
2026-10-01 19:11 ` [PATCH v3 net 3/3] selftests: net: tun: add test for VLAN-tagged GSO without NEEDS_CSUM Eric Dumazet
2026-10-01 23:37 ` Willem de Bruijn [this message]
2026-10-06 22:37 ` [PATCH v3 net 0/3] net: always dissect GSO packets in __virtio_net_hdr_to_skb() Michael S. Tsirkin
2026-10-06 23:26 ` Willem de Bruijn
2026-10-06 23:49 ` Michael S. Tsirkin
2026-10-07 0:13 ` Willem de Bruijn
2026-10-07 0:18 ` Michael S. Tsirkin
2026-10-07 0:30 ` Willem de Bruijn
2026-10-07 8:04 ` Michael S. Tsirkin
2026-10-07 14:21 ` Willem de Bruijn
2026-10-06 23:00 ` patchwork-bot+netdevbpf
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=willemdebruijn.kernel.e759da52def9@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=willemb@google.com \
/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.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.