Skip to content
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
12 changes: 10 additions & 2 deletions docs/caveats.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ These caveats apply only to Cisco IOSv and IOSvL2

* Cisco IOS release 15.x does not support unnumbered interfaces. Use Cisco CSR 1000v.
* Multiple OSPFv2 processes on Cisco IOS cannot have the same OSPF router ID. By default, _netlab_ generates the same router ID for global and VRF OSPF processes, resulting in non-fatal configuration errors that Ansible silently ignores.
* You cannot use VLANs 1002 through 1005 with Cisco IOSvL2 image
* You cannot use VLANs 1002 through 1005 with Cisco IOSvL2 image
* Cisco IOSv does not support VRRPv3 on BVI interfaces
* Cisco IOSv cannot use tagged VLAN 1 in a trunk
* Cisco IOSvL2 cannot configure tagged VLAN 1 in a trunk. Internal VLAN 1002 is used as a fake native VLAN on interfaces that have tagged VLAN 1 in a trunk.
Expand Down Expand Up @@ -316,7 +316,7 @@ Netlab enables VRRPv3 by default on Dell OS10, overriding any platform defaults.
* You have to build the *dnsmasq* container image with the **netlab clab build dnsmasq** command.

(caveats-fortios)=
## Fortinet FortiOS
## Fortinet FortiOS

* Use a recent version of Ansible and **fortinet.fortios** Ansible Galaxy collection (version 2.3.6 or later)
* _netlab_ tries to configure Fortinet devices with configuration scripts uploaded through the FortiOS Monitor API calls using username/password authentication.
Expand Down Expand Up @@ -394,6 +394,14 @@ Implementation limitations in import/export route filters (reported as errors th
* When prepending an AS number different than the local one, JunOS puts the prepended AS at the beginning of the *AS_PATH* while other vendors perform the prepending and then add the device's own AS at the beginning. Most EBGP peers deny a BGP update that does not have the neighbor's AS number at the beginning of the *AS_PATH*. If needed, _netlab_ automatically adds the *local-as* to the prepend list to get it at the beginning of the *AS_PATH*.
* *as-path* regex syntax for JunOS has different rules than other vendors. For example, a *null as-path* is represented as `()`. netlab tries some as-path conversion, but sometimes it could be wrong.

(caveats-crpd)=
## Juniper cRPD

* cRPD might require a license file to unlock additional features. You can specify the location of the license file with the **clab.license** node parameter or **defaults.devices.crpd.clab.node.license** [device default](topo-defaults).
* Inter-VRF route leaking does not work correctly
* VRRPv3 for IPv4 implementation uses the [checksum calculation that is incompatible with most other VRRP implementations](https://blog.ipspace.net/2025/01/sturgeon-law-vrrp-edition/). The `checksum-without-pseudoheader` configuration command does not seem to be available.
* Anycast gateway is unsupported

(caveats-vmx)=
## Juniper vMX

Expand Down
3 changes: 2 additions & 1 deletion docs/module/gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ The module is supported on these platforms:
| Dell OS10 | ✅ [❗](caveats-os10) | ✅ [❗](caveats-os10) | ✅ [❗](caveats-os10) |
| FRRouting | ✅ | ✅ | ✅ |
| Junos[^Junos] | ✅ [❗](caveats-junos) | ✅ | ✅ |
| Juniper cRPD | ❌ [❗](caveats-crpd) | ✅ | ✅ |
| Nokia SR OS[^SROS] | ✅ | ✅ | ✅ |
| Nokia SR Linux | ✅ | ❌ | ❌ |
| VyOS | ❌ | ✅ | ✅ |

[^18v]: Includes Cisco CSR 1000v, Cisco Catalyst 8000v, Cisco IOSv, Cisco IOSv Layer-2 image, Cisco IOS-on-Linux (IOL), and IOL Layer-2 image.

[^Junos]: Includes vMX, vSRX, vPTX, vJunos-switch, and vJunos-router but not cRPD
[^Junos]: Includes vMX, vSRX, vPTX, vJunos-switch, and vJunos-router, but not cRPD

[^SROS]: Includes the Nokia SR-SIM container and the Virtualized 7750 SR and 7950 XRS Simulator (vSIM) virtual machine

Expand Down
6 changes: 3 additions & 3 deletions docs/module/vrf.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ VRFs are supported on these platforms:
| Cumulus 5.x (NVUE) | ✅ | ✅ [❗](caveats-cumulus-nvue) | ✅ |
| Dell OS10 | ✅ | ✅ | ✅ |
| FRR [❗](caveats-frr) | ✅ | ✅ | ✅ |
| Junos[^Junos] | ✅ | ✅ | ✅ |
| Junos[^Junos] | ✅ | ✅ [❗](caveats-crpd) | ✅ |
| Mikrotik RouterOS 6 | ✅ | ✅ | ❌ |
| Mikrotik RouterOS 7 | ✅ | ✅ | ✅ |
| Nokia SR Linux | ✅ | ✅ [❗](caveats-srlinux) | ✅ |
Expand All @@ -36,7 +36,7 @@ VRFs are supported on these platforms:

[^18v]: Includes Cisco CSR 1000v, Cisco Catalyst 8000v, Cisco IOS-on-Linux (IOL) and IOL Layer-2 image

[^Junos]: Includes vMX, vSRX, vPTX, vJunos-switch, and vJunos-router but not cRPD
[^Junos]: Includes cRPD, vMX, vSRX, vPTX, vJunos-switch, and vJunos-router

[^SRRL]: Nokia SR OS supports inter-VRF route leaking, but it's not yet implemented in _netlab_

Expand Down Expand Up @@ -270,7 +270,7 @@ Consider the simplest possible topology with a switch (s1) and two hosts (h1 and
```
vrfs:
example:

links:
- h1:
s1:
Expand Down
1 change: 1 addition & 0 deletions netsim/ansible/templates/evpn/crpd.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% include 'vjunos-switch.j2' %}
37 changes: 37 additions & 0 deletions netsim/ansible/templates/gateway/crpd.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
protocols {
vrrp {
version-3;
}
}

{# VRRP interfaces #}
{% for intf in interfaces if intf.gateway.protocol|default('none') == 'vrrp' %}
{% if loop.first %}
interfaces {
{% endif %}
{{ intf.ifname }} {
unit 0 {
{% for af in 'ipv4','ipv6' if af in intf.gateway and af in intf and intf[af] is string %}
family {{ 'inet' if af == 'ipv4' else 'inet6' }} {
address {{ intf[af] }} {
{{ 'vrrp-group' if af == 'ipv4' else 'vrrp-inet6-group' }} {{ intf.gateway.vrrp.group }} {
{{ 'virtual-address' if af == 'ipv4' else 'virtual-inet6-address'
}} {{ intf.gateway[af]|ansible.utils.ipaddr('address') }} {
device-name {{ intf.ifname }};
}
{% if 'priority' in intf.gateway.vrrp %}
priority {{ intf.gateway.vrrp.priority }};
{% endif %}
{% if not intf.gateway.vrrp.preempt|default(True) %}
no-preempt;
{% endif %}
}
}
}
{% endfor %}
}
}
{% if loop.last %}
}
{% endif %}
{% endfor %}
4 changes: 4 additions & 0 deletions netsim/ansible/templates/initial/crpd.j2
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{% if vrfs is defined %}
{% include 'junos.vrf.j2' %}
{% endif %}

interfaces {
{% for l in netlab_interfaces|default([]) %}
{{ l.ifname }} {
Expand Down
5 changes: 3 additions & 2 deletions netsim/ansible/templates/mpls/junos.mplsvpn.j2
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{% if vrfs is defined %}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I know why the Junos MPLS/VPN RR tests were failing ;) Thank you!

{# set vrf per table label #}

routing-instances {
{% for vname,vdata in vrfs.items() %}
{{ vname }} {
vrf-table-label;
vrf-table-label;
}
{% endfor %}
}
{% endif %}

{# set bgp af inet-vpn and/or inet6-vpn #}
protocols {
Expand Down
26 changes: 25 additions & 1 deletion netsim/devices/crpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,31 @@
#
from box import Box

from . import _Quirks
from ..utils import log
from . import _Quirks, report_quirk


def vrf_route_leaking(node: Box) -> None:
for vname,vdata in node.get('vrfs',{}).items():
if '_leaked_routes' in vdata:
report_quirk(
text=f'Inter-VRF route leaking does not work on cRPD (node {node.name} vrf {vname})',
node=node,
category=log.IncorrectValue,
quirk='vrf_route_leak')

def vpnv6_data_plane(node: Box) -> None:
if not node.get('mpls.vpn.ipv6',None):
return

for vname,vdata in node.get('vrfs',{}).items():
if vdata.get('af.ipv6',False):
report_quirk(
text=f'MPLS VPNv6 data plane does not work on cRPD (node {node.name} vrf {vname})',
node=node,
category=log.IncorrectValue,
quirk='vpnv6_fwd')

class CRPD(_Quirks):

@classmethod
Expand All @@ -20,3 +42,5 @@ def device_quirks(self, node: Box, topology: Box) -> None:
junos.community_set_quirk(node,topology)
junos.default_originate_check(node,topology)
junos.build_bgp_import_export_policy_chain(node,topology)
vrf_route_leaking(node)
vpnv6_data_plane(node)
12 changes: 10 additions & 2 deletions netsim/devices/crpd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,31 @@ loopback_interface_name: "lo0"
mtu: 1500

features:
initial:
ipv4:
unnumbered: false # The 'unnumbered-address' family inet command does not work on cRPD
vlan: false
vxlan: false
vrf: false
gateway: false
evpn:
irb: true
gateway:
protocol: [ vrrp ]

clab:
image: crpd:24.4R1.9
build: https://containerlab.dev/manual/kinds/crpd/
node:
kind: juniper_crpd
config_templates:
hosts: /etc/hosts:shared
interface:
name: eth{ifindex+1}
features:
initial:
# config_mode: [ sh ]
group_vars:
# netlab_config_mode: sh
netlab_show_command: [ cli, -c, 'show $@' ]
netlab_check_command: who
netlab_ready: [ ssh ]
# ansible_connection: docker
Expand Down
1 change: 1 addition & 0 deletions netsim/templates/provider/clab/crpd/hosts.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% include 'linux/hosts.j2' %}
1 change: 0 additions & 1 deletion netsim/templates/provider/clab/linux/hosts-common.j2

This file was deleted.

2 changes: 1 addition & 1 deletion netsim/templates/provider/clab/linux/hosts.j2
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ ff02::2 ip6-allrouters
{% if _hosts_entries is defined %}
{{ _hosts_entries }}
{% else %}
{% include 'hosts-common.j2' %}
{% include 'templates/initial/linux/hosts-common.j2' %}
{% endif %}
7 changes: 7 additions & 0 deletions netsim/validate/crpd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#
# cRPD is running on top of Linux and starts a Linux shell, making it
# possible to do Linux pings in validation checks
#
# However, we have to tell Ruff that we know what we're doing ;)
#
from netsim.validate.linux import exec_ping, valid_ping # noqa: F401