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_bgp.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_bgp.py')
| -rwxr-xr-x | src/conf_mode/protocols_bgp.py | 136 |
1 files changed, 29 insertions, 107 deletions
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index e5c46aee6..989cf9b5c 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -19,92 +19,35 @@ from sys import argv from vyos.base import Warning from vyos.config import Config -from vyos.configdict import dict_merge -from vyos.configdict import node_changed +from vyos.configdict import get_frrender_dict +from vyos.configverify import has_frr_protocol_in_dict from vyos.configverify import verify_prefix_list from vyos.configverify import verify_route_map from vyos.configverify import verify_vrf +from vyos.frrender import FRRender from vyos.template import is_ip from vyos.template import is_interface -from vyos.template import render_to_string from vyos.utils.dict import dict_search from vyos.utils.network import get_interface_vrf from vyos.utils.network import is_addr_assigned from vyos.utils.process import process_named_running -from vyos.utils.process import call from vyos import ConfigError -from vyos import frr from vyos import airbag airbag.enable() +frrender = FRRender() + +vrf = None +if len(argv) > 1: + vrf = argv[1] + def get_config(config=None): if config: conf = config else: conf = Config() - vrf = None - if len(argv) > 1: - vrf = argv[1] - - base_path = ['protocols', 'bgp'] - - # eqivalent of the C foo ? 'a' : 'b' statement - base = vrf and ['vrf', 'name', vrf, 'protocols', 'bgp'] or base_path - bgp = conf.get_config_dict(base, key_mangling=('-', '_'), - get_first_key=True, no_tag_node_value_mangle=True) - - bgp['dependent_vrfs'] = conf.get_config_dict(['vrf', 'name'], - key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True) - - # Remove per interface MPLS configuration - get a list if changed - # nodes under the interface tagNode - interfaces_removed = node_changed(conf, base + ['interface']) - if interfaces_removed: - bgp['interface_removed'] = list(interfaces_removed) - - # Assign the name of our VRF context. This MUST be done before the return - # statement below, else on deletion we will delete the default instance - # instead of the VRF instance. - if vrf: - bgp.update({'vrf' : vrf}) - # We can not delete the BGP VRF instance if there is a L3VNI configured - # FRR L3VNI must be deleted first otherwise we will see error: - # "FRR error: Please unconfigure l3vni 3000" - tmp = ['vrf', 'name', vrf, 'vni'] - if conf.exists_effective(tmp): - bgp.update({'vni' : conf.return_effective_value(tmp)}) - # We can safely delete ourself from the dependent vrf list - if vrf in bgp['dependent_vrfs']: - del bgp['dependent_vrfs'][vrf] - - bgp['dependent_vrfs'].update({'default': {'protocols': { - 'bgp': conf.get_config_dict(base_path, key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True)}}}) - - if not conf.exists(base): - # If bgp instance is deleted then mark it - bgp.update({'deleted' : ''}) - return bgp - - # We have gathered the dict representation of the CLI, but there are default - # options which we need to update into the dictionary retrived. - bgp = conf.merge_defaults(bgp, recursive=True) - - # We also need some additional information from the config, prefix-lists - # and route-maps for instance. They will be used in verify(). - # - # XXX: one MUST always call this without the key_mangling() option! See - # vyos.configverify.verify_common_route_maps() for more information. - tmp = conf.get_config_dict(['policy']) - # Merge policy dict into "regular" config dict - bgp = dict_merge(tmp, bgp) - - return bgp - + return get_frrender_dict(conf) def verify_vrf_as_import(search_vrf_name: str, afi_name: str, vrfs_config: dict) -> bool: """ @@ -237,7 +180,18 @@ def verify_afi(peer_config, bgp_config): if tmp: return True return False -def verify(bgp): +def verify(config_dict): + global vrf + if not has_frr_protocol_in_dict(config_dict, 'bgp', vrf): + return None + + # eqivalent of the C foo ? 'a' : 'b' statement + bgp = vrf and config_dict['vrf']['name'][vrf]['protocols']['bgp'] or config_dict['bgp'] + bgp['policy'] = config_dict['policy'] + + if vrf: + bgp['vrf'] = vrf + if 'deleted' in bgp: if 'vrf' in bgp: # Cannot delete vrf if it exists in import vrf list in other vrfs @@ -252,8 +206,9 @@ def verify(bgp): for vrf, vrf_options in bgp['dependent_vrfs'].items(): if vrf != 'default': if dict_search('protocols.bgp', vrf_options): - raise ConfigError('Cannot delete default BGP instance, ' \ - 'dependent VRF instance(s) exist(s)!') + dependent_vrfs = ', '.join(bgp['dependent_vrfs'].keys()) + raise ConfigError(f'Cannot delete default BGP instance, ' \ + f'dependent VRF instance(s): {dependent_vrfs}') if 'vni' in vrf_options: raise ConfigError('Cannot delete default BGP instance, ' \ 'dependent L3VNI exists!') @@ -602,44 +557,11 @@ def verify(bgp): return None -def generate(bgp): - if not bgp or 'deleted' in bgp: - return None - - bgp['frr_bgpd_config'] = render_to_string('frr/bgpd.frr.j2', bgp) - return None - -def apply(bgp): - if 'deleted' in bgp: - # We need to ensure that the L3VNI is deleted first. - # This is not possible with old config backend - # priority bug - if {'vrf', 'vni'} <= set(bgp): - call('vtysh -c "conf t" -c "vrf {vrf}" -c "no vni {vni}"'.format(**bgp)) - - # Save original configuration prior to starting any commit actions - frr_cfg = frr.FRRConfig() - - # Generate empty helper string which can be ammended to FRR commands, it - # will be either empty (default VRF) or contain the "vrf <name" statement - vrf = '' - if 'vrf' in bgp: - vrf = ' vrf ' + bgp['vrf'] - - frr_cfg.load_configuration(frr.bgp_daemon) - - # Remove interface specific config - for key in ['interface', 'interface_removed']: - if key not in bgp: - continue - for interface in bgp[key]: - frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True) - - frr_cfg.modify_section(f'^router bgp \d+{vrf}', stop_pattern='^exit', remove_stop_mark=True) - if 'frr_bgpd_config' in bgp: - frr_cfg.add_before(frr.default_add_before, bgp['frr_bgpd_config']) - frr_cfg.commit_configuration(frr.bgp_daemon) +def generate(config_dict): + frrender.generate(config_dict) +def apply(config_dict): + frrender.apply() return None if __name__ == '__main__': |
