Netdev List
 help / color / mirror / Atom feed
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: netdev-bot+sashiko@kernel.org,  willemdebruijn.kernel@gmail.com
Cc: netdev@vger.kernel.org,  davem@davemloft.net,  kuba@kernel.org,
	 edumazet@google.com,  pabeni@redhat.com,  horms@kernel.org,
	 andrew+netdev@lunn.ch,  xietangxin@yeah.net,
	 willemb@google.com,  stable@vger.kernel.org
Subject: Re: [PATCH net v2] net: extend IPv6 exthdr detection of tunneled packets
Date: Mon, 28 Sep 2026 23:23:18 -0400	[thread overview]
Message-ID: <willemdebruijn.kernel.1c50b2a7a6f39@gmail.com> (raw)
In-Reply-To: <179064047393.3145.16303551892146530587@kernel.org>

netdev-bot+sashiko@ wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 0 · Medium: 1 · Low: 2
> 
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
> 
> - [Medium] net: unnecessary software checksum fallback for outer UDP
>   tunnels
> - [Low] The old non-encapsulated branch cleared features only for
>   SKB_GSO_TCPV6, or for SKB_GSO_UDP_L4 over IPv6.
> - [Low] The in-tree NETIF_F_IPV6_CSUM contract
>   (include/linux/skbuff.h:77-86) still says the feature covers only…
> 
> --
> 
> > +static bool skb_has_ipv6_extension_hdr(const struct sk_buff *skb)
> > +{
> > +	if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) {
> > +		if (__skb_has_ipv6_ext_hdr(skb, skb_network_offset(skb)))
> > +			return true;
> 
> [Severity: Low]
> 
> The removed non-encapsulated branch cleared features only for
> SKB_GSO_TCPV6, or for SKB_GSO_UDP_L4 over IPv6. The new outer check has no
> gso_type gate. Is it meant to apply to every IPv6 GSO type?
> 
> SKB_GSO_SCTP is one type whose behaviour changes. sctp_packet_pack()
> always makes the GSO head CHECKSUM_PARTIAL:
> 
> net/sctp/output.c:sctp_packet_pack() {
>     ...
> 	if (gso) {
> 		...
> 		goto chksum;
> 	}
>     ...
> chksum:
> 		head->ip_summed = CHECKSUM_PARTIAL;
> 		head->csum_not_inet = 1;
>     ...
> }
> 
> Take SCTP over IPv6 with IPV6_DSTOPTS or IPV6_RTHDR set.
> gso_features_check() now clears NETIF_F_IPV6_CSUM. harmonize_features()
> then sees ip_summed != CHECKSUM_NONE and
> !can_checksum_protocol(features, ETH_P_IPV6). It strips all of
> NETIF_F_CSUM_MASK, including NETIF_F_SCTP_CRC, plus NETIF_F_GSO_MASK:

NETIF_F_SCTP_CRC is not part of NETIF_F_CSUM_MASK:

#define NETIF_F_CSUM_MASK       (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
                                 NETIF_F_HW_CSUM)

 > validate_xmit_skb()
>   netif_skb_features()
>     gso_features_check()    /* clears NETIF_F_IPV6_CSUM */
>     harmonize_features()    /* clears NETIF_F_CSUM_MASK, NETIF_F_GSO_MASK */
>   skb_gso_segment()
>     sctp_gso_segment()      /* CRC32c computed in software per segment */
> 
> Some devices have NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SCTP_CRC
> but no NETIF_F_HW_CSUM. One example is hns3 without
> HNAE3_DEV_SUPPORT_HW_TX_CSUM_B. On such a device the CRC32c was offloaded
> before this patch and is computed in software after it. The output is
> still correct, so only performance is affected.
> 
> Could the gso_type restriction be kept here? If not, could the commit
> message say that the check now covers all IPv6 GSO types?
> 
> > +
> > +		/* Catch tunnels without skb->encapsulation (e.g., virtio). */
> > +		if (!skb->encapsulation &&
> > +		    skb_transport_header_was_set(skb) &&
> > +		    skb_network_header_len(skb) != sizeof(struct ipv6hdr))
> > +			return true;
> > +	}
> 
> [ ... ]
> 
> > @@ -3988,8 +4004,7 @@ int skb_csum_hwoffload_help(struct sk_buff *skb,
> >  		return 0;
> >  
> >  	if (features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) {
> > -		if (vlan_get_protocol(skb) == htons(ETH_P_IPV6) &&
> > -		    skb_network_header_len(skb) != sizeof(struct ipv6hdr))
> > +		if (skb_has_ipv6_extension_hdr(skb))
> >  			goto sw_checksum;
> >  
> >  		switch (skb->csum_offset) {
> 
> [Severity: Medium]
> skb_has_ipv6_extension_hdr() checks the inner IPv6 header whenever
> skb->encapsulation and the inner network header are set. That is right
> for gso_features_check(), where the device computes the inner checksum
> of every segment. Here it is applied regardless of which checksum is
> being offloaded.
> 
> The commit message describes the case where this matters: if the inner
> packet is CHECKSUM_NONE, the device offloads the outer UDP checksum.
> csum_start then points at the outer UDP header and the device does not
> need to parse any further.
> 
> Suppose the inner packet is IPv6 with, say, a Destination Options
> header. The inner check still returns true, and the outer checksum is
> now computed in software:
> 
> validate_xmit_skb()
>   skb_csum_hwoffload_help()
>     skb_has_ipv6_extension_hdr()
>       __skb_has_ipv6_ext_hdr(skb, skb_inner_network_offset(skb))
>                           /* inner nexthdr == NEXTHDR_DEST */
>     skb_checksum_help()   /* outer UDP csum in software */
> 
> Before this patch, skb_csum_hwoffload_help() only compared the outer
> network header length, so the outer checksum was offloaded.
> 
> The same regression affects an IPv4 outer header on a NETIF_F_IP_CSUM
> device. The old test never looked at those packets, because
> vlan_get_protocol() returned ETH_P_IP.
> 
> The output is still correct, so this is a performance issue. Whether
> it triggers depends on the contents of the inner packet.
> 
> For non-GSO skbs that are not CHECKSUM_PARTIAL,
> iptunnel_handle_offloads() clears skb->encapsulation. That likely hides
> this for the common in-tree tunnels, but the helper should not depend
> on it.

This is the key bit: tunnels disable skb->encapsulation when
checksumming of outer packet is requested.

This is not only something the "common in-tree tunnels" do, but
required.

For one, validate_xmit_skb sets either the inner or outer transport
header to csum_start depending on skb->encapsulation just before
calling this function.

        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                if (skb->encapsulation)
                        skb_set_inner_transport_header(skb,
                                                       skb_checksum_start_offset(skb));
                else
                        skb_set_transport_header(skb,
                                                 skb_checksum_start_offset(skb));
                if (skb_csum_hwoffload_help(skb, features))
                        goto out_kfree_skb;
        }

 
> Could the inner check be skipped here when the checksum being
> offloaded is not the inner one? For example, it could be skipped when
> skb_checksum_start_offset(skb) is below skb_inner_network_offset(skb).
> 
> Note that validate_xmit_skb() sets inner_transport_header to csum_start
> just before calling skb_csum_hwoffload_help(). That field therefore
> cannot tell the two cases apart.
> 
> [Severity: Low]
> 
> The NETIF_F_IPV6_CSUM description in include/linux/skbuff.h still says:
> 
>  *     - Driver (device) is only able to checksum plain
>  *	 TCP or UDP packets over IPv6. These are specifically
>  *	 unencapsulated packets of the form IPv6|TCP or
>  *	 IPv6|UDP where the Next Header field in the IPv6
>  *	 header is either TCP or UDP. IPv6 extension headers
>  *	 are not supported with this feature.
> 
> skb_has_ipv6_extension_hdr() rejects only extension headers in the outer
> and first inner IPv6 header. It also skips the length check when
> skb->encapsulation is set. As a result, skb_csum_hwoffload_help() returns
> 0 for encapsulated packets whose outer nexthdr is GRE, UDP or IPv6.
> 
> Encapsulated GRE and UDP over IPv6 could already be offloaded before this
> patch. The new case is IPv6|IPv6|TCP from ip6_tunnel with encaplimit
> none. The old network-to-transport length check sent it to
> skb_checksum_help(). Now it goes to the device.
> 
> The commit message says:
> 
>   A NETIF_F_IPV6_CSUM device must parse through the outer headers to
>   reach the inner ones.
> 
> Should this requirement also go into the NETIF_F_IPV6_CSUM documentation
> in skbuff.h? Driver authors who set the bit in hw_enc_features would then
> know about it.
> 
> -- 
> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260926140506.2335137-1-willemdebruijn.kernel%40gmail.com



  reply	other threads:[~2026-09-29  3:23 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-26 14:04 [PATCH net v2] net: extend IPv6 exthdr detection of tunneled packets Willem de Bruijn
2026-09-29  0:07 ` netdev-bot+sashiko
2026-09-29  3:23   ` Willem de Bruijn [this message]
2026-09-30  1:20 ` 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=willemdebruijn.kernel.1c50b2a7a6f39@gmail.com \
    --to=willemdebruijn.kernel@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=stable@vger.kernel.org \
    --cc=willemb@google.com \
    --cc=xietangxin@yeah.net \
    /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