From cedf7ecfb6048cce1082d234f9d859f955b0c2cd Mon Sep 17 00:00:00 2001 From: aapostoliuk Date: Tue, 11 Jul 2023 17:04:02 +0300 Subject: bgp: T5338: Added 'protocols bgp interface mpls forwarding' feature Added 'protocols bgp interface mpls forwarding' feature. It is possible to permit BGP install VPN prefixes without transport labels. This configuration will install VPN prefixes originated from an e-bgp session, and with the next-hop directly connected. --- data/templates/frr/bgpd.frr.j2 | 10 +++++ .../include/bgp/protocol-common-config.xml.i | 30 +++++++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 36 +++++++++++++++++- src/conf_mode/protocols_bgp.py | 43 +++++++++++++++++++++- 4 files changed, 117 insertions(+), 2 deletions(-) diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2 index 3e101820c..9cfc8b7cd 100644 --- a/data/templates/frr/bgpd.frr.j2 +++ b/data/templates/frr/bgpd.frr.j2 @@ -565,3 +565,13 @@ bgp route-reflector allow-outbound-policy timers bgp {{ timers.keepalive }} {{ timers.holdtime }} {% endif %} exit +{% if interface is vyos_defined %} +{% for iface, iface_config in interface.items() %} + interface {{ iface }} +{% if iface_config.mpls.forwarding is vyos_defined %} + mpls bgp forwarding +{% endif %} + exit + ! +{% endfor %} +{% endif %} diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index d69fd7dab..f95031a75 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -873,6 +873,36 @@ + + + Enable MPLS on Interface + + + + + txt + Interface name + + + #include + + + + + + MPLS options + + + + + Enable MPLS forwarding for eBGP directly connected peers + + + + + + + Listen for and accept BGP dynamic neighbors from range diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 2fd5d0c9b..f4801486a 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # 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 @@ -18,6 +18,7 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.ifconfig import Section from vyos.configsession import ConfigSessionError from vyos.template import is_ipv6 from vyos.util import process_named_running @@ -1072,5 +1073,38 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): with self.assertRaises(ConfigSessionError): self.cli_commit() + def test_bgp_22_interface_mpls_forwarding(self): + interfaces = Section.interfaces('ethernet') + self.cli_set(base_path + ['system-as', ASN]) + for interface in interfaces: + self.cli_set( + base_path + ['interface', interface, 'mpls', 'forwarding']) + self.cli_commit() + + for interface in interfaces: + frrconfig = self.getFRRconfig(f'interface {interface}') + self.assertIn(f'interface {interface}', frrconfig) + self.assertIn(f' mpls bgp forwarding', frrconfig) + + def test_bgp_23_vrf_interface_mpls_forwarding(self): + self.create_bgp_instances_for_import_test() + interfaces = Section.interfaces('ethernet') + for interface in interfaces: + self.cli_set( + ['interfaces', 'ethernet', interface, 'vrf', import_vrf]) + self.cli_set( + import_vrf_base + [import_vrf] + base_path + ['interface', + interface, + 'mpls', + 'forwarding']) + self.cli_commit() + + for interface in interfaces: + frrconfig = self.getFRRconfig(f'interface {interface}') + self.assertIn(f'interface {interface}', frrconfig) + self.assertIn(f' mpls bgp forwarding', frrconfig) + self.cli_delete(['interfaces', 'ethernet', interface, 'vrf']) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index b23584bdb..532970735 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2022 VyOS maintainers and contributors +# Copyright (C) 2020-2023 VyOS maintainers and contributors # # 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 @@ -20,6 +20,7 @@ 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.configverify import verify_prefix_list from vyos.configverify import verify_route_map from vyos.configverify import verify_vrf @@ -27,6 +28,7 @@ from vyos.template import is_ip from vyos.template import is_interface from vyos.template import render_to_string from vyos.util import dict_search +from vyos.util import get_interface_config from vyos.validate import is_addr_assigned from vyos import ConfigError from vyos import frr @@ -54,6 +56,20 @@ def get_config(config=None): key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) + # if config removed + interfaces_removed = node_changed(conf, base + ['interface']) + if interfaces_removed: + bgp['interface_removed'] = list(interfaces_removed) + # Add vrf mapping in + if 'interface' in bgp: + for interface in bgp['interface']: + tmp = get_interface_config(interface) + if dict_search('linkinfo.info_slave_kind', tmp) and \ + tmp['linkinfo']['info_slave_kind'] == 'vrf': + if 'master' in tmp: + bgp['interface'][interface]['applied_vrf'] = tmp['master'] + else: + bgp['interface'][interface]['applied_vrf'] = 'default' # 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 @@ -231,6 +247,23 @@ def verify(bgp): if 'system_as' not in bgp: raise ConfigError('BGP system-as number must be defined!') + # Verify vrf on interface and bgp section + if 'interface' in bgp: + for interface in dict_search('interface', bgp): + if dict_search(f'interface.{interface}.mpls', bgp): + if 'forwarding' in bgp['interface'][interface]['mpls']: + if 'vrf' in bgp: + if bgp['interface'][interface]['applied_vrf'] != bgp['vrf']: + raise ConfigError( + f'Can not set mpls forwarding. Interface {interface} in different vrf') + else: + if bgp['interface'][interface]['applied_vrf'] != 'default': + raise ConfigError( + f'Can not set mpls forwarding. Interface {interface} in different vrf') + else: + raise ConfigError( + f' command should have options') + # Common verification for both peer-group and neighbor statements for neighbor in ['neighbor', 'peer_group']: # bail out early if there is no neighbor or peer-group statement @@ -520,6 +553,14 @@ def apply(bgp): vrf = ' vrf ' + bgp['vrf'] frr_cfg.load_configuration(bgp_daemon) + + #If bgp interface config removed + 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']) -- cgit v1.2.3