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 21:29:27 +0100 |
commit | a2aba5c7ae574452a9f81e9d788afecdd8ec07b2 (patch) | |
tree | 25166c7d5a9a7ccb16dc3cbc6e4267ea749cefea | |
parent | d0fa124eac8bb0e35680d80ea719eada873267be (diff) | |
download | netifd-openwrt-18.06.tar.gz |
system-linux: handle hotplug event socket ENOBUFS errorsopenwrt-18.06
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>
-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 9cd49d0..dbaba4a 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 @@ -630,13 +645,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; + + 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; - free(buf); + default: + goto abort; } + u->error = false; + return; + +abort: + uloop_fd_delete(&ev->uloop); + return; } static int system_rtnl_call(struct nl_msg *msg) |