Skip to content

Commit 15aa8c4

Browse files
committed
fix(network): recover IP address after a link flap / router reboot
The network module only populates the interface address from netlink events (RTM_NEWADDR) or an explicit address dump. The interval timer re-queries WiFi and bandwidth but never re-fetches the address, so the module relies entirely on receiving the RTM_NEWADDR event. Netlink multicast delivery is reliable unless the socket receive buffer overflows, in which case the kernel drops notifications and reports ENOBUFS. During a burst of link/address/route changes -- e.g. a router reboot or a PPPoE redial -- this can drop the RTM_NEWADDR carrying the interface's new IP (after the old one was removed by RTM_DELADDR). With no overrun handling and no periodic resync, the address field stays blank until Waybar is restarted (which re-dumps addresses). Handle the overrun: when nl_recvmsgs_default reports ENOBUFS/NLE_NOMEM, request a fresh link/address (and route, when auto-detecting) dump to resynchronise, instead of silently continuing with lost state. Also enlarge the event socket receive buffer to make overruns less likely in the first place. The fix stays within the event thread, so it adds no new locking or cross-thread socket access. Fixes #5122.
1 parent 969855f commit 15aa8c4

1 file changed

Lines changed: 27 additions & 0 deletions

File tree

src/modules/network.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ void waybar::modules::Network::createEventSocket() {
183183
if (nl_socket_set_nonblocking(ev_sock_)) {
184184
throw std::runtime_error("Can't set non-blocking on network socket");
185185
}
186+
// Enlarge the socket receive buffer so that a burst of link/address/route
187+
// change notifications (e.g. a router reboot or a PPPoE redial) is less likely
188+
// to overflow it and make the kernel drop messages (ENOBUFS). Overruns are
189+
// still handled in worker() by resynchronising the state, but a larger buffer
190+
// avoids most of them. The kernel caps the request at net.core.rmem_max.
191+
nl_socket_set_buffer_size(ev_sock_, 1024 * 1024, 0);
186192
nl_socket_add_memberships(ev_sock_, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, 0);
187193
if (!config_["interface"].isString()) {
188194
nl_socket_add_memberships(ev_sock_, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0);
@@ -277,6 +283,27 @@ void waybar::modules::Network::worker() {
277283
rc = 0;
278284
break;
279285
}
286+
if (rc == -NLE_NOMEM || errno == ENOBUFS) {
287+
// The kernel dropped multicast notifications because our receive
288+
// buffer overflowed. This happens during a burst of
289+
// link/address/route changes such as a router reboot or a PPPoE
290+
// redial. We have lost track of the current state -- in
291+
// particular the RTM_NEWADDR carrying the interface's new IP
292+
// address may have been dropped -- so request a fresh dump to
293+
// resynchronise. Without this the address (cleared by the
294+
// preceding RTM_DELADDR) would stay blank until Waybar is
295+
// restarted, because nothing else re-queries it (#5122).
296+
spdlog::warn("network: netlink receive buffer overrun, resyncing state");
297+
want_link_dump_ = true;
298+
want_addr_dump_ = true;
299+
if (!config_["interface"].isString()) {
300+
want_route_dump_ = true;
301+
}
302+
askForStateDump();
303+
// Keep draining; the next recv proceeds normally now that the
304+
// overrun has been reported.
305+
continue;
306+
}
280307
}
281308
if (rc < 0) {
282309
spdlog::error("nl_recvmsgs_default error: {}", nl_geterror(-rc));

0 commit comments

Comments
 (0)