* [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