diff mbox

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

Message ID D8C50530D6022F40A817A35C40CC06A70B34FD4FD1@DUBX7MCDUB01.EMEA.DELL.COM
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Menny_Hamburger@Dell.com July 8, 2012, 8:46 a.m. UTC
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(-)
diff mbox

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,