diff options
author | Alin Nastac <alin.nastac@gmail.com> | 2019-01-31 11:20:29 +0100 |
---|---|---|
committer | Hans Dedecker <dedeckeh@gmail.com> | 2019-01-31 22:03:00 +0100 |
commit | 5cd7215a09ad440f0d1b1d05df8deb403f945898 (patch) | |
tree | 3005190dfa8fe83f0e9b8c6b3653a6b506925f4b /system-linux.c | |
parent | 2750ce2e0a9177e024823332853c76dbd0937c98 (diff) |
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 <alin.nastac@gmail.com>
Diffstat (limited to 'system-linux.c')
-rw-r--r-- | system-linux.c | 53 |
1 files 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 @@ -182,6 +182,21 @@ create_event_socket(struct event_socket *ev, int protocol, } 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) { char *e; @@ -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) |