summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2026-10-31 11:10:19 +0100
committerChristian Breunig <christian@breunig.cc>2026-10-31 11:10:19 +0100
commit8338931cf435761c12e923d98b857d124e74ceab (patch)
treef70c86e52951ee5bd0bd263e661aaafcf11115e8 /python
parentb70baa6f8af260529d1db1330da246f309039908 (diff)
downloadvyos-1x-8338931cf435761c12e923d98b857d124e74ceab.tar.gz
vyos-1x-8338931cf435761c12e923d98b857d124e74ceab.zip
frrender: T9442: reload FRR when the rendered configuration was not applied
A failed reload only dropped the in-memory cache. The record of the configuration FRR runs still held the previous one, so the DHCP render helper skipped a return to it while FRR kept a part of the failed configuration. After a rejected reload test, the rendered file also kept the rejected configuration. Change detection now also requires the rendered file to match the applied one, and a failed reload removes that record. The next commit then renders and reloads FRR again, even when it returns to the previous configuration. A smoketest stops FRR during a commit and verifies that committing again brings the configuration into FRR.
Diffstat (limited to 'python')
-rw-r--r--python/vyos/frrender.py20
1 files changed, 13 insertions, 7 deletions
diff --git a/python/vyos/frrender.py b/python/vyos/frrender.py
index e4b8dc1ab..824342773 100644
--- a/python/vyos/frrender.py
+++ b/python/vyos/frrender.py
@@ -819,9 +819,14 @@ class FRRender:
# A render which did not reach apply() must not count as applied
self._pending = None
+ # The rendered file can differ from the one FRR runs although the
+ # configuration is unchanged: frr-reload.py rejected it, or a failed
+ # reload removed frr_applied_config_file (T9442)
if (
self.cached_config_dict == config_dict
and self.cached_dhcp_gateways == dhcp_gateways
+ and read_file(self._frr_conf, None)
+ == read_file(frr_applied_config_file, None)
):
debug('FRR: NO CHANGES DETECTED')
return False
@@ -936,7 +941,7 @@ class FRRender:
if 'protocols' not in vrf_config:
continue
- # Do not mutate config_dict in-place — it is also stored as
+ # Do not mutate config_dict in-place - apply() stores it as
# cached_config_dict and in-place mutation breaks change
# detection on the next commit (T7931).
protocols = {
@@ -962,6 +967,8 @@ class FRRender:
return True
def apply(self, count_max=5):
+ pending, self._pending = self._pending, None
+
# Do a config reload test
cmdline = f'/usr/lib/frr/frr-reload.py --test'
rc, emsg = rc_cmd(f'{cmdline} {self._frr_conf}')
@@ -990,10 +997,10 @@ class FRRender:
if not reloaded:
# frr-reload.py applies its changes through vtysh in several
# steps, FRR can be left with a part of the new configuration.
- # Forget the cached one, so that the next commit reloads FRR even
+ # Forget the applied one, so that the next commit reloads FRR even
# if it returns to the previously applied configuration.
- self.cached_config_dict = None
- self.cached_dhcp_gateways = {}
+ if os.path.exists(frr_applied_config_file):
+ os.unlink(frr_applied_config_file)
raise ConfigError(emsg)
write_file(frr_applied_config_file, read_file(self._frr_conf))
@@ -1008,6 +1015,5 @@ class FRRender:
# FRR runs the rendered configuration now, remember it for the change
# detection of generate()
- if self._pending is not None:
- self.cached_config_dict, self.cached_dhcp_gateways = self._pending
- self._pending = None
+ if pending is not None:
+ self.cached_config_dict, self.cached_dhcp_gateways = pending