diff options
| author | Daniil Baturin <daniil@vyos.io> | 2025-09-23 16:01:35 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-23 16:01:35 +0100 |
| commit | bf1c29aa71980158a4e820d69351660e863cf219 (patch) | |
| tree | faec0ae12b342add260633086e6b3c51262a9504 /src | |
| parent | 9952d21aa35fd40fe583de1ac20287a6784e8052 (diff) | |
| parent | 85fe32f0e1a91a47fe4a6d4a5cdd6ac516dcc3b9 (diff) | |
| download | vyos-1x-bf1c29aa71980158a4e820d69351660e863cf219.tar.gz vyos-1x-bf1c29aa71980158a4e820d69351660e863cf219.zip | |
Merge pull request #4684 from c-po/bgp-vrf-system-as
bgp: T7760: remove per vrf instance system-as node
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/protocols_bgp.py | 26 | ||||
| -rw-r--r-- | src/migration-scripts/bgp/6-to-7 | 108 | ||||
| -rw-r--r-- | src/migration-scripts/bgp/7-to-8 | 30 |
3 files changed, 154 insertions, 10 deletions
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index fe5740a18..4e7f09d0e 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -210,8 +210,20 @@ def verify(config_dict): return None - if 'system_as' not in bgp: - raise ConfigError('BGP system-as number must be defined!') + ERR_MSG_GLOBAL_VRF_AS_MISSING = 'BGP "system-as" number must be defined! Use "set protocols ' \ + 'bgp system-as <asn>" to define a global BGP instance AS number.' + system_as = None + if vrf: + system_as = dict_search('dependent_vrfs.default.protocols.bgp.system_as', bgp) + if not system_as: + raise ConfigError(ERR_MSG_GLOBAL_VRF_AS_MISSING) + + elif 'system_as' not in bgp: + raise ConfigError(ERR_MSG_GLOBAL_VRF_AS_MISSING) + + # Cache global defined system AS number used in further checks + if not system_as: + system_as = bgp['system_as'] # Verify BMP if 'bmp' in bgp: @@ -257,7 +269,7 @@ def verify(config_dict): if 'remote_as' in peer_config: is_ibgp = True if peer_config['remote_as'] != 'internal' and \ - peer_config['remote_as'] != bgp['system_as']: + peer_config['remote_as'] != system_as: is_ibgp = False if peer_group not in peer_groups_context: @@ -278,7 +290,7 @@ def verify(config_dict): # Neighbor local-as override can not be the same as the local-as # we use for this BGP instane! asn = list(peer_config['local_as'].keys())[0] - if asn == bgp['system_as']: + if asn == system_as: raise ConfigError('Cannot have local-as same as system-as number') # Neighbor AS specified for local-as and remote-as can not be the same @@ -369,12 +381,6 @@ def verify(config_dict): if 'source_interface' in peer_config['interface']: raise ConfigError(f'"source-interface" option not allowed for neighbor "{peer}"') - # Local-AS allowed only for EBGP peers - if 'local_as' in peer_config: - remote_as = verify_remote_as(peer_config, bgp) - if remote_as == bgp['system_as']: - raise ConfigError(f'local-as configured for "{peer}", allowed only for eBGP peers!') - for afi in ['ipv4_unicast', 'ipv4_multicast', 'ipv4_labeled_unicast', 'ipv4_flowspec', 'ipv6_unicast', 'ipv6_multicast', 'ipv6_labeled_unicast', 'ipv6_flowspec', 'l2vpn_evpn']: diff --git a/src/migration-scripts/bgp/6-to-7 b/src/migration-scripts/bgp/6-to-7 new file mode 100644 index 000000000..7a11bbf3a --- /dev/null +++ b/src/migration-scripts/bgp/6-to-7 @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# T7760: Remove per VRF setting for system-as option and replace it with +# local-as if required. + +from vyos.configtree import ConfigTree + +def migrate(config: ConfigTree) -> None: + vrf_base = ['vrf', 'name'] + bgp_base = ['protocols', 'bgp'] + + if not config.exists(vrf_base): + return + + global_asn = None + if config.exists(bgp_base + ['system-as']): + global_asn = config.return_value(bgp_base + ['system-as']) + + for vrf in config.list_nodes(vrf_base): + # bail out early if there is no per VRF BGP instance defined + vrf_bgp_base = vrf_base + [vrf] + bgp_base + if not config.exists(vrf_bgp_base): + continue + + # This is a mandatory node in the old design but keep it optional + # if one want's to load a weird config + if config.exists(vrf_bgp_base + ['system-as']): + system_as = config.return_value(vrf_bgp_base + ['system-as']) + config.delete(vrf_bgp_base + ['system-as']) + + # If there is no existing global BGP instance - start one + if not config.exists(bgp_base): + config.set(bgp_base + ['system-as'], value=system_as) + global_asn = system_as + + vrf_neighbor_base = vrf_bgp_base + ['neighbor'] + vrf_peer_group_base = vrf_bgp_base + ['peer-group'] + if config.exists(vrf_neighbor_base): + for neighbor in config.list_nodes(vrf_neighbor_base): + # Neighbor already has local-as option set, do not touch it + if config.exists(vrf_neighbor_base + [neighbor, 'local-as']): + #print(f'VRF {vrf} BGP neighbor {neighbor} has local-as set - do not migrate!') + continue + + # Check if the neighbor uses a peer-group which has the local-as + # option set, do not touch it either + peer_group = None + if config.exists(vrf_neighbor_base + [neighbor, 'peer-group']): + peer_group = config.return_value(vrf_neighbor_base + [neighbor, 'peer-group']) + # Check if the peer-group has a local-as option set + if config.exists(vrf_peer_group_base + [peer_group, 'local-as']): + #print(f'VRF {vrf} BGP neighbor {neighbor} uses peer-group {peer_group} which has local-as set - do not migrate!') + continue + + # BGP local-as option is only allowed for eBGP speakers + if global_asn == system_as: + continue + + config.set(vrf_neighbor_base + [neighbor, 'local-as', system_as, 'no-prepend', 'replace-as']) + config.set_tag(vrf_neighbor_base + [neighbor, 'local-as']) + + # We do also need to take care about BGP internas. When using local-as routes with our own AS + # previously in the path will get rejected: + # bgpd: x.x.x.x(Unknown) rcvd UPDATE about 192.0.2.0/24 IPv4 unicast -- DENIED due to: as-path contains our own AS; + # Set allowas-in option + allowas_in_numer = ['allowas-in', 'number'] + for afi in ['ipv4-labeled-unicast', 'ipv4-multicast', 'ipv4-unicast', 'ipv4-vpn', + 'ipv6-labeled-unicast', 'ipv6-multicast', 'ipv6-unicast', 'ipv6-vpn']: + afi_neighbor_base = vrf_neighbor_base + [neighbor, 'address-family', afi] + afi_peer_group_base = vrf_peer_group_base + [peer_group, 'address-family', afi] + + # No need to change anything on an AFI not in use + if not config.exists(afi_neighbor_base) and not config.exists(afi_peer_group_base): + continue + + allowas_in_value = 0 + print(neighbor, afi) + # Check if there is any allowas-in definition for a peer-group + if peer_group and config.exists(afi_peer_group_base + allowas_in_numer): + allowas_in_value = int(config.return_value(afi_peer_group_base + allowas_in_numer)) + #print(f'peer-group {peer_group} allowas-in for {afi} is {allowas_in_value}') + + # Per neighbor "allowas-in" definition takes higher precendence + if config.exists(afi_neighbor_base + allowas_in_numer): + allowas_in_value = int(config.return_value(afi_neighbor_base + allowas_in_numer)) + #print(f'neighbor {neighbor} allowas-in for {afi} is {allowas_in_value}') + + # Increment allowas-in by 1 as we now have one more entry + allowas_in_value += 1 + # Clip allowas-in to 10 - max supported by FRR platform + if allowas_in_value > 10: allowas_in_value = 10 + + # Set per neighbor allowas-in which always takes precedence over the peer-group definition + config.set(afi_neighbor_base + allowas_in_numer, value=allowas_in_value, replace=True) diff --git a/src/migration-scripts/bgp/7-to-8 b/src/migration-scripts/bgp/7-to-8 new file mode 100644 index 000000000..ced4f837e --- /dev/null +++ b/src/migration-scripts/bgp/7-to-8 @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# T7760: Remove per VRF setting for system-as option in VyOS 1.5 and onwards + +from vyos.configtree import ConfigTree + +def migrate(config: ConfigTree) -> None: + vrf_base = ['vrf', 'name'] + if not config.exists(vrf_base): + return + + for vrf in config.list_nodes(vrf_base): + # bail out early if there is no per VRF BGP instance defined + vrf_bgp_base = vrf_base + [vrf, 'protocols', 'bgp'] + if config.exists(vrf_bgp_base + ['system-as']): + config.delete(vrf_bgp_base + ['system-as']) |
