Patchwork IPV6 ndisc:: Bad NIC causing IPV6 NDP to stop working

login
register
mail settings
Submitter Menny_Hamburger@Dell.com
Date July 8, 2012, 8:46 a.m.
Message ID <D8C50530D6022F40A817A35C40CC06A70B34FD4FD1@DUBX7MCDUB01.EMEA.DELL.COM>
Download mbox | patch
Permalink /patch/169624/
State Not Applicable
Delegated to: David Miller
Headers show

Comments

Menny_Hamburger@Dell.com - July 8, 2012, 8:46 a.m.
After some debugging we found that our network driver sometimes fails to release the skb after calls to tx_start_xmit, which caused the ndisc socket send buffer to become full.
(sock_alloc_send_skb would fail on (atomic_read(&sk->sk_wmwm_alloc) < sk->sk_sndbuf) ). 
We also witnessed allocation failures in cases where we have a number of different NICS (1GB, 10GB, ...) - the slowest NIC becomes a bottleneck.
Using alloc_skb instead of sock_alloc_skb fixes this problem; my only concern is that in the extreme cases of a stray driver or some memory corruption, the absence of an upper limit to the skb 
allocation may consume the skbuff cache and cause all networking to behave badly.

Thanks,
Menny

net/ipv6/ndisc.c |   24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

Patch

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c

index 69a6330..f149d85 100644

--- a/net/ipv6/ndisc.c

+++ b/net/ipv6/ndisc.c

@@ -429,7 +429,6 @@  struct sk_buff *ndisc_build_skb(struct net_device *dev,

 	int hlen = LL_RESERVED_SPACE(dev);
 	int tlen = dev->needed_tailroom;
 	int len;
-	int err;

 	u8 *opt;
 
 	if (!dev->addr_len)
@@ -439,15 +438,10 @@  struct sk_buff *ndisc_build_skb(struct net_device *dev,

 	if (llinfo)
 		len += ndisc_opt_addr_space(dev);
 
-	skb = sock_alloc_send_skb(sk,

-				  (MAX_HEADER + sizeof(struct ipv6hdr) +

-				   len + hlen + tlen),

-				  1, &err);

-	if (!skb) {

-		ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n",

-			  __func__, err);

+	skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + len + hlen + tlen,

+			GFP_ATOMIC);

+	if (!skb)

 		return NULL;
-	}

 
 	skb_reserve(skb, hlen);
 	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
@@ -1550,16 +1544,10 @@  void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)

 
 	hlen = LL_RESERVED_SPACE(dev);
 	tlen = dev->needed_tailroom;
-	buff = sock_alloc_send_skb(sk,

-				   (MAX_HEADER + sizeof(struct ipv6hdr) +

-				    len + hlen + tlen),

-				   1, &err);

-	if (buff == NULL) {

-		ND_PRINTK(0, err,

-			  "Redirect: %s failed to allocate an skb, err=%d\n",

-			  __func__, err);

+	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + len + hlen + tlen,

+			 GFP_ATOMIC);

+	if (!buff)

 		goto release;
-	}

 
 	skb_reserve(buff, hlen);
 	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,