Skip to content

Commit c4336a0

Browse files
wdebruijPaolo Abeni
authored andcommitted
net: correctly handle tunneled traffic on IPV6_CSUM GSO fallback
NETIF_F_IPV6_CSUM only advertises support for checksum offload of packets without IPv6 extension headers. Packets with extension headers must fall back onto software checksumming. Since TSO depends on checksum offload, those must revert to GSO. The below commit introduces that fallback. It always checks network header length. For tunneled packets, the inner header length must be checked instead. Extend the check accordingly. A special case is tunneled packets without inner IP protocol. Such as RFC 6951 SCTP in UDP. Those are not standard IPv6 followed by transport header either, so also must revert to the software GSO path. Cc: [email protected] Fixes: 864e339 ("net: gso: Forbid IPv6 TSO with extensions on devices with only IPV6_CSUM") Reported-by: Tangxin Xie <[email protected]> Closes: https://lore.kernel.org/netdev/[email protected]/ Suggested-by: Paolo Abeni <[email protected]> Signed-off-by: Willem de Bruijn <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent d9c2a50 commit c4336a0

1 file changed

Lines changed: 17 additions & 5 deletions

File tree

net/core/dev.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3769,6 +3769,22 @@ static netdev_features_t dflt_features_check(struct sk_buff *skb,
37693769
return vlan_features_check(skb, features);
37703770
}
37713771

3772+
static bool skb_gso_has_extension_hdr(const struct sk_buff *skb)
3773+
{
3774+
if (!skb->encapsulation)
3775+
return ((skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6 ||
3776+
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 &&
3777+
vlan_get_protocol(skb) == htons(ETH_P_IPV6))) &&
3778+
skb_transport_header_was_set(skb) &&
3779+
skb_network_header_len(skb) != sizeof(struct ipv6hdr));
3780+
else
3781+
return (!skb_inner_network_header_was_set(skb) ||
3782+
((skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6 ||
3783+
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 &&
3784+
inner_ip_hdr(skb)->version == 6)) &&
3785+
skb_inner_network_header_len(skb) != sizeof(struct ipv6hdr)));
3786+
}
3787+
37723788
static netdev_features_t gso_features_check(const struct sk_buff *skb,
37733789
struct net_device *dev,
37743790
netdev_features_t features)
@@ -3816,11 +3832,7 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
38163832
* so neither does TSO that depends on it.
38173833
*/
38183834
if (features & NETIF_F_IPV6_CSUM &&
3819-
(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6 ||
3820-
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 &&
3821-
vlan_get_protocol(skb) == htons(ETH_P_IPV6))) &&
3822-
skb_transport_header_was_set(skb) &&
3823-
skb_network_header_len(skb) != sizeof(struct ipv6hdr))
3835+
skb_gso_has_extension_hdr(skb))
38243836
features &= ~(NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4);
38253837

38263838
return features;

0 commit comments

Comments
 (0)