Skip to content

Commit

Permalink
Merge pull request #2416 from c-po/evpn-mh-t5698
Browse files Browse the repository at this point in the history
T5698 EVPN ESI Multihoming
  • Loading branch information
c-po authored Nov 2, 2023
2 parents 0c86d0a + 1d67620 commit 031a5c8
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 2 deletions.
20 changes: 20 additions & 0 deletions data/templates/frr/bgpd.frr.j2
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,26 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
{% if afi_config.advertise_svi_ip is vyos_defined %}
advertise-svi-ip
{% endif %}
{% if afi_config.default_originate.ipv4 is vyos_defined %}
default-originate ipv4
{% endif %}
{% if afi_config.default_originate.ipv6 is vyos_defined %}
default-originate ipv6
{% endif %}
{% if afi_config.disable_ead_evi_rx is vyos_defined %}
disable-ead-evi-rx
{% endif %}
{% if afi_config.disable_ead_evi_tx is vyos_defined %}
disable-ead-evi-tx
{% endif %}
{% if afi_config.ead_es_frag.evi_limit is vyos_defined %}
ead-es-frag evi-limit {{ afi_config.ead_es_frag.evi_limit }}
{% endif %}
{% if afi_config.ead_es_route_target.export is vyos_defined %}
{% for route_target in afi_config.ead_es_route_target.export %}
ead-es-route-target export {{ route_target }}
{% endfor %}
{% endif %}
{% if afi_config.rt_auto_derive is vyos_defined %}
autort rfc8365-compatible
{% endif %}
Expand Down
16 changes: 16 additions & 0 deletions data/templates/frr/evpn.mh.frr.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
!
interface {{ ifname }}
{% if evpn.es_df_pref is vyos_defined %}
evpn mh es-df-pref {{ evpn.es_df_pref }}
{% endif %}
{% if evpn.es_id is vyos_defined %}
evpn mh es-id {{ evpn.es_id }}
{% endif %}
{% if evpn.es_sys_mac is vyos_defined %}
evpn mh es-sys-mac {{ evpn.es_sys_mac }}
{% endif %}
{% if evpn.uplink is vyos_defined %}
evpn mh uplink
{% endif %}
exit
!
70 changes: 70 additions & 0 deletions interface-definitions/include/bgp/protocol-common-config.xml.i
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,76 @@
<valueless/>
</properties>
</leafNode>
<node name="default-originate">
<properties>
<help>Originate a default route</help>
</properties>
<children>
<leafNode name="ipv4">
<properties>
<help>IPv4 address family</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="ipv6">
<properties>
<help>IPv6 address family</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
<leafNode name="disable-ead-evi-rx">
<properties>
<help>Activate PE on EAD-ES even if EAD-EVI is not received</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="disable-ead-evi-tx">
<properties>
<help>Do not advertise EAD-EVI for local ESs</help>
<valueless/>
</properties>
</leafNode>
<node name="ead-es-frag">
<properties>
<help>EAD ES fragment config</help>
</properties>
<children>
<leafNode name="evi-limit">
<properties>
<help>EVIs per-fragment</help>
<valueHelp>
<format>u32:1-1000</format>
<description>limit</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-1000"/>
</constraint>
</properties>
</leafNode>
</children>
</node>
<node name="ead-es-route-target">
<properties>
<help>EAD ES Route Target</help>
</properties>
<children>
<leafNode name="export">
<properties>
<help>Route Target export</help>
<valueHelp>
<format>txt</format>
<description>Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description>
</valueHelp>
<constraint>
<validator name="bgp-rd-rt" argument="--route-target-multi"/>
</constraint>
<multi/>
</properties>
</leafNode>
</children>
</node>
<node name="flooding">
<properties>
<help>Specify handling for BUM packets</help>
Expand Down
54 changes: 54 additions & 0 deletions interface-definitions/interfaces-bonding.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,60 @@
#include <include/interface/disable.xml.i>
#include <include/interface/vrf.xml.i>
#include <include/interface/mirror.xml.i>
<node name="evpn">
<properties>
<help>EVPN Multihoming</help>
</properties>
<children>
<leafNode name="es-df-pref">
<properties>
<help>Preference value used for designated forwarder (DF) election</help>
<valueHelp>
<format>u32:1-65535</format>
<description>DF Preference value</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-65535"/>
</constraint>
</properties>
</leafNode>
<leafNode name="es-id">
<properties>
<help>Ethernet segment identifier</help>
<valueHelp>
<format>u32:1-16777215</format>
<description>Local discriminator</description>
</valueHelp>
<valueHelp>
<format>txt</format>
<description>10-byte ID - 00:11:22:33:44:55:AA:BB:CC:DD</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-65535"/>
<regex>([0-9A-Fa-f][0-9A-Fa-f]:){9}[0-9A-Fa-f][0-9A-Fa-f]</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="es-sys-mac">
<properties>
<help>Ethernet segment system MAC</help>
<valueHelp>
<format>macaddr</format>
<description>MAC address</description>
</valueHelp>
<constraint>
<validator name="mac-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="uplink">
<properties>
<help>Uplink to the VXLAN core</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
<leafNode name="hash-policy">
<properties>
<help>Bonding transmit hash policy</help>
Expand Down
40 changes: 40 additions & 0 deletions smoketest/scripts/cli/test_interfaces_bonding.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,45 @@ def test_bonding_uniq_member_description(self):
for member in self._members:
self.assertIn(member, slaves)

def test_bonding_evpn_multihoming(self):
id = '5'
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())

self.cli_set(self._base_path + [interface, 'evpn', 'es-id', id])
self.cli_set(self._base_path + [interface, 'evpn', 'es-df-pref', id])
self.cli_set(self._base_path + [interface, 'evpn', 'es-sys-mac', f'00:12:34:56:78:0{id}'])
self.cli_set(self._base_path + [interface, 'evpn', 'uplink'])

id = int(id) + 1

self.cli_commit()

id = '5'
for interface in self._interfaces:
frrconfig = self.getFRRconfig(f'interface {interface}', daemon='zebra')

self.assertIn(f' evpn mh es-id {id}', frrconfig)
self.assertIn(f' evpn mh es-df-pref {id}', frrconfig)
self.assertIn(f' evpn mh es-sys-mac 00:12:34:56:78:0{id}', frrconfig)
self.assertIn(f' evpn mh uplink', frrconfig)

id = int(id) + 1

for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'evpn', 'es-id'])
self.cli_delete(self._base_path + [interface, 'evpn', 'es-df-pref'])

self.cli_commit()

id = '5'
for interface in self._interfaces:
frrconfig = self.getFRRconfig(f'interface {interface}', daemon='zebra')
self.assertIn(f' evpn mh es-sys-mac 00:12:34:56:78:0{id}', frrconfig)
self.assertIn(f' evpn mh uplink', frrconfig)

id = int(id) + 1

if __name__ == '__main__':
unittest.main(verbosity=2)
18 changes: 18 additions & 0 deletions smoketest/scripts/cli/test_protocols_bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,15 +728,25 @@ def test_bgp_06_listen_range(self):
def test_bgp_07_l2vpn_evpn(self):
vnis = ['10010', '10020', '10030']
neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30']
evi_limit = '1000'
route_targets = ['1.1.1.1:100', '1.1.1.1:200', '1.1.1.1:300']

self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-all-vni'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-default-gw'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-svi-ip'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'flooding', 'disable'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'default-originate', 'ipv4'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'default-originate', 'ipv6'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'disable-ead-evi-rx'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'disable-ead-evi-tx'])
for vni in vnis:
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-default-gw'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-svi-ip'])

self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'ead-es-frag', 'evi-limit', evi_limit])
for route_target in route_targets:
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'ead-es-route-target', 'export', route_target])

# commit changes
self.cli_commit()

Expand All @@ -747,12 +757,20 @@ def test_bgp_07_l2vpn_evpn(self):
self.assertIn(f' advertise-all-vni', frrconfig)
self.assertIn(f' advertise-default-gw', frrconfig)
self.assertIn(f' advertise-svi-ip', frrconfig)
self.assertIn(f' default-originate ipv4', frrconfig)
self.assertIn(f' default-originate ipv6', frrconfig)
self.assertIn(f' disable-ead-evi-rx', frrconfig)
self.assertIn(f' disable-ead-evi-tx', frrconfig)
self.assertIn(f' flooding disable', frrconfig)
for vni in vnis:
vniconfig = self.getFRRconfig(f' vni {vni}')
self.assertIn(f'vni {vni}', vniconfig)
self.assertIn(f' advertise-default-gw', vniconfig)
self.assertIn(f' advertise-svi-ip', vniconfig)
self.assertIn(f' ead-es-frag evi-limit {evi_limit}', frrconfig)
for route_target in route_targets:
self.assertIn(f' ead-es-route-target export {route_target}', frrconfig)


def test_bgp_09_distance_and_flowspec(self):
distance_external = '25'
Expand Down
23 changes: 21 additions & 2 deletions src/conf_mode/interfaces-bonding.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019-2022 VyOS maintainers and contributors
# Copyright (C) 2019-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
Expand Down Expand Up @@ -35,12 +35,14 @@
from vyos.ifconfig import BondIf
from vyos.ifconfig.ethernet import EthernetIf
from vyos.ifconfig import Section
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_to_paths_values
from vyos.configdict import has_address_configured
from vyos.configdict import has_vrf_configured
from vyos.configdep import set_dependents, call_dependents
from vyos import ConfigError
from vyos import frr
from vyos import airbag
airbag.enable()

Expand Down Expand Up @@ -247,21 +249,38 @@ def verify(bond):
return None

def generate(bond):
bond['frr_zebra_config'] = ''
if 'deleted' not in bond:
bond['frr_zebra_config'] = render_to_string('frr/evpn.mh.frr.j2', bond)
return None

def apply(bond):
b = BondIf(bond['ifname'])
ifname = bond['ifname']
b = BondIf(ifname)
if 'deleted' in bond:
# delete interface
b.remove()
else:
b.update(bond)

if dict_search('member.interface_remove', bond):
try:
call_dependents()
except ConfigError:
raise ConfigError('Error in updating ethernet interface '
'after deleting it from bond')

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 bond:
frr_cfg.add_before(frr.default_add_before, bond['frr_zebra_config'])
frr_cfg.commit_configuration(zebra_daemon)

return None

if __name__ == '__main__':
Expand Down

0 comments on commit 031a5c8

Please sign in to comment.