From: Bryon Fryer <bryon@fryer.io>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, edumazet@kernel.org, horms@kernel.org,
jasowangio@gmail.com, kuba@kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
pabeni@redhat.com, shuah@kernel.org, stable@vger.kernel.org
Subject: [PATCH net 1/2] udp: restore outer transport header after tunnel GRO
Date: Wed, 11 Nov 2026 22:07:07 -0500 [thread overview]
Message-ID: <20261112030708.1915665-2-bryon@fryer.io> (raw)
In-Reply-To: <20261112030708.1915665-1-bryon@fryer.io>
UDP tunnel GRO can produce invalid virtio tunnel headers, causing
virtio-net to drop whole aggregates. Losing several TCP segments at
once causes retransmissions and can collapse throughput.
Observed as slow VXLAN TCP traffic with kernel logs reporting dropped
packets. Reproduced with ordinary tunnel traffic in disposable VMs. The
unpatched reproductions required no kernel modifications or error
injection.
Inner GRO processing moves skb->transport_header to inner TCP or
UDP. The inner completion callback saves it in inner_transport_header,
but udp_gro_complete() leaves the main transport header there too.
The virtio tunnel exporter added by commit a2fb4bc4e2a6 ("net: implement
virtio helpers to handle UDP GSO tunneling.") treats that field as the
outer UDP location. The exported outer header then appears after
the inner network header, so the receiver rejects the descriptor.
Restore skb->transport_header from nhoff after successful inner
completion. This parsed outer UDP offset retains the inner transport
and checksum offsets without assuming fixed header lengths.
Tested under virtme-ng with socat sending bulk TCP over IPv4 VXLAN
and Geneve between network namespaces. A raw sender TAP supplies
wire-sized packets to a TAP/bridge path with ingress GRO. Exported
virtio headers are relayed unchanged to a receiving TAP using the
shared virtio decoder. Kernels used the same base, config and toolchain
under KVM. For 32 MiB, median transfer times and rejected aggregates
across three paired runs were:
Before patch After patch
VXLAN, GRO on 69.8s, 1418 rejects 0.15s, 0 rejects
Geneve, GRO on 70.8s, 1414 rejects 0.16s, 0 rejects
VXLAN, GRO off 0.22s, 0 rejects 0.23s, 0 rejects
Geneve, GRO off 0.23s, 0 rejects 0.21s, 0 rejects
Rejections are receiving TAP writes returning -EINVAL. Median TCP
retransmissions fell from 2852 (VXLAN) and 2854 (Geneve) to zero.
Every transfer verified all payload bytes; no TAP queue drops occurred.
Separate eight-packet tests measured these outer UDP offsets, in
bytes from the Ethernet frame start:
TAP-exported outer_th_offset
Actual UDP Before patch After patch
VXLAN over IPv4 34 84 34
VXLAN-GPE over IPv4 34 70 34
Geneve over IPv4 34 84 34
The inner network and checksum-start offsets were unchanged. The
accompanying TUN regression fails only its outer-offset assertion
before patching and passes afterward. Selected existing TUN and UDP
GSO selftests also passed before and after patching.
VXLAN-GPE raw-TAP/GRO-on software segmentation still returns -EINVAL
before and after this patch. This is a separate issue.
Fixes: a2fb4bc4e2a6 ("net: implement virtio helpers to handle UDP GSO tunneling.")
Cc: stable@vger.kernel.org
Signed-off-by: Bryon Fryer <bryon@fryer.io>
---
net/ipv4/udp_offload.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index b77ae2f00c..1a1d1a125d 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -948,6 +948,8 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
skb->encapsulation = 1;
err = udp_sk(sk)->gro_complete(sk, skb,
nhoff + sizeof(struct udphdr));
+ if (!err)
+ skb_set_transport_header(skb, nhoff);
} else {
err = udp_gro_complete_segment(skb);
}
--
2.47.3
next prev parent reply other threads:[~2026-11-12 3:07 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 3:07 [PATCH net 0/2] udp: preserve " Bryon Fryer
2026-11-12 3:07 ` Bryon Fryer [this message]
2026-11-12 3:07 ` [PATCH net 2/2] selftests: net: check UDP tunnel GRO virtio offsets Bryon Fryer
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=20261112030708.1915665-2-bryon@fryer.io \
--to=bryon@fryer.io \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=jasowangio@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=shuah@kernel.org \
--cc=stable@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®