From: Alexandru Ardelean Date: Thu, 12 Jan 2017 12:46:05 +0000 (+0200) Subject: daemon: config netlink socket buf sizes at build time X-Git-Tag: 0.9.6~8 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Flldpd.git;a=commitdiff_plain;h=c9f0ee58bf7f21ac9e27b1bd3e1ae349e09ab207 daemon: config netlink socket buf sizes at build time 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 --- diff --git a/src/daemon/netlink.c b/src/daemon/netlink.c index b1ea76cb..1d8c3e95 100644 --- a/src/daemon/netlink.c +++ b/src/daemon/netlink.c @@ -28,6 +28,13 @@ #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);