Static route loses interface tracking after birdc configure
Hello, On BIRD 3.3.2 a static route with an interface or neighbour next hop stops reacting to interface state after the first `birdc configure`. It is frozen at whatever state that reconfiguration evaluated and never moves again -- it neither withdraws when the interface goes down nor returns when it comes back -- until `birdc restart <proto>`. `configure soft` and `configure undo` behave the same, and `birdc reload` does not repair it. `check link` makes no difference either way. The attached reproducer, bird-repro-static-iface-tracking.sh, needs only root, iproute2 and an installed bird3, cleans up after itself, and marks any step whose result differs from expectation. On Debian's bird3 3.3.2-1~bpo13+1: BIRD version 3.3.2 fresh: iface up route=yes want=yes fresh: iface down route=no want=no fresh: iface up route=yes want=yes -- birdc configure, configuration unchanged -- after cfg: iface up route=yes want=yes after cfg: iface down route=yes want=no <-- MISMATCH after cfg: iface up route=yes want=yes -- birdc restart s1 -- after restart: down route=no want=no -- birdc configure, taken while the iface is DOWN -- still down route=no want=no then: iface up route=no want=yes <-- MISMATCH then: iface down route=no want=no The same script on the same machine, with BIRD= and BIRDC= pointing at Debian's bird2 2.17.5-0+deb13u1: BIRD version 2.17.5 fresh: iface up route=yes want=yes fresh: iface down route=no want=no fresh: iface up route=yes want=yes -- birdc configure, configuration unchanged -- after cfg: iface up route=yes want=yes after cfg: iface down route=no want=no after cfg: iface up route=yes want=yes -- birdc restart s1 -- after restart: down route=no want=no -- birdc configure, taken while the iface is DOWN -- still down route=no want=no then: iface up route=yes want=yes then: iface down route=no want=no Where it seems to come from: the dependency is the route chain hanging off the neighbour-cache entry. `static_reconfigure_rte()` calls `static_add_rte()`, which links the new route into `n->data`, and then `static_reset_rte()`, which sets `r2->neigh->data = NULL`. `neigh_find()` returns the same cached neighbour for an unchanged next hop, so the reset clears the chain the add has just built, and `static_neigh_notify()` then walks an empty list. That came in with commit eb6918e4db57b7e5fabc531963deb46313289d80 ("Neighbor cache: fixed neighbor referencing"), which replaced a plain `r2->neigh = NULL;` in `static_reset_rte` with a block that also clears the shared `r2->neigh->data`, and added the matching `neigh_link()` in `static_add_rte`. The commit is not reachable from master, no v2 tag contains it, and the earliest release tag that does is v3.0.0 -- which matches bird2 passing the run above. Thanks, Dan
participants (1)
-
Danylo Mikula