]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ip6_tunnel: Fix broken GRO
authorThomas Bogendoerfer <tbogendoerfer@suse.de>
Thu, 15 Aug 2024 15:14:16 +0000 (17:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Sep 2024 11:17:40 +0000 (13:17 +0200)
[ Upstream commit 4b3e33fcc38f7750604b065c55a43e94c5bc3145 ]

GRO code checks for matching layer 2 headers to see, if packet belongs
to the same flow and because ip6 tunnel set dev->hard_header_len
this check fails in cases, where it shouldn't. To fix this don't
set hard_header_len, but use needed_headroom like ipv4/ip_tunnel.c
does.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Link: https://patch.msgid.link/20240815151419.109864-1-tbogendoerfer@suse.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/ipv6/ip6_tunnel.c

index d1f819238414733c1266b57b1596ce4780d75a4e..bd27204725ed84d3b28163e037afcb623ff34d14 100644 (file)
@@ -1531,7 +1531,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
                        tdev = __dev_get_by_index(t->net, p->link);
 
                if (tdev) {
-                       dev->hard_header_len = tdev->hard_header_len + t_hlen;
+                       dev->needed_headroom = tdev->hard_header_len +
+                               tdev->needed_headroom + t_hlen;
                        mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
 
                        mtu = mtu - t_hlen;
@@ -1758,7 +1759,9 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct ip6_tnl *tnl = netdev_priv(dev);
+       int t_hlen;
 
+       t_hlen = tnl->hlen + sizeof(struct ipv6hdr);
        if (tnl->parms.proto == IPPROTO_IPV6) {
                if (new_mtu < IPV6_MIN_MTU)
                        return -EINVAL;
@@ -1767,10 +1770,10 @@ int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
                        return -EINVAL;
        }
        if (tnl->parms.proto == IPPROTO_IPV6 || tnl->parms.proto == 0) {
-               if (new_mtu > IP6_MAX_MTU - dev->hard_header_len)
+               if (new_mtu > IP6_MAX_MTU - dev->hard_header_len - t_hlen)
                        return -EINVAL;
        } else {
-               if (new_mtu > IP_MAX_MTU - dev->hard_header_len)
+               if (new_mtu > IP_MAX_MTU - dev->hard_header_len - t_hlen)
                        return -EINVAL;
        }
        dev->mtu = new_mtu;
@@ -1916,12 +1919,11 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
        t_hlen = t->hlen + sizeof(struct ipv6hdr);
 
        dev->type = ARPHRD_TUNNEL6;
-       dev->hard_header_len = LL_MAX_HEADER + t_hlen;
        dev->mtu = ETH_DATA_LEN - t_hlen;
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                dev->mtu -= 8;
        dev->min_mtu = ETH_MIN_MTU;
-       dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len;
+       dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len - t_hlen;
 
        dev_hold(dev);
        return 0;