All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Dumazet <edumazet@kernel.org>
To: "David S . Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	netdev@vger.kernel.org
Cc: "Willem de Bruijn" <willemb@google.com>,
	"Simon Horman" <horms@kernel.org>,
	edumazet@kernel.org, "Michael S. Tsirkin" <mst@redhat.com>,
	"Jason Wang" <jasowangio@gmail.com>,
	"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
	"Eugenio Pérez" <eperezma@redhat.com>,
	"Hassan Sultan" <hassansultan@google.com>,
	virtualization@lists.linux.dev, Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH net v6 1/3] net: virtio: fix UDP tunnel GSO header of VLAN tagged packets
Date: Tue, 10 Nov 2026 22:36:26 +0100	[thread overview]
Message-ID: <20261110213628.3476051-2-edumazet@kernel.org> (raw)
In-Reply-To: <20261110213628.3476051-1-edumazet@kernel.org>

virtio_net_hdr_tnl_from_skb() builds a wrong header for VLAN tagged UDP
tunnel GSO packets.

1) When the skb carries a hwaccel VLAN tag, tun_put_user() inserts the
   802.1Q header in the frame it copies to user space or vhost-net, and
   passes vlan_hlen = VLAN_HLEN. virtio_net_hdr_from_skb() adds
   vlan_hlen to csum_start, but inner_nh_offset and outer_th_offset do
   not account for it, and are 4 bytes short of the real inner L3 and
   outer UDP headers in the emitted frame.

   tun advertises NETIF_F_HW_VLAN_CTAG_TX and NETIF_F_HW_VLAN_STAG_TX
   in hw_enc_features, and its vlan_features keep the UDP tunnel GSO
   features, so this happens for example with a VLAN filtering bridge
   with a tagged port, or with a vlan device on top of a tap.

2) The outer family comes from skb->protocol, which is ETH_P_8021Q or
   ETH_P_8021AD when the VLAN tag is in the packet data, so a packet
   with an outer IPv6 header is reported as
   VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4. This happens when
   __vlan_hwaccel_push_inside() inserted the tag because the device does
   not offload it: virtio_net never offloads VLAN insertion but keeps
   UDP tunnel GSO in its vlan_features, and tun does the same with VLAN
   TX offload disabled, or with QinQ (outer tag offloaded, inner tag in
   the data).

The receiver sets inner_network_header and transport_header from these
offsets, and checks them with the wrong outer family. A forwarded
packet that gets segmented again uses the wrong inner headers, and a
receiver checking the outer headers against the virtio header drops
the packet.

Add vlan_hlen to both offsets like csum_start, and take the outer
family from vlan_get_protocol(), which skips VLAN tags in the data.

Fixes: a2fb4bc4e2a6 ("net: implement virtio helpers to handle UDP GSO tunneling.")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/netdev/179421814766.994134.3669228181251158303@kernel.org/
Closes: https://lore.kernel.org/netdev/179433950084.994134.15100186606737698605@kernel.org/
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
---
 include/linux/virtio_net.h | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index d6466f96cdd0..83f801ff5700 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -453,7 +453,10 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
 	if (feature_hdrlen && hdr->hdr_len)
 		__virtio_net_set_tnl_hdrlen(skb, hdr);
 
-	if (skb->protocol == htons(ETH_P_IPV6))
+	/* skb->protocol is the VLAN protocol when the tag is in the
+	 * packet data.
+	 */
+	if (vlan_get_protocol(skb) == htons(ETH_P_IPV6))
 		hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6;
 	else
 		hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4;
@@ -461,8 +464,11 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
 	if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)
 		hdr->flags |= VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM;
 
-	inner_nh = skb->inner_network_header - skb_headroom(skb);
-	outer_th = skb->transport_header - skb_headroom(skb);
+	/* Like csum_start, the offsets must account for a VLAN tag
+	 * the caller inserts in the frame.
+	 */
+	inner_nh = skb->inner_network_header - skb_headroom(skb) + vlan_hlen;
+	outer_th = skb->transport_header - skb_headroom(skb) + vlan_hlen;
 	vhdr->inner_nh_offset = cpu_to_le16(inner_nh);
 	vhdr->outer_th_offset = cpu_to_le16(outer_th);
 	return 0;
-- 
2.53.0


  reply	other threads:[~2026-11-10 21:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 21:36 [PATCH net v6 0/3] net: virtio: validate outer protocol of UDP tunnel GSO packets Eric Dumazet
2026-11-10 21:36 ` Eric Dumazet [this message]
2026-11-10 21:36 ` [PATCH net v6 2/3] tun: clear stale skb->protocol of NAPI frags skbs Eric Dumazet
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 21:36 ` [PATCH net v6 3/3] net: virtio: validate outer protocol of UDP tunnel GSO packets Eric Dumazet
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-12  9:46     ` Eric Dumazet
2026-11-12 18:50 ` [PATCH net v6 0/3] " 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=20261110213628.3476051-2-edumazet@kernel.org \
    --to=edumazet@kernel.org \
    --cc=davem@davemloft.net \
    --cc=eperezma@redhat.com \
    --cc=hassansultan@google.com \
    --cc=horms@kernel.org \
    --cc=jasowangio@gmail.com \
    --cc=kuba@kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sashiko-bot@kernel.org \
    --cc=virtualization@lists.linux.dev \
    --cc=willemb@google.com \
    --cc=xuanzhuo@linux.alibaba.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.