Routes from DHCP option 121 are installed into FRR by the dhclient hooks but are not part of the generated FRR configuration, so frr-reload deletes them on the next commit that changes FRR config, including the boot-time config load. The DHCP default route is unaffected because T3680 rendered it into staticd.
Steps to reproduce
- Put the router on a DHCP server offering option 121 (RFC 3442) with at least one non-default route.
- Reboot, or issue any commit that changes the rendered FRR configuration.
- The non-default routes are gone. The default route remains.
Observed
The lease carries a default route via 192.168.0.1 and 192.168.42.0/24 via 192.168.0.250. Two identical entries, as the lease database accumulates them:
$ grep rfc3442 /run/dhclient/dhclient_eth0.leases option rfc3442-classless-static-routes 0,192,168,0,1,24,192,168,42,192,168,0,250; option rfc3442-classless-static-routes 0,192,168,0,1,24,192,168,42,192,168,0,250;
Both routes are injected by the dhclient hook during boot:
$ journalctl -b | grep 'Converted vtysh command' Aug 23 21:10:48 netman-gw dhclient-script-vyos[1803]: Converted vtysh command: "ip route 0.0.0.0/0 192.168.0.1 eth0 tag 210 210 " Aug 23 21:10:48 netman-gw dhclient-script-vyos[1803]: Converted vtysh command: "ip route 192.168.42.0/24 192.168.0.250 eth0 tag 210 210 "
Three minutes after that boot, only the default route is present:
$ ip -4 route show default nhid 6 via 192.168.0.1 dev eth0 proto static metric 20 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.136
The deletion lands about 1.1s after the injection, at the FRR re-read that follows the boot configuration load. FRR's own startup read is at 21:10:46, more than two seconds before the injection, so this is not a race with FRR starting:
$ journalctl -b -o short-precise | grep -E 'Converted vtysh command|Configuration Read in Took|configuration write completed' 21:10:46.511685 netman-gw watchfrr[1385]: [VTVCM-Y2NW3] Configuration Read in Took: 00:00:00 21:10:48.722653 netman-gw dhclient-script-vyos[1803]: Converted vtysh command: "ip route 0.0.0.0/0 192.168.0.1 eth0 tag 210 210 " 21:10:48.753596 netman-gw dhclient-script-vyos[1803]: Converted vtysh command: "ip route 192.168.42.0/24 192.168.0.250 eth0 tag 210 210 " 21:10:49.893743 netman-gw watchfrr[1385]: [VTVCM-Y2NW3] Configuration Read in Took: 00:00:00 21:10:49.915896 netman-gw watchfrr[1385]: [VTVCM-Y2NW3] Configuration Read in Took: 00:00:00 21:10:49.931548 netman-gw watchfrr[1385]: [WFP93-1D146] configuration write completed with exit code 0
Reproducible on demand, without rebooting. With the route present as the hook installed it, any commit that changes the rendered FRR configuration removes it:
$ vtysh -c 'show running-config' | grep 'ip route' ip route 0.0.0.0/0 192.168.0.1 eth0 tag 210 210 ip route 192.168.42.0/24 192.168.0.250 eth0 tag 210 210 $ configure # set protocols static route 10.97.0.0/24 next-hop 192.168.0.250 # commit # exit $ vtysh -c 'show running-config' | grep 'ip route' ip route 0.0.0.0/0 192.168.0.1 eth0 tag 210 210 ip route 10.97.0.0/24 192.168.0.250 $ ip -4 route show default nhid 6 via 192.168.0.1 dev eth0 proto static metric 20 10.97.0.0/24 nhid 10 via 192.168.0.250 dev eth0 proto static metric 20 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.136
A commit that does not change the rendered FRR configuration leaves the injected route alone, which is consistent with frr-reload's diff being what removes it.
Why the default route is unaffected
T3680 renders the DHCP default route into staticd.frr.j2, so frr-reload finds it in the intended configuration. The non-default routes carried in option 121 were never given the same treatment.