Skip to content

Commit 9145d14

Browse files
authored
vJunos-switch: support for explicit EVPN vlan-aware bundle (ipspace#2576)
1 parent bbb1a27 commit 9145d14

File tree

5 files changed

+71
-4
lines changed

5 files changed

+71
-4
lines changed

docs/caveats.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,14 @@ See also [](caveats-junos).
387387

388388
_netlab_ can use *default-switch* or MAC VRF EVPN configuration on a vJunos-switch. It uses MAC VRF EVPN configuration unless you set the **evpn.\_junos\_default\_macvrf** variable to *True*.
389389

390-
MAC VRF EVPN configuration (using VLAN-based EVPN service) works well with most other EVPN implementations. However, it uses a separate MAC VRF for every VLAN, and as we're not creating the VLAN subinterfaces, we have to assign physical interfaces to MAC VRFs. It's thus impossible to use an EVPN-enabled VLAN in a VLAN trunk.
390+
MAC VRF EVPN configuration (using VLAN-based or VLAN-aware EVPN service) works well with most other EVPN implementations. However, it uses a separate MAC VRF for every VLAN, and as we're not creating the VLAN subinterfaces, we have to assign physical interfaces to MAC VRFs. It's thus impossible to use an EVPN-enabled VLAN in a VLAN trunk.
391391

392-
The VLAN-aware EVPN configuration (using the `switch-options` of the default routing instance) has other drawbacks and limitations:
392+
The *default macvrf* VLAN-aware EVPN configuration (using the `switch-options` of the default routing instance) has other drawbacks and limitations:
393393

394394
* All EVPN routes are announced with the same RD (configured under `switch-options`). A default route target is configured under `switch-options` but is then overwritten for each VNI under the `protocol evpn` configuration.
395395
* You cannot use multiple import/export RT. The *first* import RT is used on the configuration templates as the VNI RT.
396-
* VLAN-aware EVPN service might not work with devices from other vendors using VLAN-based EVPN service. For example, the VLAN-aware EVPN service works with FRRouting but not with Arista EOS.
396+
* VLAN-aware EVPN service might not work with devices from other vendors using VLAN-based EVPN service.
397+
* Every JunOS *routing-instance* (i.e., L3 VRF and MAC-VRF) must use a unique *Route Distinguisher*. For this reason, when using EVPN with VLAN Bundles, a new RD is allocated for every MAC-VRF.
397398

398399
(caveats-vjunos-router)=
399400
## vJunos-Router in Containerlab

netsim/ansible/templates/evpn/vjunos-switch.j2

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ vlans {
9393
{% endfor %}
9494
}
9595

96+
{# vlan-based MAC VRF #}
9697
routing-instances {
9798
{% for vname,v in vlans.items() if v.evpn.evi is defined and v.evpn.bundle is not defined %}
9899
vlan_{{ vname }} {
@@ -134,6 +135,53 @@ routing-instances {
134135
}
135136
{% endif %}
136137

138+
{# vlan-aware MAC VRF #}
139+
{% if vrfs is defined %}
140+
routing-instances {
141+
{% for n,v in vrfs.items() if v.evpn.vlans is defined %}
142+
vlan_aware_{{ n }} {
143+
instance-type mac-vrf;
144+
service-type vlan-aware;
145+
vtep-source-interface {{ vxlan.vtep_interface }};
146+
route-distinguisher {{ v._junos_l2vrf_rd }};
147+
{% for dir in ['import', 'export'] %}
148+
{% set tlist_len = v[dir]|default([])|length %}
149+
{% if tlist_len == 1 %}
150+
vrf-target {{ dir }} target:{{ v[dir][0] }};
151+
{% elif tlist_len > 1 %}
152+
{# use targets already defined by vrf #}
153+
vrf-{{ dir }} vrf-{{ n }}-rt-{{ dir }};
154+
{% endif %}
155+
{% endfor %}
156+
{# map vlans and access interfaces #}
157+
{% for vname in v.evpn.vlans %}
158+
{% for intf in interfaces if intf.vlan.access|default('') == vname %}
159+
interface {{ intf.ifname }};
160+
{% endfor %}
161+
vlans {
162+
{{ vname }} {
163+
vlan-id {{ vlans[vname].id }};
164+
{% if vlans[vname].mode == 'irb' %}
165+
l3-interface irb.{{ vlans[vname].id }};
166+
{% endif %}
167+
vxlan {
168+
vni {{ vlans[vname].vni }};
169+
}
170+
}
171+
}
172+
{% endfor %}
173+
protocols {
174+
evpn {
175+
encapsulation vxlan;
176+
default-gateway no-gateway-community;
177+
extended-vni-list all;
178+
}
179+
}
180+
}
181+
{% endfor %}
182+
}
183+
{% endif %}
184+
137185
{# define L3VNI on vrf routing-instance #}
138186
{% if vrfs is defined %}
139187
routing-instances {

netsim/ansible/templates/vxlan/vjunos-switch.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ switch-options {
2424
{# define basic VLAN to VXLAN mapping #}
2525
{% if vxlan.vlans is defined %}
2626
vlans {
27-
{% for vname in vxlan.vlans if vlans[vname].vni is defined %}
27+
{% for vname in vxlan.vlans if vlans[vname].vni is defined and vlans[vname].evpn.bundle is not defined %}
2828
{% set vlan = vlans[vname] %}
2929
{{ vname }} {
3030
vxlan {

netsim/devices/vjunos-switch.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .junos import JUNOS as _JUNOS
66
from . import report_quirk
77
from ..utils import log
8+
from ..modules import vrf
89

910
def check_evpn_vlan_trunks(node: Box, topology: Box) -> None:
1011
if 'evpn' not in node.get('module',[]):
@@ -30,10 +31,26 @@ def check_evpn_vlan_trunks(node: Box, topology: Box) -> None:
3031
more_hints=['The node is using VLAN-based EVPN service which cannot be used with enterprise-style VLAN trunks'],
3132
quirk='evpn_macvrf')
3233

34+
def macvrf_unique_rd_for_vlan_bundle(node: Box, topology: Box) -> None:
35+
if 'evpn' not in node.get('module',[]):
36+
return
37+
if 'vrf' not in node.get('module',[]):
38+
return
39+
asn = vrf.get_rd_as_number(node, topology)
40+
if asn is None:
41+
return
42+
43+
for vname,vdata in node.vrfs.items():
44+
if vdata.get('evpn.bundle'):
45+
# in that case we need to generate a new RD for the mac-vrf (cannot be the same of L3 VRF)
46+
free_vrf_idx = vrf.get_next_vrf_id(asn)
47+
vdata._junos_l2vrf_rd = free_vrf_idx[1]
48+
3349
class Junos_switch(_JUNOS):
3450
@classmethod
3551
def device_quirks(self, node: Box, topology: Box) -> None:
3652
if log.debug_active('quirks'):
3753
print(f"*** DEVICE QUIRKS FOR vJunos-switch {node.name}")
3854
check_evpn_vlan_trunks(node,topology)
55+
macvrf_unique_rd_for_vlan_bundle(node,topology)
3956
super().device_quirks(node,topology)

netsim/devices/vjunos-switch.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ features:
1010
asymmetrical_irb: true
1111
irb: true
1212
multi_rt: true
13+
bundle: [ vlan_aware ]
1314
lag:
1415
passive: True
1516
vlan:

0 commit comments

Comments
 (0)