Summary
On a RUTX10 used as a Wi-Fi client bridge with relayd (pseudo-bridge), every reconnection of the Wi-Fi STA that lasts long enough for wan to lose its DHCP address leaves relayd’s local table 16800 without the route to the gateway and without the default route. The device then stops answering its gateway (ICMP, HTTP, HTTPS) and the condition never self-heals. Only a relayd restart, a reboot, or manually re-adding the routes recovers it. Reproduced 3 times out of 3 attempts, with an identical sequence each time.
This matters to us because the RUTX10 is evaluated for 24/7 industrial sites, where a periodic restart is not an acceptable workaround.
Environment
- Device: RUTX10, firmware
RUTX_R_00.07.26.1, kernel 6.6.137 - relayd package
git-r0(binary dated 2026-10-26, sha256032382c3a5ba26d802c6bff264fe55c1a41214978ec332f73050278d65d72c5c) - Wi-Fi:
wlan1-D-in client mode (STA) on a 5 GHz SSID, networkwan,proto dhcp, address 192.168.1.5/24 - LAN:
br-lanstatic 192.168.1.245/24 (wired devices behind the bridge) /etc/config/relayd:enabled 1,list network lan,list network wan,gateway 192.168.1.1,ipaddr 192.168.1.245- Running command line:
/usr/sbin/relayd -I br-lan -I wlan1-D- -L 192.168.1.245 -G 192.168.1.1 -B -D - Upstream AP and DHCP server: OpenWrt 25.12.6 router, 192.168.1.1
- Policy rules (as set by relayd):
iif lo→ 16800,iif wlan1-D-→ 16801,iif br-lan→ 16802
Steps to reproduce
- Bridge running normally: table 16800 contains
default via 192.168.1.1 dev wlan1-D- src 192.168.1.5and a /32 per known LAN host, including192.168.1.1. - Make the STA lose its association for more than about 35 s. We used the upstream AP to deauthenticate the RUTX10 and block it for 60 s (
hostapd del_clientwithban_time 60000). Rebooting the upstream router has the same effect (first occurrence). - Wait for the STA to reassociate and for DHCP to complete, then wait 60 s more.
Expected
After reconnection, the gateway route and the default route are present again in table 16800, and the device is reachable from the gateway.
Observed
wanloses 192.168.1.5 when the association is lost; the kernel then flushes every route throughwlan1-D-in all tables.- At reconnection, the DHCP ACK from 192.168.1.1 is seen by relayd (
-D). relayd adds192.168.1.1anddefault via 192.168.1.1to table 16802 before netifd restores 192.168.1.5 onwlan1-D-(seeip -ts monitorbelow). - The same two routes never appear in table 16800. Hosts learned after the address is back (for example 192.168.1.100, .110, .3) are added correctly to 16800.
ip route get 192.168.1.1returnsdev br-lan src 192.168.1.245: the device sends its own traffic to the gateway out of the wired side.- The gateway can no longer ping the device. The kernel logs
icmp: detected local route for 192.168.1.5 during ICMP sending, src 192.168.1.1repeatedly. - relayd keeps running (same PID throughout) and keeps ARP-probing 192.168.1.1 every 30 s, which answers, so the host entry never expires and the route is never re-installed.
Excerpt, attempt 1 (attempts 2 and 3 are identical, see the Evidence section below):
[20:54:12] Deleted 17: wlan1-D- inet 192.168.1.5/24 ... scope global wlan1-D-
20:55:30.377072 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply
[20:55:30] 192.168.1.1 dev wlan1-D- table 16802 scope link
[20:55:30] default via 192.168.1.1 dev wlan1-D- table 16802
[20:55:30] 17: wlan1-D- inet 192.168.1.5/24 ... scope global wlan1-D-
[20:55:30] 192.168.1.100 dev wlan1-D- table 16802 scope link
[20:55:30] 192.168.1.100 dev wlan1-D- table 16800 scope link src 192.168.1.5
(no 192.168.1.1 and no default route in table 16800 afterwards; the first, unprovoked occurrence stayed
in this state for more than 40 minutes until the routes were re-added by hand)
- Attempt 1: address removed 20:54:12, DHCP reply 20:55:30.377, .1 and default added to 16802 at 20:55:30, address restored 20:55:30; in 16800 after 60 s: missing; gateway reaches device: no
- Attempt 2: address removed 20:58:03, DHCP reply 20:59:21.377, .1 and default added to 16802 at 20:59:21, address restored 20:59:21; in 16800 after 60 s: missing; gateway reaches device: no
- Attempt 3: address removed 21:01:07, DHCP reply 21:02:24.577, .1 and default added to 16802 at 21:02:24, address restored 21:02:24; in 16800 after 60 s: missing; gateway reaches device: no
Analysis
- Removing the last IPv4 address from
wlan1-D-makes the kernel flush every route using that interface in every table (fib_inetaddr_event→fib_disable_ipwithforce). - In this build, routes in the local table 16800 carry
RTA_PREFSRC= the STA DHCP address (192.168.1.5), not the-Laddress:ip route show table 16800showssrc 192.168.1.5, and the device also answers ARP for 192.168.1.5, which upstream relayd only does for-L. The binary is linked against libubus and reacts tonetwork.interfaceevents, which upstream relayd does not. - When relayd creates the gateway host from the DHCP ACK, 192.168.1.5 is not yet configured. The kernel rejects the 16800 insertion (“Invalid prefsrc address”); the 16802 insertion, which has no prefsrc, succeeds.
- relayd sends
RTM_NEWROUTEwithoutNLM_F_ACK, ignores errors, does not monitor routes or addresses, and only installs routes when a host entry is created. A host that keeps answering ARP probes is therefore never re-installed. The ubusifuphandling does not resynchronize existing hosts.
We checked this against upstream relayd (git.openwrt.org/project/relayd, commit 708a76f) and Linux 6.6 net/ipv4 sources, and reproduced the kernel side in an isolated network namespace.
Requests
- Re-install all host routes and the default route when the interface comes up or its address changes.
- Use
NLM_F_ACKand retry failed route insertions, or periodically reconcile tables 16800 to 16802. - Keep
-Las the prefsrc of table 16800, or document why it is overridden. - Expose relayd
-P(do not parse DHCP options) in UCI and the WebUI. - Publish the GPL source of the RutOS relayd changes.
Workaround in place and results
Applied on 2026-11-04 at 21:12, without restarting relayd:
wanswitched to a static address (192.168.1.5/24, gateway and DNS 192.168.1.1; the DHCP reservation is kept on the router), so the address is no longer removed when the STA loses its association.- A /32 route to the gateway declared on
wan(config route), re-applied by netifd at eachifup. - A reconciliation script run every minute by cron: copies missing /32 routes from 16801/16802 into 16800 and restores a missing or wrong default route. It never restarts relayd.
Results with the same reproduction (STA deauthenticated and blocked by the AP):
- 60 s cuts: 4 out of 4 without failure. The address was never removed, table 16800 kept the gateway and the default route, the gateway kept reaching the device, relayd kept the same PID, and the reconciliation script had nothing to correct. A fifth run was invalidated by RutOS Ping Reboot (two consecutive checks fell during our back-to-back test cuts).
- 15 s cuts: 2 out of 2 without failure.
Further observations, relevant to the same weakness:
- Changing the
wanconfiguration (/etc/init.d/network reload) flushes every relayd route throughwlan1-D-while relayd keeps its hosts, so none of them is re-installed. We had to save and restore the routes around the change. - Right after a reboot (2026-11-04 21:25:51), the default route was missing from both 16800 and 16802 until our script added it at 21:26:00.
- Once after that reboot, a 15 s cut destroyed and re-created
wlan1-D-(ifindex 16 → 17) and relayd was restarted by the system (new PID). Its tables were then correct.
Evidence
Evidence: Attempt 1
=== Attempt 1
--- table 16800 before
default via 192.168.1.1 dev wlan1-D- src 192.168.1.5
192.168.0.200 dev wlan1-D- scope link src 192.168.1.5
192.168.1.1 dev wlan1-D- scope link src 192.168.1.5
192.168.1.3 dev wlan1-D- scope link src 192.168.1.5
192.168.1.32 dev wlan1-D- scope link src 192.168.1.5
192.168.1.33 dev wlan1-D- scope link src 192.168.1.5
192.168.1.100 dev wlan1-D- scope link src 192.168.1.5
192.168.1.110 dev wlan1-D- scope link src 192.168.1.5
192.168.1.138 dev wlan1-D- scope link src 192.168.1.5
192.168.1.181 dev wlan1-D- scope link src 192.168.1.5
192.168.1.185 dev wlan1-D- scope link src 192.168.1.5
192.168.1.231 dev wlan1-D- scope link src 192.168.1.5
192.168.1.232 dev wlan1-D- scope link src 192.168.1.5
--- ip -ts monitor route address (address and gateway events)
[2026-11-04T20:54:12.000000] Deleted 17: wlan1-D- inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan1-D-
[2026-11-04T20:55:30.000000] 192.168.1.1 dev wlan1-D- table 16802 scope link
[2026-11-04T20:55:30.000000] default via 192.168.1.1 dev wlan1-D- table 16802
[2026-11-04T20:55:30.000000] 17: wlan1-D- inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan1-D-
[2026-11-04T20:55:30.000000] 192.168.1.100 dev wlan1-D- table 16802 scope link
[2026-11-04T20:55:30.000000] 192.168.1.100 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T20:55:42.000000] 192.168.1.110 dev wlan1-D- table 16802 scope link
[2026-11-04T20:55:42.000000] 192.168.1.110 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T20:55:45.000000] 192.168.1.3 dev wlan1-D- table 16802 scope link
[2026-11-04T20:55:45.000000] 192.168.1.3 dev wlan1-D- table 16800 scope link src 192.168.1.5
--- DHCP on wlan1-D- (tcpdump -e -tttt)
2026-11-04 20:55:30.374900 22:97:27:b8:xx:xx > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 342: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 22:97:27:b8:xx:xx, length 300
2026-11-04 20:55:30.377072 94:83:c4:a7:xx:xx > 22:97:27:b8:xx:xx, ethertype IPv4 (0x0800), length 365: 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply, length 323
2026-11-04 20:55:30.484919 22:97:27:b8:xx:xx > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 342: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 22:97:27:b8:xx:xx, length 300
2026-11-04 20:55:30.487703 94:83:c4:a7:xx:xx > 22:97:27:b8:xx:xx, ethertype IPv4 (0x0800), length 365: 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply, length 323
--- table 16800 after (60 s after reassociation)
192.168.1.3 dev wlan1-D- scope link src 192.168.1.5
192.168.1.100 dev wlan1-D- scope link src 192.168.1.5
192.168.1.110 dev wlan1-D- scope link src 192.168.1.5
--- table 16802 after
default via 192.168.1.1 dev wlan1-D-
192.168.1.1 dev wlan1-D- scope link
192.168.1.3 dev wlan1-D- scope link
192.168.1.100 dev wlan1-D- scope link
192.168.1.110 dev wlan1-D- scope link
--- ip route get 192.168.1.1
192.168.1.1 dev br-lan src 192.168.1.245 uid 0
--- upstream router pings device
routeur -> pont : muet
Evidence: Attempt 2
=== Attempt 2
--- table 16800 before
default via 192.168.1.1 dev wlan1-D- src 192.168.1.5
192.168.1.1 dev wlan1-D- scope link src 192.168.1.5
192.168.1.3 dev wlan1-D- scope link src 192.168.1.5
192.168.1.100 dev wlan1-D- scope link src 192.168.1.5
192.168.1.110 dev wlan1-D- scope link src 192.168.1.5
--- ip -ts monitor route address (address and gateway events)
[2026-11-04T20:58:03.000000] Deleted 17: wlan1-D- inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan1-D-
[2026-11-04T20:59:21.000000] 192.168.1.1 dev wlan1-D- table 16802 scope link
[2026-11-04T20:59:21.000000] default via 192.168.1.1 dev wlan1-D- table 16802
[2026-11-04T20:59:21.000000] 17: wlan1-D- inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan1-D-
[2026-11-04T20:59:40.000000] 192.168.1.32 dev wlan1-D- table 16802 scope link
[2026-11-04T20:59:40.000000] 192.168.1.32 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T20:59:42.000000] 192.168.1.110 dev wlan1-D- table 16802 scope link
[2026-11-04T20:59:42.000000] 192.168.1.110 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T20:59:45.000000] 192.168.1.3 dev wlan1-D- table 16802 scope link
[2026-11-04T20:59:45.000000] 192.168.1.3 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T21:00:03.000000] 192.168.1.100 dev wlan1-D- table 16802 scope link
[2026-11-04T21:00:03.000000] 192.168.1.100 dev wlan1-D- table 16800 scope link src 192.168.1.5
--- DHCP on wlan1-D- (tcpdump -e -tttt)
2026-11-04 20:59:21.374914 22:97:27:b8:xx:xx > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 342: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 22:97:27:b8:xx:xx, length 300
2026-11-04 20:59:21.377153 94:83:c4:a7:xx:xx > 22:97:27:b8:xx:xx, ethertype IPv4 (0x0800), length 365: 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply, length 323
2026-11-04 20:59:21.474969 22:97:27:b8:xx:xx > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 342: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 22:97:27:b8:xx:xx, length 300
2026-11-04 20:59:21.477097 94:83:c4:a7:xx:xx > 22:97:27:b8:xx:xx, ethertype IPv4 (0x0800), length 365: 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply, length 323
--- table 16800 after (60 s after reassociation)
192.168.1.3 dev wlan1-D- scope link src 192.168.1.5
192.168.1.32 dev wlan1-D- scope link src 192.168.1.5
192.168.1.100 dev wlan1-D- scope link src 192.168.1.5
192.168.1.110 dev wlan1-D- scope link src 192.168.1.5
--- table 16802 after
default via 192.168.1.1 dev wlan1-D-
192.168.1.1 dev wlan1-D- scope link
192.168.1.3 dev wlan1-D- scope link
192.168.1.32 dev wlan1-D- scope link
192.168.1.100 dev wlan1-D- scope link
192.168.1.110 dev wlan1-D- scope link
--- ip route get 192.168.1.1
192.168.1.1 dev br-lan src 192.168.1.245 uid 0
--- upstream router pings device
routeur -> pont : muet
Evidence: Attempt 3
=== Attempt 3
--- table 16800 before
default via 192.168.1.1 dev wlan1-D- src 192.168.1.5
192.168.1.1 dev wlan1-D- scope link src 192.168.1.5
192.168.1.3 dev wlan1-D- scope link src 192.168.1.5
192.168.1.32 dev wlan1-D- scope link src 192.168.1.5
192.168.1.100 dev wlan1-D- scope link src 192.168.1.5
192.168.1.110 dev wlan1-D- scope link src 192.168.1.5
--- ip -ts monitor route address (address and gateway events)
[2026-11-04T21:01:07.000000] Deleted 17: wlan1-D- inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan1-D-
[2026-11-04T21:02:24.000000] 192.168.1.1 dev wlan1-D- table 16802 scope link
[2026-11-04T21:02:24.000000] default via 192.168.1.1 dev wlan1-D- table 16802
[2026-11-04T21:02:24.000000] 17: wlan1-D- inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan1-D-
[2026-11-04T21:02:25.000000] 192.168.1.100 dev wlan1-D- table 16802 scope link
[2026-11-04T21:02:25.000000] 192.168.1.100 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T21:02:45.000000] 192.168.1.3 dev wlan1-D- table 16802 scope link
[2026-11-04T21:02:45.000000] 192.168.1.3 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T21:02:54.000000] 192.168.1.181 dev wlan1-D- table 16802 scope link
[2026-11-04T21:02:54.000000] 192.168.1.181 dev wlan1-D- table 16800 scope link src 192.168.1.5
[2026-11-04T21:03:18.000000] 192.168.1.110 dev wlan1-D- table 16802 scope link
[2026-11-04T21:03:18.000000] 192.168.1.110 dev wlan1-D- table 16800 scope link src 192.168.1.5
--- DHCP on wlan1-D- (tcpdump -e -tttt)
2026-11-04 21:02:24.574897 22:97:27:b8:xx:xx > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 342: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 22:97:27:b8:xx:xx, length 300
2026-11-04 21:02:24.577151 94:83:c4:a7:xx:xx > 22:97:27:b8:xx:xx, ethertype IPv4 (0x0800), length 365: 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply, length 323
2026-11-04 21:02:24.684903 22:97:27:b8:xx:xx > ff:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 342: 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 22:97:27:b8:xx:xx, length 300
2026-11-04 21:02:24.687532 94:83:c4:a7:xx:xx > 22:97:27:b8:xx:xx, ethertype IPv4 (0x0800), length 365: 192.168.1.1.67 > 192.168.1.5.68: BOOTP/DHCP, Reply, length 323
--- table 16800 after (60 s after reassociation)
192.168.1.3 dev wlan1-D- scope link src 192.168.1.5
192.168.1.100 dev wlan1-D- scope link src 192.168.1.5
192.168.1.110 dev wlan1-D- scope link src 192.168.1.5
192.168.1.181 dev wlan1-D- scope link src 192.168.1.5
--- table 16802 after
default via 192.168.1.1 dev wlan1-D-
192.168.1.1 dev wlan1-D- scope link
192.168.1.3 dev wlan1-D- scope link
192.168.1.100 dev wlan1-D- scope link
192.168.1.110 dev wlan1-D- scope link
192.168.1.181 dev wlan1-D- scope link
--- ip route get 192.168.1.1
192.168.1.1 dev br-lan src 192.168.1.245 uid 0
--- upstream router pings device
routeur -> pont : muet