summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-05-11 14:12:31 +0200
committerChristian Breunig <christian@breunig.cc>2024-05-11 14:12:31 +0200
commit5565f27d15c5e7378e94aae8db8a894a12e25d7b (patch)
treebb9c6da6753e1cb3f550595db5f6e7919036dbbf
parent7925402b487b93d1ae8dd4941e0981437f7fb951 (diff)
downloadvyos-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.i8
-rw-r--r--interface-definitions/interfaces_bonding.xml.in7
-rw-r--r--interface-definitions/interfaces_ethernet.xml.in8
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py10
-rwxr-xr-xsrc/conf_mode/interfaces_ethernet.py17
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()