Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T5698 EVPN ESI Multihoming #2416

Merged
merged 2 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading