diff options
author | Christian Breunig <christian@breunig.cc> | 2024-05-11 14:12:31 +0200 |
---|---|---|
committer | Christian Breunig <christian@breunig.cc> | 2024-05-11 14:12:31 +0200 |
commit | 5565f27d15c5e7378e94aae8db8a894a12e25d7b (patch) | |
tree | bb9c6da6753e1cb3f550595db5f6e7919036dbbf | |
parent | 7925402b487b93d1ae8dd4941e0981437f7fb951 (diff) | |
download | vyos-1x-5565f27d15c5e7378e94aae8db8a894a12e25d7b.tar.gz vyos-1x-5565f27d15c5e7378e94aae8db8a894a12e25d7b.zip |
ethernet: T6306: add support for EVPN MH uplink/core tracking
When all the underlay links go down the PE no longer has access to the VxLAN
+overlay.
To prevent blackholing of traffic the server/ES links are protodowned on the PE.
A link can be setup for uplink tracking via the following configuration:
set interfaces ethernet eth0 evpn uplink
-rw-r--r-- | interface-definitions/include/interface/evpn-mh-uplink.xml.i | 8 | ||||
-rw-r--r-- | interface-definitions/interfaces_bonding.xml.in | 7 | ||||
-rw-r--r-- | interface-definitions/interfaces_ethernet.xml.in | 8 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_ethernet.py | 10 | ||||
-rwxr-xr-x | src/conf_mode/interfaces_ethernet.py | 17 |
5 files changed, 44 insertions, 6 deletions
diff --git a/interface-definitions/include/interface/evpn-mh-uplink.xml.i b/interface-definitions/include/interface/evpn-mh-uplink.xml.i new file mode 100644 index 000000000..5f7fe1b7f --- /dev/null +++ b/interface-definitions/include/interface/evpn-mh-uplink.xml.i @@ -0,0 +1,8 @@ +<!-- include start from interface/evpn-mh-uplink.xml.i --> +<leafNode name="uplink"> + <properties> + <help>Uplink to the VXLAN core</help> + <valueless/> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/interfaces_bonding.xml.in b/interface-definitions/interfaces_bonding.xml.in index 92c0911db..d503760e6 100644 --- a/interface-definitions/interfaces_bonding.xml.in +++ b/interface-definitions/interfaces_bonding.xml.in @@ -102,12 +102,7 @@ </constraint> </properties> </leafNode> - <leafNode name="uplink"> - <properties> - <help>Uplink to the VXLAN core</help> - <valueless/> - </properties> - </leafNode> + #include <include/interface/evpn-mh-uplink.xml.i> </children> </node> <leafNode name="hash-policy"> diff --git a/interface-definitions/interfaces_ethernet.xml.in b/interface-definitions/interfaces_ethernet.xml.in index 4e55bac7c..89f990d41 100644 --- a/interface-definitions/interfaces_ethernet.xml.in +++ b/interface-definitions/interfaces_ethernet.xml.in @@ -57,6 +57,14 @@ <defaultValue>auto</defaultValue> </leafNode> #include <include/interface/eapol.xml.i> + <node name="evpn"> + <properties> + <help>EVPN Multihoming</help> + </properties> + <children> + #include <include/interface/evpn-mh-uplink.xml.i> + </children> + </node> #include <include/interface/hw-id.xml.i> #include <include/interface/ipv4-options.xml.i> #include <include/interface/ipv6-options.xml.i> diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py index 8f387b23d..4843a40da 100755 --- a/smoketest/scripts/cli/test_interfaces_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_ethernet.py @@ -354,5 +354,15 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase): out = loads(out) self.assertFalse(out[0]['autonegotiate']) + def test_ethtool_evpn_uplink_tarcking(self): + for interface in self._interfaces: + self.cli_set(self._base_path + [interface, 'evpn', 'uplink']) + + self.cli_commit() + + for interface in self._interfaces: + frrconfig = self.getFRRconfig(f'interface {interface}', daemon='zebra') + self.assertIn(f' evpn mh uplink', frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/interfaces_ethernet.py b/src/conf_mode/interfaces_ethernet.py index 6da7e6a69..54d0669cb 100755 --- a/src/conf_mode/interfaces_ethernet.py +++ b/src/conf_mode/interfaces_ethernet.py @@ -41,6 +41,7 @@ from vyos.pki import encode_certificate from vyos.pki import load_certificate from vyos.pki import wrap_private_key from vyos.template import render +from vyos.template import render_to_string from vyos.utils.process import call from vyos.utils.dict import dict_search from vyos.utils.dict import dict_to_paths_values @@ -48,6 +49,7 @@ from vyos.utils.dict import dict_set from vyos.utils.dict import dict_delete from vyos.utils.file import write_file from vyos import ConfigError +from vyos import frr from vyos import airbag airbag.enable() @@ -389,6 +391,10 @@ def generate(ethernet): write_file(ca_cert_file_path, '\n'.join(ca_chains)) + ethernet['frr_zebra_config'] = '' + if 'deleted' not in ethernet: + ethernet['frr_zebra_config'] = render_to_string('frr/evpn.mh.frr.j2', ethernet) + return None def apply(ethernet): @@ -407,6 +413,17 @@ def apply(ethernet): call(f'systemctl {eapol_action} wpa_supplicant-wired@{ifname}') + zebra_daemon = 'zebra' + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + + # The route-map used for the FIB (zebra) is part of the zebra daemon + frr_cfg.load_configuration(zebra_daemon) + frr_cfg.modify_section(f'^interface {ifname}', stop_pattern='^exit', remove_stop_mark=True) + if 'frr_zebra_config' in ethernet: + frr_cfg.add_before(frr.default_add_before, ethernet['frr_zebra_config']) + frr_cfg.commit_configuration(zebra_daemon) + if __name__ == '__main__': try: c = get_config() |