From d518110e6f51ccfb435b307eccef36343fdb5f9d Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 5 Jul 2026 11:07:59 +0200 Subject: [PATCH] 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. --- src/modules/network.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 72a367fc..d3adfbe5 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -183,6 +183,12 @@ void waybar::modules::Network::createEventSocket() { if (nl_socket_set_nonblocking(ev_sock_)) { throw std::runtime_error("Can't set non-blocking on network socket"); } + // Enlarge the socket receive buffer so that a burst of link/address/route + // change notifications (e.g. a router reboot or a PPPoE redial) is less likely + // to overflow it and make the kernel drop messages (ENOBUFS). Overruns are + // still handled in worker() by resynchronising the state, but a larger buffer + // avoids most of them. The kernel caps the request at net.core.rmem_max. + nl_socket_set_buffer_size(ev_sock_, 1024 * 1024, 0); nl_socket_add_memberships(ev_sock_, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, 0); if (!config_["interface"].isString()) { nl_socket_add_memberships(ev_sock_, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0); @@ -277,6 +283,27 @@ void waybar::modules::Network::worker() { rc = 0; break; } + if (rc == -NLE_NOMEM || errno == ENOBUFS) { + // The kernel dropped multicast notifications because our receive + // buffer overflowed. This happens during a burst of + // link/address/route changes such as a router reboot or a PPPoE + // redial. We have lost track of the current state -- in + // particular the RTM_NEWADDR carrying the interface's new IP + // address may have been dropped -- so request a fresh dump to + // resynchronise. Without this the address (cleared by the + // preceding RTM_DELADDR) would stay blank until Waybar is + // restarted, because nothing else re-queries it (#5122). + spdlog::warn("network: netlink receive buffer overrun, resyncing state"); + want_link_dump_ = true; + want_addr_dump_ = true; + if (!config_["interface"].isString()) { + want_route_dump_ = true; + } + askForStateDump(); + // Keep draining; the next recv proceeds normally now that the + // overrun has been reported. + continue; + } } if (rc < 0) { spdlog::error("nl_recvmsgs_default error: {}", nl_geterror(-rc));