summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2026-09-04 22:14:45 +0200
committerChristian Breunig <christian@breunig.cc>2026-09-04 22:14:45 +0200
commit9a7d5b27cd908473b7cd9e16fc0d1bbe7e983d2e (patch)
treed055f72a3e7cdd44832f4f5981f654578554f11d /src
parent16f1cf4579e3c1bf3a2639d54c6ae9e1ef163259 (diff)
downloadvyos-1x-9a7d5b27cd908473b7cd9e16fc0d1bbe7e983d2e.tar.gz
vyos-1x-9a7d5b27cd908473b7cd9e16fc0d1bbe7e983d2e.zip
static: T9278: reconcile FRR config after every DHCP lease event
The default route derived from "interfaces <type> <ifname> address dhcp" is rendered from the DHCP lease file, so it is only known at lease time. Until now the sole runtime path into staticd was the one-shot vtysh injection in dhclient-enter-hooks.d/03-vyos-ipwrapper. That injection races the FRR reload of the very commit which started the DHCP client: dhclient runs with "-nw", thus the commit does not wait for a lease, and when BOUND arrives mid-reload frr_alive() can report FRR as down. The route is then installed into the kernel only and FRR never learns about it. Nothing recovers afterwards, as FRRender.generate() short-circuits on an unchanged configuration dict. The self-healing re-render used by "protocols static route <prefix> dhcp-interface" was gated on /tmp/static_dhcp_interfaces, which never lists plain "address dhcp" interfaces - protocols_static.py does not even run on an interface-only commit, as no config-mode dependency points to it. Derive the DHCP dependent interface list from the configuration dict itself, both for the default VRF and for every named VRF, and use it for FRR change detection. Drop the interface list gate in the dhclient exit hook so any lease event requests a re-render. Also poll for the lease and for the rendered route in the affected smoketests instead of relying on a fixed sleep.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/protocols_static.py15
-rwxr-xr-xsrc/etc/dhcp/dhclient-exit-hooks.d/98-vyos-static-routes-dhclient-hook11
2 files changed, 11 insertions, 15 deletions
diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py
index 0f3f735a7..7d2b4949e 100755
--- a/src/conf_mode/protocols_static.py
+++ b/src/conf_mode/protocols_static.py
@@ -24,6 +24,7 @@ from vyos.configverify import has_frr_protocol_in_dict
from vyos.configverify import verify_common_route_maps
from vyos.configverify import verify_vrf
from vyos.frrender import FRRender
+from vyos.frrender import get_dhcp_route_interfaces
from vyos.frrender import get_frrender_dict
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
@@ -99,15 +100,11 @@ def generate(config_dict):
static = vrf and dict_search(f'vrf.name.{vrf}.protocols.static',
config_dict) or config_dict['static']
- # Collect interfaces that have DHCP configuration for DHCP hooks
- dhcp_interfaces = set()
-
- # Check for DHCP interfaces in route configurations
- if 'route' in static:
- for prefix, prefix_options in static['route'].items():
- if 'dhcp_interface' in prefix_options:
- for interface_name in prefix_options['dhcp_interface']:
- dhcp_interfaces.add(interface_name)
+ # Collect interfaces that have DHCP configuration for DHCP hooks. This must
+ # be derived from the entire config_dict and not from the (possibly
+ # VRF-narrowed) static dict above, as DHCP_HOOK_IFLIST is a single global
+ # file - a per VRF invocation would otherwise clobber the list.
+ dhcp_interfaces = get_dhcp_route_interfaces(config_dict)
# Write the interface list for DHCP hooks or clean up if empty
if dhcp_interfaces:
diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/98-vyos-static-routes-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/98-vyos-static-routes-dhclient-hook
index 7038bf25e..4f207411e 100755
--- a/src/etc/dhcp/dhclient-exit-hooks.d/98-vyos-static-routes-dhclient-hook
+++ b/src/etc/dhcp/dhclient-exit-hooks.d/98-vyos-static-routes-dhclient-hook
@@ -14,12 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-DHCP_HOOK_IFLIST="/tmp/static_dhcp_interfaces"
-
-# Only run if there are static routes with dhcp-interface configured
-if ! { [ -f $DHCP_HOOK_IFLIST ] && grep -qw $interface $DHCP_HOOK_IFLIST; }; then
- return 0
-fi
+# The FRR static route configuration embeds the DHCP gateway of an interface,
+# either for "protocols static route <prefix> dhcp-interface <ifname>" or for
+# the default route implied by "interfaces <type> <ifname> address dhcp". The
+# gateway is only known at lease time, so any lease event must reconcile the
+# rendered configuration with the current lease (T8465).
# Re-generate the config on the following events:
# - BOUND: always re-generate