Skip to content

Commit be14c76

Browse files
OSPFv2/v3 support for OpenBSD devices (ipspace#2697)
Also: * Increase the integration test OSPFv3 SPF waiting time for OpenBSD --------- Co-authored-by: Ivan Pepelnjak <ip@ipspace.net>
1 parent aa29d3a commit be14c76

File tree

11 files changed

+169
-4
lines changed

11 files changed

+169
-4
lines changed

docs/caveats.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,8 @@ See also [](caveats-sros) caveats for further details.
502502

503503
* The virtual disk size of the `qcow2` image you can download from https://bsd-cloud-image.org/ is too small to survive the kernel reordering OpenBSD performs after every boot.
504504
* The kernel reordering is disabled in the Vagrant box, leaving you with approximately 170 MB of free disk space. You'll have a bit less than that in the *vrnetlab* container.
505-
* The default role of OpenBSD nodes is **host** unless the node has a loopback interface, in which case the **host** mode is automatically changed to **router** (contrary to most other network devices, OpenBSD does not you allow you to reach non-connected IP addresses unless the IPv4/IPv6 forwarding is enabled).
505+
* OpenBSD OSPFv3 implementation does not support ABR functionality. It also advertises passive interfaces with a very high cost.
506+
* The device role on nodes with a loopback interface is automatically changed to **router** (contrary to most other network devices, OpenBSD does not allow you to reach non-connected IP addresses unless the IPv4/IPv6 forwarding is enabled).
506507

507508
(caveats-sonic)=
508509
## Sonic

docs/labs/openbsd.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(build-openbsd)=
22
# Building an OpenBSD Libvirt Box
33

4-
You can use the **netlab libvirt package** command to build a OpenBSD Vagrant box:
4+
You can use the **netlab libvirt package** command to build an OpenBSD Vagrant box:
55

6-
* Download the OpenBSD **qcow2** image from https://bsd-cloud-image.org/ into an empty directory
6+
* Download the OpenBSD **qcow2** image from [https://bsd-cloud-image.org/](https://bsd-cloud-image.org/) into an empty directory
77
* Execute **netlab libvirt package openbsd _img-file-name_** and follow the instructions
88

99
```{warning}

docs/module/ospf.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ The following table describes the per-platform support of individual router-leve
6868
| Mikrotik RouterOS 7 ||||||
6969
| Nokia SR Linux ||||[](caveats-srlinux) |[](caveats-srlinux) |
7070
| Nokia SR OS[^SROS] ||||[](caveats-sros) ||
71+
| OpenBSD |||[](caveats-openbsd) |||
7172
| VyOS ||||||
7273

7374

@@ -132,6 +133,7 @@ The following table documents the common interface-level OSPF features:
132133
| Mikrotik RouterOS 7 |||||
133134
| Nokia SR Linux |||||
134135
| Nokia SR OS[^SROS] |||||
136+
| OpenBSD ||||[](caveats-openbsd) |
135137
| VyOS |||||
136138

137139
**Notes:**
@@ -162,6 +164,7 @@ These devices also support optional OSPF interface attributes:
162164
| Cumulus Linux 5.x (NVUE) |||||
163165
| Dell OS10 |||||
164166
| FRR |||||
167+
| OpenBSD |||||
165168

166169
OSPF routing daemons support these optional OSPF interface attributes:
167170

docs/platforms.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ Routing protocol [configuration modules](module-reference.md) are supported on t
325325
| Mikrotik RouterOS 7 ||||||
326326
| Nokia SR Linux ||||||
327327
| Nokia SR OS[^SROS] ||||||
328+
| OpenBSD ||||||
328329
| Sonic ||||||
329330
| VyOS ||||||
330331

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{% import "openbsd.ospfv2.j2" as ospfv2 %}
2+
{% import "openbsd.ospfv3.j2" as ospfv3 %}
3+
{% if ospf.af.ipv4 is defined %}
4+
{{ ospfv2.config(False,ospf,netlab_interfaces) }}
5+
{% endif %}
6+
{% if ospf.af.ipv6 is defined %}
7+
{{ ospfv3.config(False,ospf,netlab_interfaces) }}
8+
{% endif %}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{% macro config(ospf_vrf,ospf_data,intf_data) %}
2+
{%- set areas = intf_data|selectattr('ipv4', 'defined')|map(attribute='ospf.area', default='')|reject('eq', '')|sort|unique %}
3+
#!/bin/sh
4+
5+
cat <<OSPFD_CONF >/etc/ospfd.conf
6+
{% if ospf_data.router_id|ipv4 %}
7+
router-id {{ ospf_data.router_id }}
8+
{% endif %}
9+
spf-delay msec 100
10+
spf-holdtime msec 200
11+
{% if ospf_data.default is defined %}
12+
{% set dfd = ospf_data.default %}
13+
redistribute default set { metric {{ dfd.cost|default(100) }} type {{ dfd.type|default('e1')|replace('e','') }} }
14+
{% endif %}
15+
16+
{% for a in areas %}
17+
area {{ a }} {
18+
{% for l in intf_data if l.ospf.area is defined and l.ospf.area is eq a and 'ipv4' in l %}
19+
{% if l.ifname == "lo0" %}
20+
interface {{ l.ifname }}:{{ l.ipv4 | ipaddr('address') }} {
21+
{% else %}
22+
interface {{ l.ifname }} {
23+
{% endif %}
24+
{% if l.ospf.network_type is defined and l.ospf.network_type == 'point-to-point' %}
25+
type p2p
26+
{% endif %}
27+
{% if l.ospf.passive|default(False) %}
28+
passive
29+
{% endif %}
30+
{% if l.ospf.cost is defined %}
31+
metric {{ l.ospf.cost }}
32+
{% endif %}
33+
{% if l.ospf.timers.hello is defined %}
34+
hello-interval {{ l.ospf.timers.hello }}
35+
{% endif %}
36+
{% if l.ospf.timers.dead is defined %}
37+
router-dead-time {{ l.ospf.timers.dead }}
38+
{% endif %}
39+
{% if l.ospf.priority is defined %}
40+
router-priority {{ l.ospf.priority }}
41+
{% endif %}
42+
{% if l.ospf.password is defined %}
43+
auth-key {{ l.ospf.password }}
44+
auth-type simple
45+
{% endif %}
46+
}
47+
{% endfor -%}
48+
}
49+
{% endfor %}
50+
OSPFD_CONF
51+
52+
chmod 640 /etc/ospfd.conf
53+
rcctl enable ospfd
54+
rcctl restart ospfd
55+
{% endmacro %}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{% macro config(ospf_vrf,ospf_data,intf_data) %}
2+
{%- set areas = intf_data|selectattr('ipv6', 'defined')|map(attribute='ospf.area', default='')|reject('eq', '')|sort|unique %}
3+
#!/bin/sh
4+
5+
cat <<OSPFD_CONF >/etc/ospf6d.conf
6+
{% if ospf_data.router_id is defined %}
7+
router-id {{ ospf_data.router_id }}
8+
{% endif %}
9+
spf-delay 1
10+
spf-holdtime 1
11+
{% if ospf_data.default is defined %}
12+
{% set dfd = ospf_data.default %}
13+
redistribute default set { metric {{ dfd.cost|default(100) }} type {{ dfd.type|default('e1')|replace('e','') }} }
14+
{% endif %}
15+
16+
{% for a in areas %}
17+
area {{ a }} {
18+
{% for l in intf_data if l.ospf.area is defined and l.ospf.area is eq a and 'ipv6' in l %}
19+
interface {{ l.ifname }} {
20+
{% if l.ospf.network_type is defined and l.ospf.network_type == 'point-to-point' %}
21+
type p2p
22+
{% endif %}
23+
{% if l.ospf.passive|default(False) %}
24+
passive
25+
{% endif %}
26+
{% if l.ospf.cost is defined %}
27+
metric {{ l.ospf.cost }}
28+
{% endif %}
29+
{% if l.ospf.timers.hello is defined %}
30+
hello-interval {{ l.ospf.timers.hello }}
31+
{% endif %}
32+
{% if l.ospf.timers.dead is defined %}
33+
router-dead-time {{ l.ospf.timers.dead }}
34+
{% endif %}
35+
{% if l.ospf.priority is defined %}
36+
router-priority {{ l.ospf.priority }}
37+
{% endif %}
38+
}
39+
{% endfor -%}
40+
}
41+
{% endfor %}
42+
OSPFD_CONF
43+
44+
chmod 640 /etc/ospf6d.conf
45+
rcctl enable ospf6d
46+
rcctl restart ospf6d
47+
{% endmacro %}

netsim/devices/openbsd.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44
from box import Box
55

6+
from ..utils import log
67
from . import _Quirks, report_quirk
78
from ._common import check_indirect_static_routes
89

@@ -22,9 +23,45 @@ def check_loopback(node: Box, topology: Box) -> None:
2223
category=Warning,
2324
node=node)
2425

26+
"""
27+
OpenBSD OSPFv3 implementation is not an ABR
28+
"""
29+
def check_ospf6_quirks(node: Box) -> None:
30+
if 'ospf' not in node.get('module',[]): # Is the device running OSPF?
31+
return
32+
if 'ipv6' not in node.ospf.get('af',{}): # Does it run OSPF with IPv6?
33+
return
34+
area_set = { intf.ospf.area # Collect OSPF areas into a set
35+
for intf in node.interfaces + # ... going through all interfaces
36+
[ node.get('loopback',{}) ] # ... plus the loopback
37+
if 'ospf' in intf and 'ipv6' in intf } # ... when the interface uses OSPF and has an IPv6 address
38+
if len(area_set) > 1: # Do we have more than one area per device?
39+
report_quirk(
40+
f'node {node.name} cannot be an OSPFv3 ABR',
41+
more_hints=['OpenBSD OSPFv3 daemon does not implement the ABR functionality'],
42+
quirk='ospfv3_abr',
43+
category=log.IncorrectType,
44+
node=node)
45+
46+
passive_list = []
47+
for intf in node.interfaces: # Next, check for 'passive' OSPF interfaces
48+
if 'ospf' not in intf or 'ipv6' not in intf: # Skip interfaces not running OSPF or not having an IPv6 address
49+
continue
50+
if 'cost' in intf.ospf and 'passive' in intf.ospf: # Find passive interfaces with explicit cost
51+
passive_list.append(intf.ifname)
52+
53+
if passive_list:
54+
report_quirk(
55+
f'node {node.name} uses passive OSPFv3 interfaces with OSPF cost ({",".join(passive_list)})',
56+
more_hints=['OpenBSD OSPFv3 daemon sets the cost of passive interfaces to 65535'],
57+
quirk='ospfv3_passive',
58+
category=Warning,
59+
node=node)
60+
2561
class OpenBSD(_Quirks):
2662

2763
@classmethod
2864
def device_quirks(self, node: Box, topology: Box) -> None:
2965
check_loopback(node,topology)
3066
check_indirect_static_routes(node)
67+
check_ospf6_quirks(node)

netsim/devices/openbsd.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ interface_name: vio{ifindex}
55
loopback_interface_name: lo{ifindex}
66
ifindex_offset: 1
77
mgmt_if: vio0
8-
role: host
8+
role: router
99
features:
1010
routing:
1111
static: true
@@ -14,6 +14,13 @@ features:
1414
ipv6:
1515
use_ra: true
1616
lla: true
17+
ospf:
18+
unnumbered: false
19+
import: [ connected, static ]
20+
default: true
21+
password: true
22+
priority: true
23+
timers: true
1724
libvirt:
1825
create_template: openbsd.xml.j2
1926
image: netlab/openbsd

tests/integration/ospf/ospfv3/01-network.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ links:
3030
ospf.network_type: point-to-point
3131
mtu: 1500
3232

33+
defaults.devices.openbsd.netlab_validate.x1_lb.wait: 20
34+
defaults.devices.openbsd.netlab_validate.x2_lb.wait: 20
35+
3336
validate:
3437
adj:
3538
description: Check OSPF adjacencies

0 commit comments

Comments
 (0)