diff options
author | Christian Breunig <christian@breunig.cc> | 2024-12-08 08:34:41 +0100 |
---|---|---|
committer | Christian Breunig <christian@breunig.cc> | 2024-12-16 22:24:36 +0100 |
commit | 3c79477adf3cd4f4efb302b58542ddd668b562ac (patch) | |
tree | 316d03a81f1c9c37b48b658af7826eaf11413130 /src/conf_mode/protocols_segment-routing.py | |
parent | 328f354677a4fd2f60b95473698816e99aaa20a7 (diff) | |
download | vyos-1x-3c79477adf3cd4f4efb302b58542ddd668b562ac.tar.gz vyos-1x-3c79477adf3cd4f4efb302b58542ddd668b562ac.zip |
frr: T6747: migrate protocols to unified FRRender class
With FRR 10.0 daemons started to be migrated to integrated FRR mgmtd and a
northbound interface. This led to some drawbacks in the current state how
changes to FRR are handled. The current implementation will use frr-reload.py
and specifies excatly WHICH daemon needs a config update and will only replace
this part inside FRR.
With FRR10 and mgmtd when a partial configuration is sent to mgmtd, it will
remove configuration parts from other daemons like bgpd or ospfd which have
not yet been migrated to mgmtd.
It's not possible to call frr-reload.py with daemon mgmtd - it will error out.
This commit will also change the CLI for static routes:
CLI command "set protocols static route 10.0.0.0/8 next-hop 1.2.3.4 bfd multi-hop
source 1.1.1.1" will be split into:
* set protocols static route 10.0.0.0/8 next-hop 1.2.3.4 bfd source-address 1.1.1.1
* set protocols static route 10.0.0.0/8 next-hop 1.2.3.4 bfd multi-hop
To make the XML blocks reusable, and comply with the FRR CLI - this was actually
a wrong implementation from the beginning as you can not have multiple BFD
source addresses.
CLI command "set protocols static route 10.0.0.0/8 next-hop 1.2.3.4 bfd multi-hop
source 1.1.1.1 profile bar" is changed to:
* set protocols static route 10.0.0.0/8 next-hop 1.2.3.4 bfd profile bar
CLI commands "set protocols static multicast interface-route" is moved to:
* set protocols static multicast route <x.x.x.x/x> interface
To have an identical look and feel with regular static routes.
Diffstat (limited to 'src/conf_mode/protocols_segment-routing.py')
-rwxr-xr-x | src/conf_mode/protocols_segment-routing.py | 92 |
1 files changed, 40 insertions, 52 deletions
diff --git a/src/conf_mode/protocols_segment-routing.py b/src/conf_mode/protocols_segment-routing.py index 67f8005ef..0fad968e1 100755 --- a/src/conf_mode/protocols_segment-routing.py +++ b/src/conf_mode/protocols_segment-routing.py @@ -17,14 +17,17 @@ from sys import exit from vyos.config import Config -from vyos.configdict import node_changed -from vyos.template import render_to_string +from vyos.configdict import get_frrender_dict +from vyos.configdict import list_diff +from vyos.configverify import has_frr_protocol_in_dict +from vyos.frrender import FRRender +from vyos.ifconfig import Section from vyos.utils.dict import dict_search from vyos.utils.system import sysctl_write from vyos import ConfigError -from vyos import frr from vyos import airbag airbag.enable() +frrender = FRRender() def get_config(config=None): if config: @@ -32,25 +35,14 @@ def get_config(config=None): else: conf = Config() - base = ['protocols', 'segment-routing'] - sr = conf.get_config_dict(base, key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True, - with_recursive_defaults=True) + return get_frrender_dict(conf) - # FRR has VRF support for different routing daemons. As interfaces belong - # to VRFs - or the global VRF, we need to check for changed interfaces so - # that they will be properly rendered for the FRR config. Also this eases - # removal of interfaces from the running configuration. - interfaces_removed = node_changed(conf, base + ['interface']) - if interfaces_removed: - sr['interface_removed'] = list(interfaces_removed) +def verify(config_dict): + if not has_frr_protocol_in_dict(config_dict, 'segment_routing'): + return None - import pprint - pprint.pprint(sr) - return sr + sr = config_dict['segment_routing'] -def verify(sr): if 'srv6' in sr: srv6_enable = False if 'interface' in sr: @@ -62,45 +54,41 @@ def verify(sr): raise ConfigError('SRv6 should be enabled on at least one interface!') return None -def generate(sr): - if not sr: +def generate(config_dict): + frrender.generate(config_dict) + return None + +def apply(config_dict): + if not has_frr_protocol_in_dict(config_dict, 'segment_routing'): return None - sr['new_frr_config'] = render_to_string('frr/zebra.segment_routing.frr.j2', sr) - return None + sr = config_dict['segment_routing'] -def apply(sr): - if 'interface_removed' in sr: - for interface in sr['interface_removed']: - # Disable processing of IPv6-SR packets - sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '0') + current_interfaces = Section.interfaces() + sr_interfaces = list(sr.get('interface', {}).keys()) - if 'interface' in sr: - for interface, interface_config in sr['interface'].items(): - # Accept or drop SR-enabled IPv6 packets on this interface - if 'srv6' in interface_config: - sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '1') - # Define HMAC policy for ingress SR-enabled packets on this interface - # It's a redundant check as HMAC has a default value - but better safe - # then sorry - tmp = dict_search('srv6.hmac', interface_config) - if tmp == 'accept': - sysctl_write(f'net.ipv6.conf.{interface}.seg6_require_hmac', '0') - elif tmp == 'drop': - sysctl_write(f'net.ipv6.conf.{interface}.seg6_require_hmac', '1') - elif tmp == 'ignore': - sysctl_write(f'net.ipv6.conf.{interface}.seg6_require_hmac', '-1') - else: - sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '0') + for interface in list_diff(current_interfaces, sr_interfaces): + # Disable processing of IPv6-SR packets + sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '0') - # Save original configuration prior to starting any commit actions - frr_cfg = frr.FRRConfig() - frr_cfg.load_configuration(frr.zebra_daemon) - frr_cfg.modify_section(r'^segment-routing') - if 'new_frr_config' in sr: - frr_cfg.add_before(frr.default_add_before, sr['new_frr_config']) - frr_cfg.commit_configuration(frr.zebra_daemon) + for interface, interface_config in sr.get('interface', {}).items(): + # Accept or drop SR-enabled IPv6 packets on this interface + if 'srv6' in interface_config: + sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '1') + # Define HMAC policy for ingress SR-enabled packets on this interface + # It's a redundant check as HMAC has a default value - but better safe + # then sorry + tmp = dict_search('srv6.hmac', interface_config) + if tmp == 'accept': + sysctl_write(f'net.ipv6.conf.{interface}.seg6_require_hmac', '0') + elif tmp == 'drop': + sysctl_write(f'net.ipv6.conf.{interface}.seg6_require_hmac', '1') + elif tmp == 'ignore': + sysctl_write(f'net.ipv6.conf.{interface}.seg6_require_hmac', '-1') + else: + sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '0') + frrender.apply() return None if __name__ == '__main__': |