Skip to content

Commit bc45dad

Browse files
authored
Remove intra-VRF EBGP sessions with other PE-devices (ipspace#2712)
An intra-VRF EBGP session should not be established between PE-device running EVPN-over-EBGP when they're in the same EVPN instance. This commit adds a 'remove VRF EBGP PE-device neighbors' function to the EVPN cleanup hook. That function performs a number of tests before deciding to remove an intra-VRF EBGP session: * Both devices must run EBGP session in the same VRF. This preserves loopback EBGP sessions between VRFs * Only EBGP sessions between EVPN-enabled devices are removed * The two EVPN-enabled devices must be in the same evpn.domain -- this check enables multi-pod/multi-site designs * The EBGP session must run over an EVPN-controlled SVI interface -- this check preserves the in-VRF EBGP sessions in Inter-AS Option A designs Fixes ipspace#2477
1 parent 3ee233a commit bc45dad

File tree

6 files changed

+246
-149
lines changed

6 files changed

+246
-149
lines changed

docs/module/evpn.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ EVPN module supports these default/global/node parameters:
118118
* **evpn.as** (global parameter): Autonomous system number for VLAN and VRF route targets. Default value: **bgp.as** (when set globally) or **vrf.as**.
119119
* **evpn.start_transit_vni** (system default parameter) -- the first symmetric IRB transit VNI, range 4096..16777215
120120
* **evpn.start_transit_vlan** (device-dependent node parameter) -- the starting VLAN ID for VLANs used to map VXLAN transit VNIs
121+
* **evpn.domain** (node parameter) -- EVPN domain (site) name. This parameter might have to be used in multi-site designs when you want to have an in-VRF inter-site EBGP session across an EVPN-controlled VLAN (see [](evpn-rp) for more details).
121122

122123
(evpn-vlan-service)=
123124
### VLAN-Based Service Parameters
@@ -217,7 +218,15 @@ If you're using EVPN to implement symmetrical IRB (**evpn.transit_vni** is set i
217218

218219
If you want to implement an EVPN L3VPN with CE-routers, use separate segments (not VXLAN-backed VLANs) for PE-CE connectivity. There is no way to block the establishment of PE-to-PE in-VRF IGP adjacencies if you expect to have the PE-CE IGP adjacencies on a VXLAN-backed VLAN.
219220

220-
Finally, if you use EBGP with EVPN (simple EBGP, IBGP-over-EBGP, or EBGP-over-EBGP design), the PE devices have different AS numbers, and _netlab_ tries to establish VRF EBGP sessions between them whenever they share a VLAN. To prevent the formation of VRF EBGP sessions between the PE devices:
221+
Finally, if you use EBGP with EVPN (simple EBGP, IBGP-over-EBGP, or EBGP-over-EBGP design), the PE devices have different AS numbers. _netlab_ thus tries to establish VRF EBGP sessions between them whenever they share a VLAN. However, the EVPN module removes such PE-to-PE intra-VRF EBGP sessions when:
222+
223+
* Both devices use the EVPN module
224+
* The EBGP session is established across an EVPN-controlled VLAN
225+
* The two devices use the same VRF name
226+
227+
This algorithm might remove an inter-site PE-to-PE EBGP session when you use Inter-AS Option A (EBGP sessions in VRFs) over EVPN-controlled VLANs. If that happens, use a different value of the **evpn.domain** parameter on nodes belonging to different sites (all nodes within a site must have the same **evpn.domain** value).
228+
229+
It might be even better to prevent the formation of VRF EBGP sessions between the PE devices:
221230

222231
* Use EVPN as a pure L3VPN (no stretched VLAN-over-VXLAN segments);
223232
* Disable BGP in the EVPN-controlled VRFs with a setting similar to **vrfs._tenant_vrf_.bgp: False**;

netsim/defaults/hints.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ evpn:
1212
route targets. 'bgp.as' specified on individual nodes or groups will not work. You
1313
can also specify the global AS used by EVPN in 'vrf.as' parameter if you use
1414
VRFs, or in 'evpn.as' parameter if you use EVPN in bridging-only scenarios.
15+
ebgp_vlan: >
16+
In most scenarios, you don't need EBGP sessions between PE-devices across an
17+
EVPN-controlled VLAN. See https://netlab.tools/module/evpn/#evpn-rp for details.
1518
1619
report:
1720
source: >

netsim/modules/evpn.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from ..augment import devices
77
from ..data.types import must_be_dict, must_be_int, must_be_string
88
from ..utils import log
9+
from ..utils import routing as _rp_utils
910
from . import _dataplane, _Module, _routing
1011

1112
VALID_TRANSPORTS = [ 'vxlan', 'mpls' ] # In order of preference
@@ -447,6 +448,56 @@ def check_vlan_rt_values(node: Box, topology: Box) -> None:
447448
category=log.IncorrectValue,
448449
module='evpn')
449450

451+
"""
452+
Remove unneeded in-VRF EBGP sessions between EVPN routers
453+
454+
In designs using "EBGP as a better IGP", we might get in-VRF EBGP sessions between PE-routers
455+
over IRB VLANs. This function removes those EBGP sessions if:
456+
457+
* Both BGP routers are also running EVPN
458+
* Both BGP neighbors are in the same VRF
459+
* The "evpn.domain" attribute (when set) is the same
460+
"""
461+
def remove_vlan_ebgp_neighbors(node: Box,topology: Box) -> None:
462+
cleanup_needed = False
463+
for ngb in _rp_utils.neighbors(node, vrf=True,select=['ebgp']):
464+
vrf = ngb.get('_src_vrf','default')
465+
if ngb.get('_vrf','default') != vrf: # Are both neighbors in the same VRF?
466+
continue # ... if not, this could be a valid inter-VRF session
467+
ngb_data = topology.nodes[ngb.name] # Get neighbor data
468+
if 'evpn' not in ngb_data.get('module',[]): # Is the neighbor running EVPN?
469+
continue
470+
if node.get('evpn.domain','default') != ngb_data.get('evpn.domain','default'):
471+
continue # EVPN PE-devices in different EVPN domains, probably OK
472+
473+
iflist = [ intf for intf in node.interfaces if intf.ifindex == ngb.ifindex ]
474+
if len(iflist) < 1: # Neighbor has incorrect ifindex. Weird.
475+
continue # we don't know what's going on, so keep it intact
476+
477+
ngb_intf = iflist[0]
478+
if ngb_intf.type != 'svi': # We have to remove EVPN EBGP neighbors only over SVI interfaces
479+
continue
480+
481+
ngb_vlan = ngb_intf.get('vlan.name') # Get the VLAN associated with the SVI interface
482+
if not ngb_vlan: # Can't get it? Weird, but let's move on
483+
continue
484+
485+
if ngb_vlan not in node.get('evpn.vlans',[]): # Is this an EVPN-enabled VLAN
486+
continue # No? We may need the EBGP session
487+
488+
ngb._must_remove = True
489+
log.warning(
490+
text=f'Removing an EBGP session between {node.name} and {ngb.name} running over an EVPN-enabled VLAN {ngb_vlan}',
491+
flag='ebgp_vlan',
492+
hint='ebgp_vlan')
493+
494+
cleanup_needed = True
495+
496+
if cleanup_needed: # Finally, remove neighbors with '_must_remove' flag
497+
for (bgp,_,_) in _rp_utils.rp_data(node,proto='bgp'): # ... iterating over global and VRF BGP instances
498+
if 'neighbors' in bgp:
499+
bgp.neighbors = [ ngb for ngb in bgp.neighbors if '_must_remove' not in ngb ]
500+
450501
class EVPN(_Module):
451502

452503
def module_init(self, topology: Box) -> None:
@@ -488,3 +539,6 @@ def node_post_transform(self, node: Box, topology: Box) -> None:
488539
check_vlan_rt_values(node,topology)
489540
trim_node_evpn_lists(node)
490541
set_local_evpn_rd(node)
542+
543+
def node_cleanup(self, node: Box, topology: Box) -> None:
544+
remove_vlan_ebgp_neighbors(node,topology)

netsim/modules/evpn.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ attributes:
1919
session:
2020
vlans:
2121
vrfs:
22+
domain: str
2223
vlan:
2324
evi: rd
2425
rd: rd

0 commit comments

Comments
 (0)