diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-10-07 19:59:13 +0200 |
|---|---|---|
| committer | Christian Breunig <christian@breunig.cc> | 2026-10-07 19:59:13 +0200 |
| commit | c8d75f88f078c8c2c2a1f6a9a62c937424279d4b (patch) | |
| tree | 2b3cf67a9a08b1daadf30806f49471294715abdf /python | |
| parent | fff4e828d2a7ec1549ca20db30906ff47396e374 (diff) | |
| download | vyos-1x-c8d75f88f078c8c2c2a1f6a9a62c937424279d4b.tar.gz vyos-1x-c8d75f88f078c8c2c2a1f6a9a62c937424279d4b.zip | |
frrender: T9368: reconcile FRR after a DHCP lease without the commit socket
Reconciling the FRR configuration after a DHCP lease event was requested from
the configuration daemon over the socket the commit pipeline uses. The daemon
serves one client at a time and assumes it is the running commit, so
the request either landed in the middle of the handshake which hands over the
configuration, or kept the daemon busy past the 10ms a commit waits for it.
Either way the commit fell back to running the conf-mode scripts directly.
Those never render FRR, only the daemon does, so the commit succeeded while FRR
kept the configuration rendered before it, until the next lease event.
A lease event now renders FRR in its own process, and a commit which could not
use the daemon renders FRR itself instead of skipping the reload. Both take the
same lock. A commit post-hook would remove the second case, for a full render
on every commit.
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/frrender.py | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/python/vyos/frrender.py b/python/vyos/frrender.py index eac03e4d3..371ea95b5 100644 --- a/python/vyos/frrender.py +++ b/python/vyos/frrender.py @@ -21,8 +21,10 @@ frr-reload.py, if the configuration has no errors. Will fail early if the rendered configuration has any errors. """ +import fcntl import os +from contextlib import contextmanager from copy import deepcopy from time import sleep @@ -33,6 +35,7 @@ from vyos.configdict import get_pppoe_interfaces from vyos.defaults import frr_debug_enable from vyos.utils.dict import dict_search from vyos.utils.dict import dict_set_nested +from vyos.utils.file import read_file from vyos.utils.file import write_file from vyos.utils.process import rc_cmd from vyos.template import get_dhcp_router @@ -44,6 +47,21 @@ def debug(message): return print(message) +frr_config_file: str = '/run/frr/config/vyos.frr.conf' +# Configuration of the last successful reload, for consumers which have no +# cached configuration of their own +frr_applied_config_file: str = '/run/frr/config/vyos.frr.applied.conf' +frr_render_lock_file: str = '/run/vyos-frr-render.lock' + +@contextmanager +def frr_render_lock(): + """Serialize everything which renders FRR. The rendered configuration is a + single file handed to frr-reload.py, so a second renderer would rewrite it + while FRR is being reloaded from it.""" + with open(frr_render_lock_file, 'w') as lock_file: + fcntl.lockf(lock_file, fcntl.LOCK_EX) + yield + ERROR_RELOAD_TEST: str = 'The system encountered an error while rendering the ' \ 'new routing daemon configuration. To ensure network stability and avoid ' \ 'potential connectivity disruptions, the configuration was not applied!' @@ -747,7 +765,7 @@ class FRRender: cached_config_dict = {} cached_dhcp_gateways = {} def __init__(self): - self._frr_conf = '/run/frr/config/vyos.frr.conf' + self._frr_conf = frr_config_file def generate(self, config_dict) -> None: """ @@ -935,6 +953,8 @@ class FRRender: if count >= count_max: raise ConfigError(emsg) + write_file(frr_applied_config_file, read_file(self._frr_conf)) + # frr-reload.py --reload has already saved the configuration to # /etc/frr/frr.conf (bind-mounted from /run/frr/config/frr.conf): it # does so whenever it is not run with --daemon. T3217 added a second |
