Skip to content

ubus: reconnect connections and their listeners when ubusd drops them - #518

Open
WiFiGUY512 wants to merge 2 commits into
ucode-lang:masterfrom
WiFiGUY512:ubus-reconnect
Open

WiFiGUY512 wants to merge 2 commits into
ucode-lang:masterfrom
WiFiGUY512:ubus-reconnect

Conversation

@WiFiGUY512

Copy link
Copy Markdown

When ubusd drops a client (ubusd restarting, or a message over UBUS_MAX_MSGLEN), libubus calls the connection's connection_lost. The ubus module keeps libubus' default there, both for the shared connection of the module-level functions and for connections made with connect(). That default ends the uloop only while the socket is still registered, and uloop's epoll backend unregisters it on the hangup before the callback runs. So nothing happens: the connection stays dead, and everything published on it is gone until the process restarts.

On OpenWrt this is how these objects disappear after a ubusd restart, while netifd's own C objects come back:

  • netifd's network.wireless, which wireless.uc publishes on the shared connection;
  • the hostapd and wpa_supplicant objects, which hostapd.uc and wpa_supplicant.uc publish on connect() connections.

There are two commits.

ubus: reconnect a connection when ubusd drops it reconnects instead, retrying every second as ubus_auto_connect() does. ubus_reconnect() registers the connection's objects again. It keeps the socket path given to connect() for that. The pending reconnect is cancelled in uc_ubus_conn_teardown(), which both disconnect() and the resource's free run.

ubus: register listeners again after a reconnect. ubus_reconnect() adds a listener's object again, but not its event pattern registration with ubusd. This commit keeps each connection's listeners with their patterns and registers them again once reconnected. A listener also leaves that list when it is freed (it gets a free callback), so the connection never walks a freed listener, whichever of the two the VM frees first.

Tested on an Arista W-118 (ipq40xx, musl) with OpenWrt main of 2026-11-01:

  • With this branch's lib/ubus.c, built for the unit and loaded in place of the stock module, killall ubusd brought back network.wireless (answering status), hostapd and wpa_supplicant on the same PIDs.
  • A script listening on b36.* heard an event sent before the restart and one sent after it.
  • OpenWrt's ucode is dfc64d4, whose headers are the same as master's.
  • An earlier version of these commits has run in OpenWrt package patches on five APs since 2026-10-25.
  • The file compiles clean with the project's -Wall -Wextra -Werror.

🤖 Generated with Claude Code

When ubusd drops a client (ubusd restarting, or a message over
UBUS_MAX_MSGLEN), libubus calls the connection's connection_lost. The
module keeps libubus' default there, both for the shared connection of
the module-level functions and for connections made with connect().
That default ends the uloop only while the socket is still registered,
and uloop's epoll backend unregisters it on the hangup before the
callback runs, so nothing happens: the connection stays dead and
everything published on it is gone until the process restarts.

On OpenWrt this is how netifd's network.wireless object (wireless.uc,
shared connection) and the hostapd and wpa_supplicant objects
(hostapd.uc and wpa_supplicant.uc, connect()) disappear after a ubusd
restart, while netifd's own objects come back.

Reconnect instead, retrying every second as ubus_auto_connect() does;
ubus_reconnect() registers the connection's objects again. Keep the
socket path given to connect() for that, and cancel a pending reconnect
on disconnect() and when the connection is freed.

Signed-off-by: Christopher Griffin <christophergriffin05@gmail.com>
ubus_reconnect() adds a listener's object again but not its event
pattern registration with ubusd, so after a reconnect the connection's
listeners would hear nothing. Keep each connection's listeners with
their patterns and register them again once reconnected. A listener
also leaves that list when it is freed, so the connection never walks
a freed listener, whichever of the two the VM frees first at exit.

Signed-off-by: Christopher Griffin <christophergriffin05@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant