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
2 changes: 2 additions & 0 deletions docs/caveats.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ Other caveats:
* The default MTU value is 1500 to match the implementation defaults from other vendors and enable things like seamless OSPF peering.
* *netlab* uses Cumulus VX 5.3 containers created by Michael Kashin and downloaded from his Docker Hub account. These containers are severely out-of-date, are not tested in our integration tests, and might not work as expected.
* Some features - such as VRF route leaking and route advertisement in the default VRF (used in certain EVPN scenarios) - are not supported by NVUE, and require the use of custom config *snippets*. Only one such snippet is supported per configuration file (e.g. /etc/frr/frr.conf), which means a topology using a combination of multiple features that all require *snippets* will not work.
* Cumulus NVUE does not support OSPFv3

(caveats-os10)=
## Dell OS10
Expand All @@ -253,6 +254,7 @@ Other caveats:
* Sadly, it's also **NOT** possible to use *VRRP* on a *Virtual Network* interface (but *anycast* gateway is supported).
* At the same time, the *anycast* gateway is not supported on plain *ethernet* interfaces, so you need to use *VRRP* there.
* Dell OS10 only allows configuring of the EVPN RD in the form `X.X.X.X:N.` By default, *netlab* uses `N:M` for L3VNI, so on this platform the L3VNI RD is derived from the Router-ID and the VRF ID as `router-id:vrf-id` (and the one generated by *netlab* is not used).
* OSPF NSSA areas are not supported for OSPFv3

### VRRP Caveats
Netlab enables VRRPv3 by default on Dell OS10, overriding any platform defaults. If you need VRRPv2, check out the [vrrp.version](plugin-vrrp-version) plugin
Expand Down
10 changes: 6 additions & 4 deletions docs/plugins/ospf.areas.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ The plugin also supports suppressing inter-area routes in stub/NSSA areas, resul
The plugin includes Jinja2 templates for the following platforms:

| Operating system | Stub/NSSA<br>areas | Totally<br>stubby areas | Area ranges |
|-----------|:-:|:-:|:-:|
| Arista EOS | ✅ [❗](caveats-eos) |✅|✅|
| FRR |✅|✅|✅ [❗](caveats-frr) |
| JunOS |✅|✅|✅ |
|--------------|:-:|:-:|:-:|
| Arista EOS |✅ [❗](caveats-eos) |✅|✅|
| Cumulus NVUE |✅|✅|✅ [❗](caveats-cumulus-nvue) |
| Dell OS10 |✅|✅|✅ [❗](caveats-os10) |
| FRR |✅|✅|✅ [❗](caveats-frr) |
| JunOS |✅|✅|✅|

## Specifying OSPF Area Parameters

Expand Down
18 changes: 17 additions & 1 deletion netsim/devices/cumulus_nvue.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from . import _Quirks, report_quirk
# from .cumulus import Cumulus # This causes Cumulus_Nvue to get skipped
from .cumulus import check_ospf_vrf_default
from ..utils import log
from ..utils import log, routing as _rp_utils
from ..augment import devices
from .. import data
import netaddr
Expand Down Expand Up @@ -154,6 +154,21 @@ def mark_shared_mlag_vtep(node: Box, topology: Box) -> None:
node.vxlan._shared_vtep = n.name
return

def nvue_check_nssa_summarize(node: Box) -> None:
for (odata,_,_) in _rp_utils.rp_data(node,'ospf'):
if 'areas' not in odata:
continue
for area in odata.areas:
if area.kind != 'nssa':
continue
if 'external_range' in area or 'external_filter' in area:
report_quirk(
f'{node.name} cannot summarize type-7 NSSA routes (area {area.area})',
more_hints = [ 'Cumulus cannot configure NSSA type-7 ranges, FRR version too old' ],
node=node,
category=Warning,
quirk='ospf_nssa_range')

class Cumulus_Nvue(_Quirks):

@classmethod
Expand All @@ -166,6 +181,7 @@ def device_quirks(self, node: Box, topology: Box) -> None:
nvue_check_ospf_passive_in_vrf(node)
nvue_check_ospf_vrf_loopbacks(node)
nvue_check_ospfv3(node)
nvue_check_nssa_summarize(node)
nvue_merge_ospf_loopbacks(node)

if 'stp' in mods:
Expand Down
24 changes: 23 additions & 1 deletion netsim/devices/dellos10.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from box import Box,BoxList

from . import _Quirks,need_ansible_collection,report_quirk
from ..utils import log
from ..utils import log, routing as _rp_utils
from ..augment import devices

def check_vlan_ospf(node: Box, iflist: BoxList, vname: str) -> None:
Expand Down Expand Up @@ -99,6 +99,27 @@ def check_expanded_communities(node:Box, topology: Box) -> None:
quirk='non-standard_communities',
node=node)

def check_nssa_area_limitations(node: Box) -> None:
for (odata,_,_) in _rp_utils.rp_data(node,'ospf'):
if 'areas' not in odata:
continue
for area in odata.areas:
if area.kind != 'nssa':
continue
if 'ipv6' in odata.af:
report_quirk(
f'{node.name} cannot configure NSSA type areas for OSPFv3 (area {area.area})',
more_hints = [ 'Dell OS10 does not support NSSA for OSPFv3' ],
node=node,
quirk='ospfv3_nssa')
if 'external_range' in area or 'external_filter' in area:
report_quirk(
f'{node.name} cannot summarize type-7 NSSA routes (area {area.area})',
more_hints = [ 'Dell OS10 cannot configure NSSA type-7 ranges' ],
node=node,
category=Warning,
quirk='ospf_nssa_range')

class OS10(_Quirks):

@classmethod
Expand All @@ -109,6 +130,7 @@ def device_quirks(self, node: Box, topology: Box) -> None:
for vname,vdata in node.get('vrfs',{}).items():
check_vlan_ospf(node,vdata.get('ospf.interfaces',[]),vname)
check_ospf_originate_default(node)
check_nssa_area_limitations(node)

if 'gateway' in mods:
if 'anycast' in node.get('gateway',{}):
Expand Down
44 changes: 44 additions & 0 deletions netsim/extra/ospf.areas/cumulus_nvue.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
{% macro area_config(adata,af,abr) %}
{% set kind = 'normal' if adata.kind == 'regular' else adata.kind %}
{{ adata.area }}:
type: {{ 'totally-' if not adata.inter_area else '' }}{{ kind }}
{% if adata.kind in ['stub','nssa'] and adata.default.cost is defined and af == 'ipv4' %}
default-lsa-cost: {{ adata.default.cost }}
{% endif %}
{% if abr %}
{% for range in adata.range|default([])+adata.filter|default([]) if af in range %}
{% if loop.first %}
range:
{% endif %}
{{ range[af] }}:
suppress: {{ 'on' if range in adata.filter|default([]) else 'off' }}
{% endfor %}
{% endif %}
{% endmacro %}

{% macro ospf_area_config(odata,vrf='') %}
{% for af in ['ipv4'] if odata.af[af] is defined %}
{% if loop.first %}
- set:
vrf:
{{ vrf if vrf else 'default' }}:
router:
ospf:
area:
{% endif %}
{% for adata in odata.areas %}
{{ area_config(adata,af,odata._abr|default(false)) -}}
{% endfor %}
{% endfor %}
{% endmacro %}

{% if ospf.areas is defined %}
{{ ospf_area_config(ospf,'') }}
{% endif %}
{% if vrfs is defined %}
{% for vname,vdata in vrfs.items() if vdata.ospf.areas is defined %}
{{ ospf_area_config(vdata.ospf,vname) }}
{% endfor %}
{% endif %}

2 changes: 2 additions & 0 deletions netsim/extra/ospf.areas/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
---
devices:
cumulus_nvue.features.ospf.areas: True
dellos10.features.ospf.areas: True
frr.features.ospf.areas: True
eos.features.ospf.areas: True
junos.features.ospf.areas: True
Expand Down
42 changes: 42 additions & 0 deletions netsim/extra/ospf.areas/dellos10.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% macro area_config(adata,af,abr) %}
{% if adata.kind == 'stub' %}
area {{ adata.area }} stub {% if not adata.inter_area %}no-summary{% endif +%}
{% endif %}
{% if adata.kind == 'nssa' and af == 'ipv4' %}
area {{ adata.area }} nssa {% if not adata.inter_area %}no-summary{% endif +%}
{% if abr and adata.default|default(false) %}
area {{ adata.area }} nssa default-information-originate
{% endif %}
{% endif %}
{% if adata.kind in ['stub','nssa'] and adata.default.cost is defined and af == 'ipv4' %}
area {{ adata.area }} default-cost {{ adata.default.cost }}
{% endif %}
{% if abr %}
{% for range in adata.range|default([]) if af in range %}
area {{ adata.area }} range {{ range[af] }}
{% endfor %}
{% for range in adata.filter|default([]) if af in range %}
area {{ adata.area }} range {{ range[af] }} no-advertise
{% endfor %}
{% endif %}
{% endmacro %}

{% macro ospf_area_config(odata,vrf='',pid=1) %}
{% for af in ['ipv4','ipv6'] if odata.af[af] is defined %}
{% set proto = 'ospf' if af == 'ipv4' else 'ospfv3' %}
router {{ proto }} {{ pid }}{% if vrf %} vrf {{ vrf }}{% endif +%}
{% for adata in odata.areas %}
{{ area_config(adata,af,odata._abr|default(false)) -}}
{% endfor %}
exit
{% endfor %}
{% endmacro %}

{% if ospf.areas is defined %}
{{ ospf_area_config(ospf,'',ospf.process|default(1)) }}
{% endif %}
{% if vrfs is defined %}
{% for vname,vdata in vrfs.items() if vdata.ospf.areas is defined %}
{{ ospf_area_config(vdata.ospf,vname,vdata.vrfidx) }}
{% endfor %}
{% endif %}