Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers
@ 2026-11-05 20:13 Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 1/4] ipv6: fix transport header of forwarded GSO packets Matt Vollrath
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Matt Vollrath @ 2026-11-05 20:13 UTC (permalink / raw)
  To: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, David Ahern, Ido Schimmel, Andrea Mayer,
	Justin Iurman, Alexander Aring, Willem de Bruijn, Alexander Duyck

IPv6 input uses transport_header as a cursor over the extension headers:
ip6_rcv_core() sets it just past the fixed header, and each handler
advances it. Forwarding stops after hop-by-hop options, so a forwarded
GSO packet with a destination options or routing header keeps
transport_header at that extension header, in place of the L4 offset
GRO had computed. seg6 inline, rpl and ioam6 inline likewise point it at
the header they insert on output.

Code that runs later reads the extension header as TCP:

- Since commit fe6cc55f3a9a ("net: ip, ipv6: handle gso skbs in
  forwarding path"), ip6_forward()'s MTU check can answer with Packet
  Too Big at the current MTU, and the flow stalls.
- Since commit 7fb4c1967011 ("net: pull headers in
  qdisc_pkt_len_segs_init()"), in v7.1 and 6.12.114,
  __dev_queue_xmit() drops the packet as SKB_BAD_GSO when the bogus
  doff is below 5. Zero padding and SRH segment addresses make that
  common.
- Qdisc length accounting and ndo_features_check() see the wrong
  header lengths.

Rather than make each reader find the L4 header itself, set
transport_header where it goes stale. Patch 1 does it in ip6_forward()
before the MTU check, which every forwarding path reaches, including a
router that processes a routing header and forwards the packet again.
Patches 2-4 restore it after inline insertion on output. The input
paths keep it at the inserted header, where local input parses from.

For these packets, drivers now see the real L4 header in
ndo_features_check(), and in ndo_start_xmit() too for those that are not
CHECKSUM_PARTIAL, such as fraglist GRO. CHECKSUM_PARTIAL packets already
reached ndo_start_xmit() with this value.

Not covered: bridged IPv6 with br_netfilter, where
br_nf_pre_routing_ipv6() does what ip6_rcv_core() does, and GSO
packets that never pass through IPv6 input, such as LRO aggregates
redirected by tc.

Tested on net-next in QEMU with 3 s TCP flows between network
namespaces over veth, forwarded by the host unless noted:

                                        before     after
  dstopts, byte 12 = 0x00 (drop)        1.1 MB     13.9 GB
  dstopts, byte 12 = 0xf0 (PTB loop)    6.2 MB     13.9 GB
  SRH set by an unprivileged sender     5.0 MB     14.4 GB
  SRH with the router as a segment      4.7 MB     11.4 GB
  fraglist GRO, dstopts 0x00            3.8 MB      3.0 GB
  sender's seg6 / rpl / ioam6 inline     65 KB   9.3-11.0 GB

Forwarding without extension headers was unchanged within run-to-run
noise.

Matt Vollrath (4):
  ipv6: fix transport header of forwarded GSO packets
  ipv6: sr: keep transport header after inline SRH insertion
  ipv6: rpl: keep transport header after SRH insertion
  ipv6: ioam: keep transport header after inline insertion

 net/ipv6/ioam6_iptunnel.c |  7 +++++++
 net/ipv6/ip6_output.c     | 17 +++++++++++++++++
 net/ipv6/rpl_iptunnel.c   |  7 +++++++
 net/ipv6/seg6_iptunnel.c  |  8 ++++++++
 4 files changed, 39 insertions(+)


base-commit: 0822d2fe38262e8b55c5ea55c970022bca8dd2a9
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net-next 1/4] ipv6: fix transport header of forwarded GSO packets
  2026-11-05 20:13 [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers Matt Vollrath
@ 2026-11-05 20:13 ` Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 2/4] ipv6: sr: keep transport header after inline SRH insertion Matt Vollrath
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Matt Vollrath @ 2026-11-05 20:13 UTC (permalink / raw)
  To: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, David Ahern, Ido Schimmel, Andrea Mayer,
	Justin Iurman, Alexander Aring, Willem de Bruijn, Alexander Duyck

ip6_rcv_core() sets transport_header just past the fixed IPv6 header,
and local input advances it over each extension header. Forwarding
skips that walk, so a GSO packet with a destination options or routing
header reaches ip6_forward() with transport_header at an extension
header. So does a packet forwarded again after the router processed its
routing header.

skb_gso_validate_network_len() then reads a bogus TCP header length. An
overestimate makes ip6_forward() answer with Packet Too Big at the
current MTU, and the flow stalls. Since commit 7fb4c1967011 ("net: pull
headers in qdisc_pkt_len_segs_init()"), a bogus doff below 5 also makes
__dev_queue_xmit() drop the packet as SKB_BAD_GSO.

Before the MTU check, set transport_header from csum_start for
CHECKSUM_PARTIAL packets without encapsulation. Otherwise, if the
packet has extension headers, skip them with ipv6_skip_exthdr().

Signed-off-by: Matt Vollrath <tactii@gmail.com>
---
The Packet Too Big stall dates back to commit fe6cc55f3a9a ("net: ip,
ipv6: handle gso skbs in forwarding path").
---
 net/ipv6/ip6_output.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 25fe0ba98b1a..60ac56afbd06 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -662,6 +662,23 @@ int ip6_forward(struct sk_buff *skb)
 
 	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
 
+	if (skb_is_gso(skb)) {
+		if (skb->ip_summed == CHECKSUM_PARTIAL && !skb->encapsulation) {
+			skb_set_transport_header(skb,
+						 skb_checksum_start_offset(skb));
+		} else if (ipv6_ext_hdr(hdr->nexthdr)) {
+			u8 nexthdr = hdr->nexthdr;
+			__be16 frag_off;
+			int thoff;
+
+			thoff = ipv6_skip_exthdr(skb, skb_network_offset(skb) +
+						 sizeof(*hdr), &nexthdr,
+						 &frag_off);
+			if (thoff >= 0)
+				skb_set_transport_header(skb, thoff);
+		}
+	}
+
 	mtu = ip6_dst_mtu_maybe_forward(dst, true);
 	if (mtu < IPV6_MIN_MTU)
 		mtu = IPV6_MIN_MTU;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 2/4] ipv6: sr: keep transport header after inline SRH insertion
  2026-11-05 20:13 [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 1/4] ipv6: fix transport header of forwarded GSO packets Matt Vollrath
@ 2026-11-05 20:13 ` Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 3/4] ipv6: rpl: keep transport header after " Matt Vollrath
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Matt Vollrath @ 2026-11-05 20:13 UTC (permalink / raw)
  To: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, David Ahern, Ido Schimmel, Andrea Mayer,
	Justin Iurman, Alexander Aring, Willem de Bruijn, Alexander Duyck

In inline mode, seg6_do_srh() leaves transport_header at the inserted
SRH, although the L4 header has not moved. GSO length checks then read
the SRH as TCP, and since commit 7fb4c1967011 ("net: pull headers in
qdisc_pkt_len_segs_init()"), a bogus doff below 5 there makes
__dev_queue_xmit() drop each GSO packet of the flow as SKB_BAD_GSO.

On output, restore transport_header from its distance to the end of the
packet, which the insertion does not change. The input path keeps it at
the SRH, where local input parses extension headers from.

Signed-off-by: Matt Vollrath <tactii@gmail.com>
---
transport_header has pointed at the inserted SRH since commit
6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection
with lwtunnels"), where qdisc length accounting and ndo_features_check()
read it.
---
 net/ipv6/seg6_iptunnel.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 0d39a38a5dd2..942704eca8db 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -676,6 +676,7 @@ static int seg6_output_core(struct net *net, struct sock *sk,
 	struct dst_entry *orig_dst = skb_dst(skb);
 	struct dst_entry *dst = NULL;
 	struct seg6_lwt *slwt;
+	int tail_len = -1;
 	int err;
 
 	slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
@@ -684,10 +685,17 @@ static int seg6_output_core(struct net *net, struct sock *sk,
 	dst = dst_cache_get(&slwt->cache_output);
 	local_bh_enable();
 
+	if (slwt->tuninfo->mode == SEG6_IPTUN_MODE_INLINE &&
+	    skb_transport_header_was_set(skb))
+		tail_len = skb->len - skb_transport_offset(skb);
+
 	err = seg6_do_srh(skb, dst);
 	if (unlikely(err))
 		goto drop;
 
+	if (tail_len >= 0)
+		skb_set_transport_header(skb, skb->len - tail_len);
+
 	if (unlikely(!dst)) {
 		struct ipv6hdr *hdr = ipv6_hdr(skb);
 		struct flowi6 fl6;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 3/4] ipv6: rpl: keep transport header after SRH insertion
  2026-11-05 20:13 [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 1/4] ipv6: fix transport header of forwarded GSO packets Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 2/4] ipv6: sr: keep transport header after inline SRH insertion Matt Vollrath
@ 2026-11-05 20:13 ` Matt Vollrath
  2026-11-05 20:13 ` [PATCH net-next 4/4] ipv6: ioam: keep transport header after inline insertion Matt Vollrath
  2026-11-05 20:17 ` [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers netdev-bot+sinfo
  4 siblings, 0 replies; 7+ messages in thread
From: Matt Vollrath @ 2026-11-05 20:13 UTC (permalink / raw)
  To: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, David Ahern, Ido Schimmel, Andrea Mayer,
	Justin Iurman, Alexander Aring, Willem de Bruijn, Alexander Duyck

rpl_do_srh_inline() leaves transport_header at the inserted RPL SRH,
although the L4 header has not moved. GSO length checks then read the
SRH as TCP, and since commit 7fb4c1967011 ("net: pull headers in
qdisc_pkt_len_segs_init()"), a bogus doff below 5 there makes
__dev_queue_xmit() drop each GSO packet of the flow as SKB_BAD_GSO.

In rpl_output(), restore transport_header from its distance to the end
of the packet, which the insertion does not change. rpl_input() keeps it
at the SRH, where local input parses extension headers from.

Signed-off-by: Matt Vollrath <tactii@gmail.com>
---
transport_header has pointed at the inserted SRH since commit
a7a29f9c361f ("net: ipv6: add rpl sr tunnel"), where qdisc length
accounting and ndo_features_check() read it.
---
 net/ipv6/rpl_iptunnel.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c
index 4e10adcd70e8..0556bb989041 100644
--- a/net/ipv6/rpl_iptunnel.c
+++ b/net/ipv6/rpl_iptunnel.c
@@ -206,6 +206,7 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 	struct dst_entry *orig_dst = skb_dst(skb);
 	struct dst_entry *dst = NULL;
 	struct rpl_lwt *rlwt;
+	int tail_len = -1;
 	int err;
 
 	rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
@@ -214,10 +215,16 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 	dst = dst_cache_get(&rlwt->cache);
 	local_bh_enable();
 
+	if (skb_transport_header_was_set(skb))
+		tail_len = skb->len - skb_transport_offset(skb);
+
 	err = rpl_do_srh(skb, rlwt, dst);
 	if (unlikely(err))
 		goto drop;
 
+	if (tail_len >= 0)
+		skb_set_transport_header(skb, skb->len - tail_len);
+
 	if (unlikely(!dst)) {
 		struct ipv6hdr *hdr = ipv6_hdr(skb);
 		struct flowi6 fl6;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 4/4] ipv6: ioam: keep transport header after inline insertion
  2026-11-05 20:13 [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers Matt Vollrath
                   ` (2 preceding siblings ...)
  2026-11-05 20:13 ` [PATCH net-next 3/4] ipv6: rpl: keep transport header after " Matt Vollrath
@ 2026-11-05 20:13 ` Matt Vollrath
  2026-11-05 20:17 ` [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers netdev-bot+sinfo
  4 siblings, 0 replies; 7+ messages in thread
From: Matt Vollrath @ 2026-11-05 20:13 UTC (permalink / raw)
  To: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, David Ahern, Ido Schimmel, Andrea Mayer,
	Justin Iurman, Alexander Aring, Willem de Bruijn, Alexander Duyck

ioam6_do_inline() leaves transport_header at the inserted hop-by-hop
header, although the L4 header has not moved. GSO length checks then
read that header as TCP, and since commit 7fb4c1967011 ("net: pull
headers in qdisc_pkt_len_segs_init()"), a bogus doff below 5 there makes
__dev_queue_xmit() drop each GSO packet of the flow as SKB_BAD_GSO. This
depends on the trace type, and affects forwarded packets too, since the
insertion happens on output.

After ioam6_do_inline(), restore transport_header from its distance to
the end of the packet, which the insertion does not change.

Signed-off-by: Matt Vollrath <tactii@gmail.com>
---
transport_header has pointed at the inserted hop-by-hop header since
commit 3edede08ff37 ("ipv6: ioam: Support for IOAM injection with
lwtunnels"), where qdisc length accounting and ndo_features_check() read
it.
---
 net/ipv6/ioam6_iptunnel.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/net/ipv6/ioam6_iptunnel.c b/net/ipv6/ioam6_iptunnel.c
index cfb2c41634a0..27b47f0c8bf8 100644
--- a/net/ipv6/ioam6_iptunnel.c
+++ b/net/ipv6/ioam6_iptunnel.c
@@ -340,6 +340,7 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 	struct dst_entry *orig_dst = skb_dst(skb);
 	struct dst_entry *dst = NULL;
 	struct ioam6_lwt *ilwt;
+	int tail_len = -1;
 	int err = -EINVAL;
 	u32 pkt_cnt;
 
@@ -375,10 +376,16 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 		if (ipv6_hdr(skb)->nexthdr == NEXTHDR_HOP)
 			goto out;
 
+		if (skb_transport_header_was_set(skb))
+			tail_len = skb->len - skb_transport_offset(skb);
+
 		err = ioam6_do_inline(net, skb, &ilwt->tuninfo, dst);
 		if (unlikely(err))
 			goto drop;
 
+		if (tail_len >= 0)
+			skb_set_transport_header(skb, skb->len - tail_len);
+
 		break;
 	case IOAM6_IPTUNNEL_MODE_ENCAP:
 do_encap:
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers
  2026-11-05 20:13 [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers Matt Vollrath
                   ` (3 preceding siblings ...)
  2026-11-05 20:13 ` [PATCH net-next 4/4] ipv6: ioam: keep transport header after inline insertion Matt Vollrath
@ 2026-11-05 20:17 ` netdev-bot+sinfo
  2026-11-05 20:26   ` Matt Vollrath
  4 siblings, 1 reply; 7+ messages in thread
From: netdev-bot+sinfo @ 2026-11-05 20:17 UTC (permalink / raw)
  To: Matt Vollrath
  Cc: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Ahern, Ido Schimmel,
	Andrea Mayer, Justin Iurman, Alexander Aring, Willem de Bruijn,
	Alexander Duyck

Hi!

This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:

 - How the issue was discovered, e.g. hit in production, hit during
   development, syzbot report, manual code inspection, LLM or static
   analysis tool scan.

Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.

The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers
  2026-11-05 20:17 ` [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers netdev-bot+sinfo
@ 2026-11-05 20:26   ` Matt Vollrath
  0 siblings, 0 replies; 7+ messages in thread
From: Matt Vollrath @ 2026-11-05 20:26 UTC (permalink / raw)
  To: netdev-bot+sinfo
  Cc: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Ahern, Ido Schimmel,
	Andrea Mayer, Justin Iurman, Alexander Aring, Willem de Bruijn,
	Alexander Duyck

On 11/5/26 15:17, netdev-bot+sinfo@kernel.org wrote:
> Hi!
> 
> This is an automated message. This series looks like a fix, but its
> commit messages seem to be missing some information:
> 
>   - How the issue was discovered, e.g. hit in production, hit during
>     development, syzbot report, manual code inspection, LLM or static
>     analysis tool scan.

This was encountered while working on an ndo_features_check
implementation to fix a bug in e1000e[1]. An LLM found that there
were more affected consumers of transport_header, so I expanded
the scope of a different fix[2].

[1] https://lore.kernel.org/netdev/20261028170239.28606-1-tactii@gmail.com/
[2] https://lore.kernel.org/netdev/20261104175517.2395704-1-tactii@gmail.com/
> Please do not repost the series just to address the above. Instead,
> reply to this email with the missing information, so that reviewers
> can take it into account. If the series needs another revision for
> other reasons, please include the information in the commit messages
> then.
> 
> The evaluation is done by an LLM so it may be wrong, if you think
> that is the case please reply and explain.


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-05 20:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 20:13 [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers Matt Vollrath
2026-11-05 20:13 ` [PATCH net-next 1/4] ipv6: fix transport header of forwarded GSO packets Matt Vollrath
2026-11-05 20:13 ` [PATCH net-next 2/4] ipv6: sr: keep transport header after inline SRH insertion Matt Vollrath
2026-11-05 20:13 ` [PATCH net-next 3/4] ipv6: rpl: keep transport header after " Matt Vollrath
2026-11-05 20:13 ` [PATCH net-next 4/4] ipv6: ioam: keep transport header after inline insertion Matt Vollrath
2026-11-05 20:17 ` [PATCH net-next 0/4] ipv6: fix stale transport header of GSO packets with extension headers netdev-bot+sinfo
2026-11-05 20:26   ` Matt Vollrath

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox