Subject: Re: iproute uses too small of a receive buffer

From: Patrick McHardy <[email-masked]>
Date: Wed, 28 Oct 2009 20:05:12 +0100

Eric Dumazet wrote:
> Stephen Hemminger a écrit :
>> Just having larger buffer isn't guarantee of success. Allocating
>> a huge buffer is not going to work on embedded.
>>
> 
> Please note we do not allocate a big buffer, only allow more small skbs
> to be queued on socket receive queue.
> 
> If memory is not available, skb allocation will eventually fail
> and be reported as well, embedded or not.
> 
> I vote for allowing 1024*1024 bytes instead of 32768,
> and eventually user should be warned that it is capped by 
> /proc/sys/net/core/rmem_max

How about this? It will double the receive queue limit on ENOBUFS
up to 1024 * 1024b, then bail out with the normal error message on
further ENOBUFS.

Signed-off-by: Patrick McHardy <[email-masked]>
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index b68e2fd..e4fda40 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -25,6 +25,8 @@
 
 #include "libnetlink.h"
 
+static int rcvbuf = 32768;
+
 void rtnl_close(struct rtnl_handle *rth)
 {
 	if (rth->fd >= 0) {
@@ -38,7 +40,6 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
 {
 	socklen_t addr_len;
 	int sndbuf = 32768;
-	int rcvbuf = 32768;
 
 	memset(rth, 0, sizeof(*rth));
 
@@ -407,6 +409,12 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 		if (status < 0) {
 			if (errno == EINTR || errno == EAGAIN)
 				continue;
+			if (errno == ENOBUFS && rcvbuf < 1024 * 1024) {
+				rcvbuf *= 2;
+				if (setsockopt(rtnl->fd, SOL_SOCKET, SO_RCVBUF,
+					       &rcvbuf, sizeof(rcvbuf)) == 0)
+					continue;
+			}
 			fprintf(stderr, "netlink receive error %s (%d)\n",
 				strerror(errno), errno);
 			return -1;