diff --git a/docs/caveats.md b/docs/caveats.md
index 5c594573d6..af569d2852 100644
--- a/docs/caveats.md
+++ b/docs/caveats.md
@@ -443,8 +443,7 @@ sudo pip3 install --upgrade 'ansible>=9.5.1'
Other caveats:
-* In our current implementation, Nokia SR-OS does not propagate EVPN type-5 (IP prefix) routes into VRF routing protocols.
-* We did not implement inter-VRF route leaking. Every VRF is limited to one import and export route target (and they have to match).
+* We implemented inter-VRF route leaking only for MPLS/VPN deployments.
* The SR OS configuration templates do not support additional routing policies on routing protocol route imports
* An SR OS interface cannot use an unnumbered IPv4 address in combination with IPv6 GUA
* SR OS requires the IPv6 prefix configured on the global loopback interface to be a /128 prefix. _netlab_ automatically adjusts the **loopback.ipv6** prefix.
diff --git a/docs/module/evpn.md b/docs/module/evpn.md
index bb0ec1e3b5..df247f82cf 100644
--- a/docs/module/evpn.md
+++ b/docs/module/evpn.md
@@ -63,10 +63,10 @@ EVPN module supports IBGP- and EBGP-based EVPN:
| Cumulus 5.x (NVUE) | ✅ | ✅ | ✅ | ✅ |
| Dell OS 10 [❗](caveats-os10) | ✅ | ✅ | ✅ | ✅ |
| FRR | ✅ | ✅ | ✅ | ✅ |
-| Nokia SR Linux | ✅ | ✅ | ❌ | ❌ |
-| Nokia SR OS | ✅ | ✅ | ✅ | ✅ |
+| Nokia SR Linux | ✅ | ✅ | ✅ | ✅ |
+| Nokia SR OS | ✅ | ✅ | ✅ | ❌ |
| vJunos-switch | ✅ | ✅ | ❌ | ❌ |
-| VyOS | ✅ | ✅ | ❌ | ❌ |
+| VyOS | ✅ | ✅ | ❌ | ✅ |
With additional nerd knobs ([more details](evpn-weird-designs)), it's possible to implement the more convoluted designs, including:
@@ -76,14 +76,14 @@ With additional nerd knobs ([more details](evpn-weird-designs)), it's possible t
| Operating system | IBGP over
EBGP | EBGP
over EBGP |
| ------------------ | :-: | :-: |
| Arista EOS | ✅ | ✅ |
-| Aruba AOS-CX | ✅ | ❌ |
+| Aruba AOS-CX | ✅ | ✅ |
| Cisco Nexus OS | ❌ | ❌ |
| Cumulus Linux 4.x | ✅ | ✅ |
| Cumulus 5.x (NVUE) | ✅ | ✅ |
| Dell OS 10 | ✅ | ❌ |
| FRR | ✅ | ✅ |
-| Nokia SR Linux | ✅ | ❌ |
-| Nokia SR OS | ✅ | ❌ |
+| Nokia SR Linux | ✅ | ✅ |
+| Nokia SR OS | ✅ | ✅ |
| vJunos-switch | ✅ | ✅ |
| VyOS | ✅ | ❌ |
diff --git a/netsim/ansible/templates/evpn/sros.j2 b/netsim/ansible/templates/evpn/sros.j2
index d8d6281ec8..24ea815496 100644
--- a/netsim/ansible/templates/evpn/sros.j2
+++ b/netsim/ansible/templates/evpn/sros.j2
@@ -1,4 +1,5 @@
updates:
+{# Configure EVPN AF on BGP neighbors #}
- path: configure/router[router-name=Base]
val:
bgp:
@@ -51,19 +52,10 @@ updates:
advertise: True # Symmetric IRB using RT5 prefixes
mac-ip:
advertise: False
-{% endif %}
- vxlan:
- - vxlan-instance: 1
- bgp-instance: 1
- admin-state: enable
- ecmp: {{ 1 if 'ixr' in clab.type else 8 }}
-{% if is_routed %}
- routed-vpls:
- vxlan-ipv4-tep-ecmp: True # Enable ECMP for routed VXLAN
{% endif %}
{% endmacro %}
-{% macro evpn_vprn %}
+{% macro evpn_vprn() %}
{# Add it to the VPRN, enable evpn-tunnel and configure RT #}
- path: configure/service/vprn[service-name={{ vname }}]
val:
@@ -84,30 +76,88 @@ updates:
ecmp: {{ 1 if 'ixr' in clab.type else 8 }}
{% endmacro %}
-{# Configure EVPN parameters for VLANs, TODO bundles #}
+{# Configure EVPN parameters for simple MAC-VRF (VLAN) services #}
{% if vlans is defined %}
{% for vname,vdata in vlans.items() if vdata.evpn.evi is defined %}
- path: configure/service/vpls[service-name=vlan{{ vdata.id }}]
val:
- bgp:
- - bgp-instance: 1
- # route-distinguisher: "{{ vdata.evpn.rd }}" # use auto-rd
- route-target:
- export: "target:{{ vdata.evpn.export[0] }}"
- import: "target:{{ vdata.evpn.import[0] }}"
+{% if vdata.mode|default('irb') == 'irb' %}
+ routed-vpls:
+ vxlan-ipv4-tep-ecmp: True # Enable ECMP for routed VXLAN
+{% endif %}
+ bgp:
+ - bgp-instance: 1
+ route-distinguisher: "{{ vdata.evpn.rd }}"
+ route-target:
+ export: "target:{{ vdata.evpn.export[0] }}"
+ import: "target:{{ vdata.evpn.import[0] }}"
+ bgp-evpn:
+ evi: {{ vdata.evpn.evi }}
+ routes:
+ mac-ip:
+ advertise: True
+{% if evpn.transport|default('vxlan') == 'mpls' %}
+ # TODO if evpn.transport == 'mpls'
+ mpls:
+ - bgp-instance: 1
+ admin-state: enable
+ ecmp: {{ 2 if 'ixr' in clab.type else 32 }}
+ # ingress-replication-bum-label: True # TODO, requires reserved label range
+ auto-bind-tunnel:
+ resolution: any
+ ecmp: {{ 2 if 'ixr' in clab.type else 32 }}
+{% else %}
+ vxlan:
+ - vxlan-instance: 1
+ bgp-instance: 1
+ admin-state: enable
+ ecmp: {{ 1 if 'ixr' in clab.type else 8 }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{# Configure EVPN parameters for IP-VRF services #}
+{% if vrfs is defined %}
+{% for vname,vdata in vrfs.items() if vdata.evpn.transit_vni is defined %}
+- path: configure/service/vprn[service-name={{ vname }}]
+ val:
+ bgp-evpn:
{% if evpn.transport|default('vxlan') == 'mpls' %}
- bgp-evpn:
- evi: {{ vdata.evpn.evi }}
# TODO if evpn.transport == 'mpls'
- mpls:
- - bgp-instance: 1
- admin-state: enable
- ecmp: {{ 2 if 'ixr' in clab.type else 32 }}
+ mpls:
+ - bgp-instance: 1
+ admin-state: enable
+ ecmp: {{ 2 if 'ixr' in clab.type else 32 }}
# ingress-replication-bum-label: True # TODO, requires reserved label range
- auto-bind-tunnel:
- resolution: any
- ecmp: {{ 2 if 'ixr' in clab.type else 32 }}
+ auto-bind-tunnel:
+ resolution: any
+ ecmp: {{ 2 if 'ixr' in clab.type else 32 }}
+{% else %}
+ vxlan:
+ - vxlan-instance: 1
+ bgp-instance: 1
+ admin-state: enable
+ route-distinguisher: "{{ vdata.rd }}"
+ vrf-target:
+ export-community: "target:{{ vdata.export[0] }}"
+ import-community: "target:{{ vdata.import[0] }}"
+
+ vxlan:
+ instance:
+ - vxlan-instance: 1
+ vni: {{ vdata.evpn.transit_vni }}
{% endif %}
+{% for proto in ['bgp','ospf','isis','ripv2'] if proto in vdata %}
+#
+- path: configure/policy-options/policy-statement[name={{ proto }}_{{ vname }}_export]
+ val:
+ entry:
+ - entry-id: 2000
+ from:
+ protocol:
+ name: [ evpn-ifl ]
+ action:
+ action-type: accept
+{% endfor %}
{% endfor %}
{% endif %}
diff --git a/netsim/devices/sros.py b/netsim/devices/sros.py
index a1d9baae94..ec856131cb 100644
--- a/netsim/devices/sros.py
+++ b/netsim/devices/sros.py
@@ -28,17 +28,21 @@ def vrf_route_leaking(node: Box) -> None:
node=node,
category=log.IncorrectValue)
-def evpn_vrf_rp(node: Box) -> None:
- for vname,vdata in node.get('vrfs',{}).items():
- if not vdata.get('evpn',None):
+"""
+It looks like SR-OS does not apply AS-path loop detection parameters on EVPN AF
+"""
+def evpn_allowas_in(node: Box) -> None:
+ for ngb in node.get('bgp.neighbors',[]):
+ if not ngb.get('evpn',None):
continue
- if vdata.get('bgp.neighbors',[]) or vdata.get('ospf'):
- report_quirk(
- text=f'We did not implement propagation of EVPN ip-prefix routes into VRF routing protocols',
- more_data = f'Node {node.name} vrf {vname}',
- quirk='evpn_rp',
- node=node,
- category=log.IncorrectValue)
+ if not ngb.get('allowas_in',None):
+ continue
+ report_quirk(
+ text=f'node {node.name}: cannot use "allowas_in" on BGP neighbor {node.name} with EVPN address family',
+ more_hints = f'It looks SR/OS does not apply AS-path loop detection parameters to EVPN AF',
+ quirk='evpn_allowas_in',
+ node=node,
+ category=log.IncorrectValue)
def set_port_mode(intf: Box, mode: str) -> None:
if '_port_mode' not in intf:
@@ -105,7 +109,7 @@ def device_quirks(self, node: Box, topology: Box) -> None:
ipv4_unnumbered(node)
vrf_route_leaking(node)
vxlan_vtep(node)
- evpn_vrf_rp(node)
+ evpn_allowas_in(node)
def check_config_sw(self, node: Box, topology: Box) -> None:
need_ansible_collection(node,'nokia.grpc',version='1.0.2')