From 5cd7215a09ad440f0d1b1d05df8deb403f945898 Mon Sep 17 00:00:00 2001 From: Alin Nastac Date: Thu, 31 Jan 2019 11:20:29 +0100 Subject: system-linux: handle hotplug event socket ENOBUFS errors Hotplug events are no longer handled after socket RX queue is overrun. The issue has been fixed by: - setting SO_RCVBUF initially to 65535 - doubling SO_RCVBUF value each time RX queue gets overrun Signed-off-by: Alin Nastac --- system-linux.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/system-linux.c b/system-linux.c index ea16ed5..82e9928 100644 --- a/system-linux.c +++ b/system-linux.c @@ -181,6 +181,21 @@ create_event_socket(struct event_socket *ev, int protocol, return true; } +static bool +create_hotplug_event_socket(struct event_socket *ev, int protocol, + void (*cb)(struct uloop_fd *u, unsigned int events)) +{ + if (!create_raw_event_socket(ev, protocol, 1, cb, ULOOP_ERROR_CB)) + return false; + + /* Increase rx buffer size to 65K on event sockets */ + ev->bufsize = 65535; + if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0)) + return false; + + return true; +} + static bool system_rtn_aton(const char *src, unsigned int *dst) { @@ -249,8 +264,8 @@ int system_init(void) if (!create_event_socket(&rtnl_event, NETLINK_ROUTE, cb_rtnl_event)) return -1; - if (!create_raw_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, 1, - handle_hotplug_event, 0)) + if (!create_hotplug_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, + handle_hotplug_event)) return -1; /* Receive network link events form kernel */ @@ -660,13 +675,39 @@ handle_hotplug_event(struct uloop_fd *u, unsigned int events) struct sockaddr_nl nla; unsigned char *buf = NULL; int size; + int err; + socklen_t errlen = sizeof(err); + + if (!u->error) { + while ((size = nl_recv(ev->sock, &nla, &buf, NULL)) > 0) { + if (nla.nl_pid == 0) + handle_hotplug_msg((char *) buf, size); + + free(buf); + } + return; + } - while ((size = nl_recv(ev->sock, &nla, &buf, NULL)) > 0) { - if (nla.nl_pid == 0) - handle_hotplug_msg((char *) buf, size); + if (getsockopt(u->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen)) + goto abort; - free(buf); + switch(err) { + case ENOBUFS: + /* Increase rx buffer size on netlink socket */ + ev->bufsize *= 2; + if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0)) + goto abort; + break; + + default: + goto abort; } + u->error = false; + return; + +abort: + uloop_fd_delete(&ev->uloop); + return; } static int system_rtnl_call(struct nl_msg *msg) -- cgit v1.2.3