* [PATCH net v4 0/4] ipmr: forward GSO multicast packets
@ 2026-11-01 16:42 Julius Bairaktaris
2026-11-01 16:42 ` [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list() Julius Bairaktaris
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Julius Bairaktaris @ 2026-11-01 16:42 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
With fraglist GRO or UDP GRO forwarding on, a routed IPv4 multicast
stream arrives as GSO packets. ipmr_prepare_xmit() drops every DF
aggregate larger than the MTU, and ip_encap() sets no tunnel GSO state,
so a GSO packet sent to a VIFF_TUNNEL vif is dropped during
segmentation. With that state set, a fraglist aggregate reaches
skb_segment_list() with tunnel headers, which can write before the head
of a frag_list member; this also happens today when such a packet is
routed into a tunnel device. Checking the segment length instead of
skb->len relies on skb_gso_transport_seglen(), which counts the inner
UDP header of an encapsulated UDP GSO packet 8 bytes short.
Patch 1 makes room for the tunnel headers in skb_segment_list().
Patch 2 counts the inner UDP header of encapsulated UDP GSO packets.
Patch 3 sets up IPXIP4 GSO state, outer IP IDs and length in ip_encap().
Patch 4 lets DF GSO packets pass when their segments fit the MTU.
Tested in QEMU (KASAN) on veth, one run per arm: an MFC entry to a plain
vif and a tunnel vif, 40 x 1316-byte datagrams per GSO packet, 4000
datagrams per arm, UDP_SEGMENT, fraglist GRO and UDP GRO forwarding, DF
set and clear, software and device segmentation on egress:
- net (7076f684d513): every DF aggregate dropped on both vifs (FragFails
2 per aggregate), and with software segmentation nothing arrives over
the tunnel vif; fraglist GRO routed into VXLAN reports a KASAN
slab-out-of-bounds write in skb_segment_list(), then panics.
- this series, all 12 arms: 4000 of 4000 datagrams on the plain vif,
FragFails 0; on the tunnel vif 4000 of 4000 IPIP packets with unique
outer IDs with software segmentation, and the 100 GSO packets of 52688
bytes whole with device segmentation.
- VXLAN with DF, 1404-byte outer segments, route MTU 1400: net and this
series without patch 2 forward all 1000 segments at 1404 bytes through
ip_forward(), and the series without patch 2 also through the MFC
entry; with patch 2 none leave and FragFails counts them.
- a GRE GSO packet (skb->encapsulation set) multicast-routed to both
vifs: all 1000 segments on the plain vif, none on the tunnel vif.
- fraglist GRO routed into VXLAN and IPIP with software segmentation:
every segment reaches the peer, no KASAN report.
Changes in v4:
- Add patch 2 (Sashiko).
- Patch 3: drop GSO packets that are already encapsulated, and set the
outer length with iph_set_totlen() (Sashiko).
- Drop v3 patch 2 (TCP fixed-ID flag on encapsulation): multicast
routing does not carry TCP, and the flag also needs the decap and
GRE/UDP segmentation paths, which go to a separate series (Sashiko).
- Rebase onto net.
- v3: https://lore.kernel.org/netdev/cover.1792293419.git.julius@bairaktaris.de/
Changes in v3:
- Patch 1: name the VXLAN out-of-bounds write (Sashiko).
- Add patch 2 (Sashiko).
- Patch 3: reserve one outer IP ID per segment (Sashiko).
- v2: https://lore.kernel.org/netdev/20261011162957.1328474-1-julius@bairaktaris.de/
Changes in v2:
- Add patches 1 and 3; v1 let DF GSO packets reach ip_encap() on tunnel
vifs, where they were dropped during segmentation (Sashiko).
- Keep the additive MTU comparison and check mtu > encap before
subtracting, so a route MTU below 20 cannot wrap (Sashiko).
- v1: https://lore.kernel.org/netdev/20261010131842.2157365-1-julius@bairaktaris.de/
I used Claude (Anthropic) to help write these patches.
Julius Bairaktaris (4):
net: make room for the tunnel header in skb_segment_list()
net: gso: count the inner UDP header of encapsulated UDP GSO packets
ipmr: set up GSO state for tunnel vifs
ipmr: do not drop GSO packets that fit the MTU after segmentation
net/core/gso.c | 2 ++
net/core/skbuff.c | 4 ++++
net/ipv4/ipmr.c | 29 ++++++++++++++++++++++-------
3 files changed, 28 insertions(+), 7 deletions(-)
base-commit: 7076f684d5132e6a6145e1da2fa74771ecd052e5
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list()
2026-11-01 16:42 [PATCH net v4 0/4] ipmr: forward GSO multicast packets Julius Bairaktaris
@ 2026-11-01 16:42 ` Julius Bairaktaris
2026-11-03 12:43 ` Simon Horman
2026-11-01 16:42 ` [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets Julius Bairaktaris
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Julius Bairaktaris @ 2026-11-01 16:42 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
skb_segment_list() pushes each frag_list member back to the outer MAC
header and copies the tunnel headers in front of it, but never checks
that the member has the headroom. A fraglist GRO packet forwarded into
a tunnel and segmented in software then hits skb_under_panic() on IPIP,
and on VXLAN the copy writes before the member's head (KASAN:
slab-out-of-bounds write in skb_segment_list()).
Call skb_cow_head() on each member before pushing it.
Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.")
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
---
net/core/skbuff.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 48f6764117243..48291a2d21241 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4777,6 +4777,10 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
}
}
+ if (!err)
+ err = skb_cow_head(nskb, offset + tnl_hlen -
+ skb_network_offset(nskb));
+
if (!tail)
skb->next = nskb;
else
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets
2026-11-01 16:42 [PATCH net v4 0/4] ipmr: forward GSO multicast packets Julius Bairaktaris
2026-11-01 16:42 ` [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list() Julius Bairaktaris
@ 2026-11-01 16:42 ` Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
2026-11-01 16:42 ` [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs Julius Bairaktaris
2026-11-01 16:42 ` [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation Julius Bairaktaris
3 siblings, 1 reply; 13+ messages in thread
From: Julius Bairaktaris @ 2026-11-01 16:42 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
skb_gso_transport_seglen() adds the inner TCP header length for an
encapsulated GSO packet, but not the inner UDP header for
SKB_GSO_UDP_L4, whose gso_size covers the payload only. Every segment
of a UDP GSO packet in a UDP tunnel, built by UDP GRO behind a tunnel
socket or sent with UDP_SEGMENT over VXLAN, is counted 8 bytes short.
ip_forward() and ip_finish_output_gso() then let DF segments that
exceed the MTU by up to 8 bytes leave unfragmented.
Add the inner UDP header as the unencapsulated branch does.
Fixes: ee80d1ebe5ba ("udp: add udp gso")
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
---
net/core/gso.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/gso.c b/net/core/gso.c
index b5bd269e56e4e..eb95c9d2819b1 100644
--- a/net/core/gso.c
+++ b/net/core/gso.c
@@ -156,6 +156,8 @@ static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
thlen += inner_tcp_hdrlen(skb);
+ else if (shinfo->gso_type & SKB_GSO_UDP_L4)
+ thlen += sizeof(struct udphdr);
} else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
thlen = tcp_hdrlen(skb);
} else if (unlikely(skb_is_gso_sctp(skb))) {
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs
2026-11-01 16:42 [PATCH net v4 0/4] ipmr: forward GSO multicast packets Julius Bairaktaris
2026-11-01 16:42 ` [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list() Julius Bairaktaris
2026-11-01 16:42 ` [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets Julius Bairaktaris
@ 2026-11-01 16:42 ` Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
2026-11-03 13:13 ` Eric Dumazet
2026-11-01 16:42 ` [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation Julius Bairaktaris
3 siblings, 2 replies; 13+ messages in thread
From: Julius Bairaktaris @ 2026-11-01 16:42 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
ip_encap() pushes the outer IPv4 header but does not set SKB_GSO_IPXIP4,
skb->encapsulation or the inner headers. A GSO packet forwarded to a
VIFF_TUNNEL vif is then rejected by ipip_gso_segment() and dropped in
validate_xmit_skb(), after being counted as sent. A device with UDP
segmentation offload is handed a GSO packet whose transport header
points at the inner IP header.
Call iptunnel_handle_offloads() and skb_set_inner_ipproto() as
ipip_tunnel_xmit() does, reserve one outer IP ID per segment as
iptunnel_xmit() does, and set the outer length with iph_set_totlen(),
since a GSO packet plus the outer header can exceed 64 KB. A GSO packet
that GRE or UDP tunnel GRO marked as encapsulated already uses the inner
headers for its own tunnel; drop it, as segmentation did before.
Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
---
net/ipv4/ipmr.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index acacaae05cc49..98e38839f8ccb 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1849,12 +1849,21 @@ static struct notifier_block ip_mr_notifier = {
* This avoids tunnel drivers and other mess and gives us the speed so
* important for multicast video.
*/
-static void ip_encap(struct net *net, struct sk_buff *skb,
- __be32 saddr, __be32 daddr)
+static int ip_encap(struct net *net, struct sk_buff *skb,
+ __be32 saddr, __be32 daddr)
{
+ const struct iphdr *old_iph;
struct iphdr *iph;
- const struct iphdr *old_iph = ip_hdr(skb);
+ /* The inner headers can describe one tunnel only */
+ if (skb_is_gso(skb) && skb->encapsulation)
+ return -1;
+
+ if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
+ return -1;
+ skb_set_inner_ipproto(skb, IPPROTO_IPIP);
+
+ old_iph = ip_hdr(skb);
skb_push(skb, sizeof(struct iphdr));
skb->transport_header = skb->network_header;
skb_reset_network_header(skb);
@@ -1868,12 +1877,13 @@ static void ip_encap(struct net *net, struct sk_buff *skb,
iph->saddr = saddr;
iph->protocol = IPPROTO_IPIP;
iph->ihl = 5;
- iph->tot_len = htons(skb->len);
- ip_select_ident(net, skb, NULL);
+ iph_set_totlen(iph, skb->len);
+ ip_select_ident_segs(net, skb, NULL, skb_shinfo(skb)->gso_segs ?: 1);
ip_send_check(iph);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
nf_reset_ct(skb);
+ return 0;
}
static inline int ipmr_forward_finish(struct net *net, struct sock *sk,
@@ -1982,7 +1992,8 @@ static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
* What do we do with netfilter? -- RR
*/
if (vif->flags & VIFF_TUNNEL) {
- ip_encap(net, skb, vif->local, vif->remote);
+ if (ip_encap(net, skb, vif->local, vif->remote))
+ return -1;
/* FIXME: extra output firewall step used to be here. --RR */
DEV_STATS_INC(vif_dev, tx_packets);
DEV_STATS_ADD(vif_dev, tx_bytes, skb->len);
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation
2026-11-01 16:42 [PATCH net v4 0/4] ipmr: forward GSO multicast packets Julius Bairaktaris
` (2 preceding siblings ...)
2026-11-01 16:42 ` [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs Julius Bairaktaris
@ 2026-11-01 16:42 ` Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
3 siblings, 1 reply; 13+ messages in thread
From: Julius Bairaktaris @ 2026-11-01 16:42 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
ipmr_prepare_xmit() drops a packet with DF set when skb->len exceeds the
route MTU, without checking whether it is a GSO packet. A UDP multicast
stream received with fraglist GRO or UDP GRO forwarding enabled is
aggregated into GSO packets, and every aggregate is dropped with
FragFails, while ip_forward() lets the same packets pass by checking
skb_gso_validate_network_len(). Do the same for multicast routing,
leaving room for the outer header on tunnel vifs. ip6mr has no such
check and leaves GSO packets to ip6_output().
On an IPQ8074 router with fraglist GRO on, a 10 Mbit/s stream of
1316-byte DF datagrams routed by igmpproxy loses 14.5 to 15.5% (n=3)
and 0% with this change.
Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
---
net/ipv4/ipmr.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 98e38839f8ccb..1fb728fb15741 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1932,6 +1932,7 @@ static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
struct rtable *rt;
struct flowi4 fl4;
int encap = 0;
+ unsigned int mtu;
vif_dev = vif_dev_read(vif);
if (!vif_dev)
@@ -1964,7 +1965,10 @@ static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
return -1;
}
- if (skb->len+encap > dst4_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
+ mtu = dst4_mtu(&rt->dst);
+ if (skb->len + encap > mtu && (ntohs(iph->frag_off) & IP_DF) &&
+ !(skb_is_gso(skb) && mtu > encap &&
+ skb_gso_validate_network_len(skb, mtu - encap))) {
/* Do not fragment multicasts. Alas, IPv4 does not
* allow to send ICMP, so that packets will disappear
* to blackhole.
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list()
2026-11-01 16:42 ` [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list() Julius Bairaktaris
@ 2026-11-03 12:43 ` Simon Horman
2026-11-03 13:05 ` Eric Dumazet
0 siblings, 1 reply; 13+ messages in thread
From: Simon Horman @ 2026-11-03 12:43 UTC (permalink / raw)
To: Julius Bairaktaris
Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
On Sun, Nov 01, 2026 at 05:42:29PM +0100, Julius Bairaktaris wrote:
> skb_segment_list() pushes each frag_list member back to the outer MAC
> header and copies the tunnel headers in front of it, but never checks
> that the member has the headroom. A fraglist GRO packet forwarded into
> a tunnel and segmented in software then hits skb_under_panic() on IPIP,
> and on VXLAN the copy writes before the member's head (KASAN:
> slab-out-of-bounds write in skb_segment_list()).
>
> Call skb_cow_head() on each member before pushing it.
>
> Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.")
> Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets
2026-11-01 16:42 ` [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets Julius Bairaktaris
@ 2026-11-03 12:44 ` Simon Horman
2026-11-03 13:08 ` Eric Dumazet
0 siblings, 1 reply; 13+ messages in thread
From: Simon Horman @ 2026-11-03 12:44 UTC (permalink / raw)
To: Julius Bairaktaris
Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
On Sun, Nov 01, 2026 at 05:42:30PM +0100, Julius Bairaktaris wrote:
> skb_gso_transport_seglen() adds the inner TCP header length for an
> encapsulated GSO packet, but not the inner UDP header for
> SKB_GSO_UDP_L4, whose gso_size covers the payload only. Every segment
> of a UDP GSO packet in a UDP tunnel, built by UDP GRO behind a tunnel
> socket or sent with UDP_SEGMENT over VXLAN, is counted 8 bytes short.
> ip_forward() and ip_finish_output_gso() then let DF segments that
> exceed the MTU by up to 8 bytes leave unfragmented.
>
> Add the inner UDP header as the unencapsulated branch does.
>
> Fixes: ee80d1ebe5ba ("udp: add udp gso")
> Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs
2026-11-01 16:42 ` [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs Julius Bairaktaris
@ 2026-11-03 12:44 ` Simon Horman
2026-11-03 13:13 ` Eric Dumazet
1 sibling, 0 replies; 13+ messages in thread
From: Simon Horman @ 2026-11-03 12:44 UTC (permalink / raw)
To: Julius Bairaktaris
Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
On Sun, Nov 01, 2026 at 05:42:31PM +0100, Julius Bairaktaris wrote:
> ip_encap() pushes the outer IPv4 header but does not set SKB_GSO_IPXIP4,
> skb->encapsulation or the inner headers. A GSO packet forwarded to a
> VIFF_TUNNEL vif is then rejected by ipip_gso_segment() and dropped in
> validate_xmit_skb(), after being counted as sent. A device with UDP
> segmentation offload is handed a GSO packet whose transport header
> points at the inner IP header.
>
> Call iptunnel_handle_offloads() and skb_set_inner_ipproto() as
> ipip_tunnel_xmit() does, reserve one outer IP ID per segment as
> iptunnel_xmit() does, and set the outer length with iph_set_totlen(),
> since a GSO packet plus the outer header can exceed 64 KB. A GSO packet
> that GRE or UDP tunnel GRO marked as encapsulated already uses the inner
> headers for its own tunnel; drop it, as segmentation did before.
>
> Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
> Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation
2026-11-01 16:42 ` [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation Julius Bairaktaris
@ 2026-11-03 12:44 ` Simon Horman
2026-11-03 13:15 ` Eric Dumazet
0 siblings, 1 reply; 13+ messages in thread
From: Simon Horman @ 2026-11-03 12:44 UTC (permalink / raw)
To: Julius Bairaktaris
Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
On Sun, Nov 01, 2026 at 05:42:32PM +0100, Julius Bairaktaris wrote:
> ipmr_prepare_xmit() drops a packet with DF set when skb->len exceeds the
> route MTU, without checking whether it is a GSO packet. A UDP multicast
> stream received with fraglist GRO or UDP GRO forwarding enabled is
> aggregated into GSO packets, and every aggregate is dropped with
> FragFails, while ip_forward() lets the same packets pass by checking
> skb_gso_validate_network_len(). Do the same for multicast routing,
> leaving room for the outer header on tunnel vifs. ip6mr has no such
> check and leaves GSO packets to ip6_output().
>
> On an IPQ8074 router with fraglist GRO on, a 10 Mbit/s stream of
> 1316-byte DF datagrams routed by igmpproxy loses 14.5 to 15.5% (n=3)
> and 0% with this change.
>
> Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
> Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list()
2026-11-03 12:43 ` Simon Horman
@ 2026-11-03 13:05 ` Eric Dumazet
0 siblings, 0 replies; 13+ messages in thread
From: Eric Dumazet @ 2026-11-03 13:05 UTC (permalink / raw)
To: Simon Horman
Cc: Julius Bairaktaris, netdev, dsahern, idosch, davem, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
Le mar. 3 nov. 2026 à 13:43, Simon Horman <horms@kernel.org> a écrit :
>
> On Sun, Nov 01, 2026 at 05:42:29PM +0100, Julius Bairaktaris wrote:
> > skb_segment_list() pushes each frag_list member back to the outer MAC
> > header and copies the tunnel headers in front of it, but never checks
> > that the member has the headroom. A fraglist GRO packet forwarded into
> > a tunnel and segmented in software then hits skb_under_panic() on IPIP,
> > and on VXLAN the copy writes before the member's head (KASAN:
> > slab-out-of-bounds write in skb_segment_list()).
> >
> > Call skb_cow_head() on each member before pushing it.
> >
> > Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.")
> > Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
>
> Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Thanks!
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets
2026-11-03 12:44 ` Simon Horman
@ 2026-11-03 13:08 ` Eric Dumazet
0 siblings, 0 replies; 13+ messages in thread
From: Eric Dumazet @ 2026-11-03 13:08 UTC (permalink / raw)
To: Simon Horman
Cc: Julius Bairaktaris, netdev, dsahern, idosch, davem, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
Le mar. 3 nov. 2026 à 13:44, Simon Horman <horms@kernel.org> a écrit :
>
> On Sun, Nov 01, 2026 at 05:42:30PM +0100, Julius Bairaktaris wrote:
> > skb_gso_transport_seglen() adds the inner TCP header length for an
> > encapsulated GSO packet, but not the inner UDP header for
> > SKB_GSO_UDP_L4, whose gso_size covers the payload only. Every segment
> > of a UDP GSO packet in a UDP tunnel, built by UDP GRO behind a tunnel
> > socket or sent with UDP_SEGMENT over VXLAN, is counted 8 bytes short.
> > ip_forward() and ip_finish_output_gso() then let DF segments that
> > exceed the MTU by up to 8 bytes leave unfragmented.
> >
> > Add the inner UDP header as the unencapsulated branch does.
> >
> > Fixes: ee80d1ebe5ba ("udp: add udp gso")
> > Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
>
> Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs
2026-11-01 16:42 ` [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
@ 2026-11-03 13:13 ` Eric Dumazet
1 sibling, 0 replies; 13+ messages in thread
From: Eric Dumazet @ 2026-11-03 13:13 UTC (permalink / raw)
To: Julius Bairaktaris
Cc: netdev, dsahern, idosch, davem, kuba, pabeni, horms,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
Le dim. 1 nov. 2026 à 17:42, Julius Bairaktaris
<julius@bairaktaris.de> a écrit :
>
> ip_encap() pushes the outer IPv4 header but does not set SKB_GSO_IPXIP4,
> skb->encapsulation or the inner headers. A GSO packet forwarded to a
> VIFF_TUNNEL vif is then rejected by ipip_gso_segment() and dropped in
> validate_xmit_skb(), after being counted as sent. A device with UDP
> segmentation offload is handed a GSO packet whose transport header
> points at the inner IP header.
>
> Call iptunnel_handle_offloads() and skb_set_inner_ipproto() as
> ipip_tunnel_xmit() does, reserve one outer IP ID per segment as
> iptunnel_xmit() does, and set the outer length with iph_set_totlen(),
> since a GSO packet plus the outer header can exceed 64 KB. A GSO packet
> that GRE or UDP tunnel GRO marked as encapsulated already uses the inner
> headers for its own tunnel; drop it, as segmentation did before.
>
> Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
> Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
> ---
> net/ipv4/ipmr.c | 23 +++++++++++++++++------
> 1 file changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
> index acacaae05cc49..98e38839f8ccb 100644
> --- a/net/ipv4/ipmr.c
> +++ b/net/ipv4/ipmr.c
> @@ -1849,12 +1849,21 @@ static struct notifier_block ip_mr_notifier = {
> * This avoids tunnel drivers and other mess and gives us the speed so
> * important for multicast video.
> */
> -static void ip_encap(struct net *net, struct sk_buff *skb,
> - __be32 saddr, __be32 daddr)
> +static int ip_encap(struct net *net, struct sk_buff *skb,
> + __be32 saddr, __be32 daddr)
> {
> + const struct iphdr *old_iph;
> struct iphdr *iph;
> - const struct iphdr *old_iph = ip_hdr(skb);
>
> + /* The inner headers can describe one tunnel only */
> + if (skb_is_gso(skb) && skb->encapsulation)
> + return -1;
> +
> + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
> + return -1;
By the time ip_encap() runs, ipmr_prepare_xmit() has already bumped
vif->pkt_out/bytes_out and decreased the TTL, so these drops are still
counted as sent, which is what the changelog complains about.
Could you move the encapsulation check into ipmr_prepare_xmit(),
in the VIFF_TUNNEL branch before the route lookup ?
if (vif->flags & VIFF_TUNNEL) {
/* The inner headers can describe one tunnel only */
if (skb_is_gso(skb) && skb->encapsulation)
return -1;
rt = ip_route_output_ports(...);
Also note that iptunnel_handle_offloads() can not fail here:
skb_cow() was called before, so skb_header_unclone() has nothing to do.
> + skb_set_inner_ipproto(skb, IPPROTO_IPIP);
> +
> + old_iph = ip_hdr(skb);
> skb_push(skb, sizeof(struct iphdr));
> skb->transport_header = skb->network_header;
> skb_reset_network_header(skb);
> @@ -1868,12 +1877,13 @@ static void ip_encap(struct net *net, struct sk_buff *skb,
> iph->saddr = saddr;
> iph->protocol = IPPROTO_IPIP;
> iph->ihl = 5;
> - iph->tot_len = htons(skb->len);
> - ip_select_ident(net, skb, NULL);
> + iph_set_totlen(iph, skb->len);
Minor: a fraglist aggregate can reach 65535 bytes, so with the outer
header tot_len can now be 0. The packet then goes through the
NF_INET_FORWARD hook, where iph_totlen() only handles TCP GSO packets,
so nft will consider it malformed. Still better than the silent
truncation we had, but maybe worth a mention in the changelog.
Thanks.
pw-bot: cr
> + ip_select_ident_segs(net, skb, NULL, skb_shinfo(skb)->gso_segs ?: 1);
> ip_send_check(iph);
>
> memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
> nf_reset_ct(skb);
> + return 0;
> }
>
> static inline int ipmr_forward_finish(struct net *net, struct sock *sk,
> @@ -1982,7 +1992,8 @@ static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
> * What do we do with netfilter? -- RR
> */
> if (vif->flags & VIFF_TUNNEL) {
> - ip_encap(net, skb, vif->local, vif->remote);
> + if (ip_encap(net, skb, vif->local, vif->remote))
> + return -1;
> /* FIXME: extra output firewall step used to be here. --RR */
> DEV_STATS_INC(vif_dev, tx_packets);
> DEV_STATS_ADD(vif_dev, tx_bytes, skb->len);
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation
2026-11-03 12:44 ` Simon Horman
@ 2026-11-03 13:15 ` Eric Dumazet
0 siblings, 0 replies; 13+ messages in thread
From: Eric Dumazet @ 2026-11-03 13:15 UTC (permalink / raw)
To: Simon Horman
Cc: Julius Bairaktaris, netdev, dsahern, idosch, davem, kuba, pabeni,
steffen.klassert, willemb, jiayuan.chen, mfleming, almasrymina,
bigeasy, richardbgobert, ecree.xilinx, linux-kernel
Le mar. 3 nov. 2026 à 13:44, Simon Horman <horms@kernel.org> a écrit :
>
> On Sun, Nov 01, 2026 at 05:42:32PM +0100, Julius Bairaktaris wrote:
> > ipmr_prepare_xmit() drops a packet with DF set when skb->len exceeds the
> > route MTU, without checking whether it is a GSO packet. A UDP multicast
> > stream received with fraglist GRO or UDP GRO forwarding enabled is
> > aggregated into GSO packets, and every aggregate is dropped with
> > FragFails, while ip_forward() lets the same packets pass by checking
> > skb_gso_validate_network_len(). Do the same for multicast routing,
> > leaving room for the outer header on tunnel vifs. ip6mr has no such
> > check and leaves GSO packets to ip6_output().
> >
> > On an IPQ8074 router with fraglist GRO on, a 10 Mbit/s stream of
> > 1316-byte DF datagrams routed by igmpproxy loses 14.5 to 15.5% (n=3)
> > and 0% with this change.
> >
> > Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
> > Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
>
> Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-11-03 13:15 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-01 16:42 [PATCH net v4 0/4] ipmr: forward GSO multicast packets Julius Bairaktaris
2026-11-01 16:42 ` [PATCH net v4 1/4] net: make room for the tunnel header in skb_segment_list() Julius Bairaktaris
2026-11-03 12:43 ` Simon Horman
2026-11-03 13:05 ` Eric Dumazet
2026-11-01 16:42 ` [PATCH net v4 2/4] net: gso: count the inner UDP header of encapsulated UDP GSO packets Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
2026-11-03 13:08 ` Eric Dumazet
2026-11-01 16:42 ` [PATCH net v4 3/4] ipmr: set up GSO state for tunnel vifs Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
2026-11-03 13:13 ` Eric Dumazet
2026-11-01 16:42 ` [PATCH net v4 4/4] ipmr: do not drop GSO packets that fit the MTU after segmentation Julius Bairaktaris
2026-11-03 12:44 ` Simon Horman
2026-11-03 13:15 ` Eric Dumazet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox