Skip to content

Commit c99b479

Browse files
authored
ospf.areas support for Dell OS10 & Cumulus NVUE (#2364)
1 parent 7f9129d commit c99b479

File tree

7 files changed

+136
-6
lines changed

7 files changed

+136
-6
lines changed

docs/caveats.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ Other caveats:
245245
* The default MTU value is 1500 to match the implementation defaults from other vendors and enable things like seamless OSPF peering.
246246
* *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.
247247
* 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.
248+
* Cumulus NVUE does not support OSPFv3
248249

249250
(caveats-os10)=
250251
## Dell OS10
@@ -253,6 +254,7 @@ Other caveats:
253254
* Sadly, it's also **NOT** possible to use *VRRP* on a *Virtual Network* interface (but *anycast* gateway is supported).
254255
* At the same time, the *anycast* gateway is not supported on plain *ethernet* interfaces, so you need to use *VRRP* there.
255256
* 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).
257+
* OSPF NSSA areas are not supported for OSPFv3
256258

257259
### VRRP Caveats
258260
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

docs/plugins/ospf.areas.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ The plugin also supports suppressing inter-area routes in stub/NSSA areas, resul
99
The plugin includes Jinja2 templates for the following platforms:
1010

1111
| Operating system | Stub/NSSA<br>areas | Totally<br>stubby areas | Area ranges |
12-
|-----------|:-:|:-:|:-:|
13-
| Arista EOS |[](caveats-eos) |||
14-
| FRR |||[](caveats-frr) |
15-
| JunOS ||||
12+
|--------------|:-:|:-:|:-:|
13+
| Arista EOS |[](caveats-eos) |||
14+
| Cumulus NVUE |||[](caveats-cumulus-nvue) |
15+
| Dell OS10 |||[](caveats-os10) |
16+
| FRR |||[](caveats-frr) |
17+
| JunOS ||||
1618

1719
## Specifying OSPF Area Parameters
1820

netsim/devices/cumulus_nvue.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from . import _Quirks, report_quirk
77
# from .cumulus import Cumulus # This causes Cumulus_Nvue to get skipped
88
from .cumulus import check_ospf_vrf_default
9-
from ..utils import log
9+
from ..utils import log, routing as _rp_utils
1010
from ..augment import devices
1111
from .. import data
1212
import netaddr
@@ -154,6 +154,21 @@ def mark_shared_mlag_vtep(node: Box, topology: Box) -> None:
154154
node.vxlan._shared_vtep = n.name
155155
return
156156

157+
def nvue_check_nssa_summarize(node: Box) -> None:
158+
for (odata,_,_) in _rp_utils.rp_data(node,'ospf'):
159+
if 'areas' not in odata:
160+
continue
161+
for area in odata.areas:
162+
if area.kind != 'nssa':
163+
continue
164+
if 'external_range' in area or 'external_filter' in area:
165+
report_quirk(
166+
f'{node.name} cannot summarize type-7 NSSA routes (area {area.area})',
167+
more_hints = [ 'Cumulus cannot configure NSSA type-7 ranges, FRR version too old' ],
168+
node=node,
169+
category=Warning,
170+
quirk='ospf_nssa_range')
171+
157172
class Cumulus_Nvue(_Quirks):
158173

159174
@classmethod
@@ -166,6 +181,7 @@ def device_quirks(self, node: Box, topology: Box) -> None:
166181
nvue_check_ospf_passive_in_vrf(node)
167182
nvue_check_ospf_vrf_loopbacks(node)
168183
nvue_check_ospfv3(node)
184+
nvue_check_nssa_summarize(node)
169185
nvue_merge_ospf_loopbacks(node)
170186

171187
if 'stp' in mods:

netsim/devices/dellos10.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from box import Box,BoxList
55

66
from . import _Quirks,need_ansible_collection,report_quirk
7-
from ..utils import log
7+
from ..utils import log, routing as _rp_utils
88
from ..augment import devices
99

1010
def check_vlan_ospf(node: Box, iflist: BoxList, vname: str) -> None:
@@ -99,6 +99,27 @@ def check_expanded_communities(node:Box, topology: Box) -> None:
9999
quirk='non-standard_communities',
100100
node=node)
101101

102+
def check_nssa_area_limitations(node: Box) -> None:
103+
for (odata,_,_) in _rp_utils.rp_data(node,'ospf'):
104+
if 'areas' not in odata:
105+
continue
106+
for area in odata.areas:
107+
if area.kind != 'nssa':
108+
continue
109+
if 'ipv6' in odata.af:
110+
report_quirk(
111+
f'{node.name} cannot configure NSSA type areas for OSPFv3 (area {area.area})',
112+
more_hints = [ 'Dell OS10 does not support NSSA for OSPFv3' ],
113+
node=node,
114+
quirk='ospfv3_nssa')
115+
if 'external_range' in area or 'external_filter' in area:
116+
report_quirk(
117+
f'{node.name} cannot summarize type-7 NSSA routes (area {area.area})',
118+
more_hints = [ 'Dell OS10 cannot configure NSSA type-7 ranges' ],
119+
node=node,
120+
category=Warning,
121+
quirk='ospf_nssa_range')
122+
102123
class OS10(_Quirks):
103124

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

113135
if 'gateway' in mods:
114136
if 'anycast' in node.get('gateway',{}):
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
{% macro area_config(adata,af,abr) %}
3+
{% set kind = 'normal' if adata.kind == 'regular' else adata.kind %}
4+
{{ adata.area }}:
5+
type: {{ 'totally-' if not adata.inter_area else '' }}{{ kind }}
6+
{% if adata.kind in ['stub','nssa'] and adata.default.cost is defined and af == 'ipv4' %}
7+
default-lsa-cost: {{ adata.default.cost }}
8+
{% endif %}
9+
{% if abr %}
10+
{% for range in adata.range|default([])+adata.filter|default([]) if af in range %}
11+
{% if loop.first %}
12+
range:
13+
{% endif %}
14+
{{ range[af] }}:
15+
suppress: {{ 'on' if range in adata.filter|default([]) else 'off' }}
16+
{% endfor %}
17+
{% endif %}
18+
{% endmacro %}
19+
20+
{% macro ospf_area_config(odata,vrf='') %}
21+
{% for af in ['ipv4'] if odata.af[af] is defined %}
22+
{% if loop.first %}
23+
- set:
24+
vrf:
25+
{{ vrf if vrf else 'default' }}:
26+
router:
27+
ospf:
28+
area:
29+
{% endif %}
30+
{% for adata in odata.areas %}
31+
{{ area_config(adata,af,odata._abr|default(false)) -}}
32+
{% endfor %}
33+
{% endfor %}
34+
{% endmacro %}
35+
36+
{% if ospf.areas is defined %}
37+
{{ ospf_area_config(ospf,'') }}
38+
{% endif %}
39+
{% if vrfs is defined %}
40+
{% for vname,vdata in vrfs.items() if vdata.ospf.areas is defined %}
41+
{{ ospf_area_config(vdata.ospf,vname) }}
42+
{% endfor %}
43+
{% endif %}
44+

netsim/extra/ospf.areas/defaults.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#
33
---
44
devices:
5+
cumulus_nvue.features.ospf.areas: True
6+
dellos10.features.ospf.areas: True
57
frr.features.ospf.areas: True
68
eos.features.ospf.areas: True
79
junos.features.ospf.areas: True
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{% macro area_config(adata,af,abr) %}
2+
{% if adata.kind == 'stub' %}
3+
area {{ adata.area }} stub {% if not adata.inter_area %}no-summary{% endif +%}
4+
{% endif %}
5+
{% if adata.kind == 'nssa' and af == 'ipv4' %}
6+
area {{ adata.area }} nssa {% if not adata.inter_area %}no-summary{% endif +%}
7+
{% if abr and adata.default|default(false) %}
8+
area {{ adata.area }} nssa default-information-originate
9+
{% endif %}
10+
{% endif %}
11+
{% if adata.kind in ['stub','nssa'] and adata.default.cost is defined and af == 'ipv4' %}
12+
area {{ adata.area }} default-cost {{ adata.default.cost }}
13+
{% endif %}
14+
{% if abr %}
15+
{% for range in adata.range|default([]) if af in range %}
16+
area {{ adata.area }} range {{ range[af] }}
17+
{% endfor %}
18+
{% for range in adata.filter|default([]) if af in range %}
19+
area {{ adata.area }} range {{ range[af] }} no-advertise
20+
{% endfor %}
21+
{% endif %}
22+
{% endmacro %}
23+
24+
{% macro ospf_area_config(odata,vrf='',pid=1) %}
25+
{% for af in ['ipv4','ipv6'] if odata.af[af] is defined %}
26+
{% set proto = 'ospf' if af == 'ipv4' else 'ospfv3' %}
27+
router {{ proto }} {{ pid }}{% if vrf %} vrf {{ vrf }}{% endif +%}
28+
{% for adata in odata.areas %}
29+
{{ area_config(adata,af,odata._abr|default(false)) -}}
30+
{% endfor %}
31+
exit
32+
{% endfor %}
33+
{% endmacro %}
34+
35+
{% if ospf.areas is defined %}
36+
{{ ospf_area_config(ospf,'',ospf.process|default(1)) }}
37+
{% endif %}
38+
{% if vrfs is defined %}
39+
{% for vname,vdata in vrfs.items() if vdata.ospf.areas is defined %}
40+
{{ ospf_area_config(vdata.ospf,vname,vdata.vrfidx) }}
41+
{% endfor %}
42+
{% endif %}

0 commit comments

Comments
 (0)