net: allow gro_max_size to exceed 65536
authorAlexander Duyck <alexanderduyck@fb.com>
Fri, 13 May 2022 18:34:03 +0000 (11:34 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 16 May 2022 09:18:56 +0000 (10:18 +0100)
Allow the gro_max_size to exceed a value larger than 65536.

There weren't really any external limitations that prevented this other
than the fact that IPv4 only supports a 16 bit length field. Since we have
the option of adding a hop-by-hop header for IPv6 we can allow IPv6 to
exceed this value and for IPv4 and non-TCP flows we can cap things at 65536
via a constant rather than relying on gro_max_size.

[edumazet] limit GRO_MAX_SIZE to (8 * 65535) to avoid overflows.

Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
include/linux/netdevice.h
include/net/ipv6.h
net/core/dev.c
net/core/gro.c
net/core/rtnetlink.c

index 838870bc6dbd6e3a3d8c9443ff4675a0e411006b..24de37b79f5a917b304c011fcebcd09748ee5c6a 100644 (file)
@@ -2038,7 +2038,7 @@ mlx5e_hw_gro_skb_has_enough_space(struct sk_buff *skb, u16 data_bcnt)
 {
        int nr_frags = skb_shinfo(skb)->nr_frags;
 
-       return PAGE_SIZE * nr_frags + data_bcnt <= GRO_MAX_SIZE;
+       return PAGE_SIZE * nr_frags + data_bcnt <= GRO_LEGACY_MAX_SIZE;
 }
 
 static void
index fd38847d0dc7e2c985646ac427d0131995e9c827..d57ce248004ca32d8a3e984e31ec40c7a7b9f51d 100644 (file)
@@ -2161,7 +2161,11 @@ struct net_device {
        struct bpf_prog __rcu   *xdp_prog;
        unsigned long           gro_flush_timeout;
        int                     napi_defer_hard_irqs;
-#define GRO_MAX_SIZE           65536
+#define GRO_LEGACY_MAX_SIZE    65536u
+/* TCP minimal MSS is 8 (TCP_MIN_GSO_SIZE),
+ * and shinfo->gso_segs is a 16bit field.
+ */
+#define GRO_MAX_SIZE           (8 * 65535u)
        unsigned int            gro_max_size;
        rx_handler_func_t __rcu *rx_handler;
        void __rcu              *rx_handler_data;
index b6df0314aa02dd1c4094620145ccb24da7195b2b..5b38bf1a586b9da55f43db30d140d364a70f6c11 100644 (file)
@@ -477,7 +477,7 @@ static inline int ipv6_has_hopopt_jumbo(const struct sk_buff *skb)
        const struct hop_jumbo_hdr *jhdr;
        const struct ipv6hdr *nhdr;
 
-       if (likely(skb->len <= GRO_MAX_SIZE))
+       if (likely(skb->len <= GRO_LEGACY_MAX_SIZE))
                return 0;
 
        if (skb->protocol != htons(ETH_P_IPV6))
index 830beb05161a5763957007e5da39f65d506c726c..d93456c75b55c27166cf43cbd1d5d44d950ffc41 100644 (file)
@@ -10598,7 +10598,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 
        dev->gso_max_size = GSO_LEGACY_MAX_SIZE;
        dev->gso_max_segs = GSO_MAX_SEGS;
-       dev->gro_max_size = GRO_MAX_SIZE;
+       dev->gro_max_size = GRO_LEGACY_MAX_SIZE;
        dev->tso_max_size = TSO_LEGACY_MAX_SIZE;
        dev->tso_max_segs = TSO_MAX_SEGS;
        dev->upper_level = 1;
index 78110edf5d4b36d2fa6f8a2676096efe0112aa0e..b4190eb084672fb4f2be8b437eccb4e8507ff63f 100644 (file)
@@ -167,6 +167,14 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
        if (unlikely(p->len + len >= gro_max_size || NAPI_GRO_CB(skb)->flush))
                return -E2BIG;
 
+       if (unlikely(p->len + len >= GRO_LEGACY_MAX_SIZE)) {
+               if (p->protocol != htons(ETH_P_IPV6) ||
+                   skb_headroom(p) < sizeof(struct hop_jumbo_hdr) ||
+                   ipv6_hdr(p)->nexthdr != IPPROTO_TCP ||
+                   p->encapsulation)
+                       return -E2BIG;
+       }
+
        lp = NAPI_GRO_CB(p)->last;
        pinfo = skb_shinfo(lp);
 
index f2b0f747d3d298897a7f191363bfee632542257b..ac45328607f77af33cf51f85f9918376a9fe8ae0 100644 (file)
@@ -2360,14 +2360,6 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[],
                }
        }
 
-       if (tb[IFLA_GRO_MAX_SIZE]) {
-               u32 gro_max_size = nla_get_u32(tb[IFLA_GRO_MAX_SIZE]);
-
-               if (gro_max_size > GRO_MAX_SIZE) {
-                       NL_SET_ERR_MSG(extack, "too big gro_max_size");
-                       return -EINVAL;
-               }
-       }
        return 0;
 }