]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
daemon: config netlink socket buf sizes at build time
authorAlexandru Ardelean <ardeleanalex@gmail.com>
Thu, 12 Jan 2017 12:46:05 +0000 (14:46 +0200)
committerVincent Bernat <vincent@bernat.im>
Sat, 14 Jan 2017 09:53:23 +0000 (10:53 +0100)
I admit it would be nicer to have this configurable at run-time
or better yet, introduce a mechanism for recovering from
overrun situations via polling.

We're starting to see in certain situations that on devices
with many ports (i.e. switches with around ~50 ports) lldpd
info is not always consistent.

I'm not entirely sure that the issue is with netlink
sock buffer sizes.

But we've also recentl addressed some issues for the mstpd
daemon with netlink sock buffer sizes.
So, I'm tempted to think that it's the same issue.

We [especially I] prefer to bump sock buffer sizes where needed
and not via sysctl `net.core.rmem_default` & `net.core.wmem_default`.

Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
src/daemon/netlink.c

index b1ea76cbf327f096fb7985491b735143ef7128ff..1d8c3e951e23ed1101ff0b1186880d12259723d2 100644 (file)
 
 #define NETLINK_BUFFER 4096
 
+#ifndef RTNL_SND_BUFSIZE
+#define RTNL_SND_BUFSIZE       32 * 1024
+#endif
+#ifndef RTNL_RCV_BUFSIZE
+#define RTNL_RCV_BUFSIZE       256 * 1024
+#endif
+
 struct netlink_req {
        struct nlmsghdr hdr;
        struct rtgenmsg gen;
@@ -40,6 +47,55 @@ struct lldpd_netlink {
        struct interfaces_address_list *addresses;
 };
 
+
+static int
+netlink_socket_set_buffer_sizes(int s)
+{
+       int sndbuf = RTNL_SND_BUFSIZE;
+       int rcvbuf = RTNL_RCV_BUFSIZE;
+       socklen_t size = 0;
+       int got = 0;
+
+       if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
+               log_warn("netlink", "unable to set SO_SNDBUF to '%d'", sndbuf);
+               return -1;
+       }
+
+       if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) {
+               log_warn("netlink", "unable to set SO_RCVBUF to '%d'", rcvbuf);
+               return -1;
+       }
+
+       /* Now read them back from kernel.
+        * SO_SNDBUF & SO_RCVBUF are cap-ed at sysctl `net.core.rmem_max` &
+        * `net.core.wmem_max`. This it the easiest [probably sanest too]
+        * to validate that our socket buffers were set properly.
+        */
+       if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &got, &size) < 0) {
+               log_warn("netlink", "unable to get SO_SNDBUF");
+       } else {
+               if (size != sizeof(sndbuf))
+                       log_warn("netlink", "size mismatch for SO_SNDBUF got '%u' "
+                                "should be '%zu'", size, sizeof(sndbuf));
+               if (got != sndbuf)
+                       log_warn("netlink", "tried to set SO_SNDBUF to '%d' "
+                                "but got '%d'", sndbuf, got);
+       }
+
+       if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &got, &size) < 0) {
+               log_warn("netlink", "unable to get SO_RCVBUF");
+       } else {
+               if (size != sizeof(rcvbuf))
+                       log_warn("netlink", "size mismatch for SO_RCVBUF got '%u' "
+                                "should be '%zu'", size, sizeof(rcvbuf));
+               if (got != rcvbuf)
+                       log_warn("netlink", "tried to set SO_RCVBUF to '%d' "
+                                "but got '%d'", rcvbuf, got);
+       }
+
+       return 0;
+}
+
 /**
  * Connect to netlink.
  *
@@ -66,6 +122,8 @@ netlink_connect(int protocol, unsigned groups)
                log_warn("netlink", "unable to open netlink socket");
                return -1;
        }
+       if (netlink_socket_set_buffer_sizes(s) < 0)
+               return -1;
        if (groups && bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) < 0) {
                log_warn("netlink", "unable to bind netlink socket");
                close(s);