71 lines
2.7 KiB
Diff
71 lines
2.7 KiB
Diff
From 30b678d844af3305cda5953467005cebb5d7b687 Mon Sep 17 00:00:00 2001
|
|
From: Ben Hutchings <bhutchings@solarflare.com>
|
|
Date: Mon, 30 Jul 2012 15:57:00 +0000
|
|
Subject: [PATCH] net: Allow driver to limit number of GSO segments per skb
|
|
|
|
A peer (or local user) may cause TCP to use a nominal MSS of as little
|
|
as 88 (actual MSS of 76 with timestamps). Given that we have a
|
|
sufficiently prodigious local sender and the peer ACKs quickly enough,
|
|
it is nevertheless possible to grow the window for such a connection
|
|
to the point that we will try to send just under 64K at once. This
|
|
results in a single skb that expands to 861 segments.
|
|
|
|
In some drivers with TSO support, such an skb will require hundreds of
|
|
DMA descriptors; a substantial fraction of a TX ring or even more than
|
|
a full ring. The TX queue selected for the skb may stall and trigger
|
|
the TX watchdog repeatedly (since the problem skb will be retried
|
|
after the TX reset). This particularly affects sfc, for which the
|
|
issue is designated as CVE-2012-3412.
|
|
|
|
Therefore:
|
|
1. Add the field net_device::gso_max_segs holding the device-specific
|
|
limit.
|
|
2. In netif_skb_features(), if the number of segments is too high then
|
|
mask out GSO features to force fall back to software GSO.
|
|
|
|
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
include/linux/netdevice.h | 2 ++
|
|
net/core/dev.c | 4 ++++
|
|
2 files changed, 6 insertions(+), 0 deletions(-)
|
|
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index eb06e58..a9db4f3 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -1300,6 +1300,8 @@ struct net_device {
|
|
/* for setting kernel sock attribute on TCP connection setup */
|
|
#define GSO_MAX_SIZE 65536
|
|
unsigned int gso_max_size;
|
|
+#define GSO_MAX_SEGS 65535
|
|
+ u16 gso_max_segs;
|
|
|
|
#ifdef CONFIG_DCB
|
|
/* Data Center Bridging netlink ops */
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 0cb3fe8..f91abf8 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -2134,6 +2134,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
|
|
__be16 protocol = skb->protocol;
|
|
netdev_features_t features = skb->dev->features;
|
|
|
|
+ if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
|
|
+ features &= ~NETIF_F_GSO_MASK;
|
|
+
|
|
if (protocol == htons(ETH_P_8021Q)) {
|
|
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
|
|
protocol = veh->h_vlan_encapsulated_proto;
|
|
@@ -5986,6 +5989,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
|
dev_net_set(dev, &init_net);
|
|
|
|
dev->gso_max_size = GSO_MAX_SIZE;
|
|
+ dev->gso_max_segs = GSO_MAX_SEGS;
|
|
|
|
INIT_LIST_HEAD(&dev->napi_list);
|
|
INIT_LIST_HEAD(&dev->unreg_list);
|
|
--
|
|
1.7.7.6
|
|
|