Skip to content
Open
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
3 changes: 3 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ All notable changes to the project are documented in this file.
`ripng`/`ospfv3` type and the IPv6 address-family
- Support building without Frr, which also drops bash. The minimal
defconfigs are now built this way, with static routing only, issue #1670
- Configurable OSPF auto-cost reference bandwidth, for OSPFv2 and OSPFv3,
issue #1576. The default, 100000 Mbit/s, is the value used before, so
link costs do not change on upgrade. The CLI shows it in `show ip ospf`
- Check for a new software release on demand: `upgrade` without a bundle in
the CLI, the Check now button on the WebUI dashboard, or the `check-update`
RPC, see [Unattended Software Updates][unattended]
Expand Down
22 changes: 21 additions & 1 deletion doc/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,13 @@ admin@example:/>
### OSPF global settings

In addition to *area* and *interface* specific settings, OSPF provides
global settings for route redistribution and OSPF router identifier.
global settings for route redistribution, OSPF router identifier, and
the reference bandwidth used to calculate interface costs.

<pre class="cli"><code>admin@example:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@example:/config/routing/…/ospf/> <b>set ?</b>
area List of OSPF areas.
auto-cost Interface auto-cost configuration state.
default-route-advertise Distribute default route to network
explicit-router-id Defined in RFC 2328. A 32-bit number
redistribute Redistribute protocols into OSPF
Expand All @@ -242,6 +244,24 @@ admin@example:/config/routing/…/ospf/> set
router will distribute a default route even when it lacks a default
route. The default route will be distributed as an *external type-2*
(E2) route.
- Reference bandwidth: Routers from different vendors only agree on
the shortest path if they use the same reference bandwidth. The cost
of an interface without an explicit `cost` is the reference bandwidth
divided by the link speed, rounded, with 1 as the lowest cost. The
default is 100000 Mbit/s, which gives a 1 Gbit/s link cost 100. Use
`set auto-cost reference-bandwidth 10000` (Mbit/s) to change it. A
link of unknown speed, e.g., a virtual link, counts as 10000 Mbit/s.
Auto-cost can not be disabled.

`show ip ospf` shows the reference bandwidth in use, and `show ipv6
ospf` does the same for OSPFv3.

<pre class="cli"><code>admin@example:/> <b>show ip ospf</b>
OSPF Routing Process, Router ID: 192.168.10.1
Reference bandwidth: 100000 Mbit/s
Number of areas attached to this router: 1
...
</code></pre>


### Debug OSPFv2
Expand Down
10 changes: 8 additions & 2 deletions src/confd/src/routing.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ int parse_ospf_areas(sr_session_ctx_t *session, struct lyd_node *areas, FILE *fp
int parse_ospf(sr_session_ctx_t *session, struct lyd_node *ospf)
{
struct lyd_node *areas, *default_route, *debug;
const char *router_id;
const char *router_id, *refbw;
int bfd_enabled = 0;
int num_areas = 0;
FILE *fp;
Expand Down Expand Up @@ -381,6 +381,9 @@ int parse_ospf(sr_session_ctx_t *session, struct lyd_node *ospf)
}
}

refbw = lydx_get_cattr(lydx_get_child(ospf, "auto-cost"), "reference-bandwidth");
if (refbw)
fprintf(fp, " auto-cost reference-bandwidth %s\n", refbw);
if (router_id)
fprintf(fp, " ospf router-id %s\n", router_id);
fclose(fp);
Expand Down Expand Up @@ -429,7 +432,7 @@ static int parse_ospf6_areas(struct lyd_node *areas, FILE *fp)
int parse_ospf6(sr_session_ctx_t *session, struct lyd_node *ospf)
{
struct lyd_node *areas, *default_route, *debug;
const char *router_id;
const char *router_id, *refbw;
int bfd_enabled = 0;
int num_areas = 0;
FILE *fp;
Expand Down Expand Up @@ -489,6 +492,9 @@ int parse_ospf6(sr_session_ctx_t *session, struct lyd_node *ospf)
}
}

refbw = lydx_get_cattr(lydx_get_child(ospf, "auto-cost"), "reference-bandwidth");
if (refbw)
fprintf(fp, " auto-cost reference-bandwidth %s\n", refbw);
if (router_id)
fprintf(fp, " ospf6 router-id %s\n", router_id);
fclose(fp);
Expand Down
4 changes: 2 additions & 2 deletions src/confd/yang/confd.inc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ MODULES=(
"ietf-routing@2018-03-13.yang"
"ietf-ipv6-unicast-routing@2018-03-13.yang"
"ietf-ipv4-unicast-routing@2018-03-13.yang"
"ietf-ospf@2022-10-19.yang -e bfd -e explicit-router-id -e hybrid-interface"
"ietf-ospf@2022-10-19.yang -e auto-cost -e bfd -e explicit-router-id -e hybrid-interface"
"ietf-rip@2020-02-20.yang"
"iana-bfd-types@2021-10-21.yang"
"ietf-bfd-types@2022-09-22.yang"
Expand All @@ -31,7 +31,7 @@ MODULES=(
"ieee802-dot1q-types@2022-10-29.yang"
"infix-ip@2026-04-28.yang"
"infix-if-type@2026-01-07.yang"
"infix-routing@2026-09-28.yang"
"infix-routing@2026-10-07.yang"
"ieee802-dot1ab-lldp@2022-03-15.yang"
"infix-lldp@2025-05-05.yang"
"infix-dhcp-common@2025-12-21.yang"
Expand Down
32 changes: 26 additions & 6 deletions src/confd/yang/confd/infix-routing.yang
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,19 @@ module infix-routing {
contact "kernelkit@googlegroups.com";
description "Deviations and augments for ietf-routing, ietf-ospf, and ietf-rip.";

revision 2026-10-07 {
description "Add OSPF auto-cost reference-bandwidth, for OSPFv2 and
OSPFv3. The default 100000 Mbit/s matches the value
previously used, and auto-cost can not be disabled.";
reference "internal";
}

revision 2026-09-28 {
description "Add ospf, rip, and bfd features, where ospf covers OSPFv2
and OSPFv3, and rip covers RIPv2 and RIPng. A build without
FRR leaves them off, so only static routes can be configured
and the device advertises exactly what it supports.";
reference "Issue #1670";
reference "internal";
}

revision 2026-07-22 {
Expand Down Expand Up @@ -67,19 +74,19 @@ module infix-routing {
Allows displaying which area a route was learned from,
how long neighbors have been up, their DR/BDR role, and
the interface with local address.";
reference "Issue #1190";
reference "internal";
}

revision 2025-11-11 {
description "Add BFD IP single-hop support (RFC 9127).
Deviate session-statistics (not implemented yet).";
reference "RFC 9127, Issue #1190";
reference "RFC 9127";
}
revision 2025-11-10 {
description "Add must constraint to prevent backbone area as stub/NSSA.
Enable OSPF operational data for CLI: un-deviate priority,
hello-timer, wait-timer, route metric and route-tag fields.";
reference "RFC 2328, RFC 3101, Issue #1190";
reference "RFC 2328, RFC 3101";
}
revision 2024-11-27 {
description "Deviate address-family in OSPF";
Expand Down Expand Up @@ -423,8 +430,21 @@ module infix-routing {
}
}

deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:auto-cost" {
deviate not-supported;
/* The reference bandwidth must be the same on all routers in the OSPF
domain. Frr always derives the interface cost from it, unless a cost
is set on the interface, so auto-cost can not be disabled. */
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:auto-cost/ospf:enabled" {
deviate add {
default "true";
must ". = 'true'" {
error-message "Disabling OSPF auto-cost is not supported.";
}
}
}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:auto-cost/ospf:reference-bandwidth" {
deviate add {
default "100000";
}
Comment on lines +444 to +447

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This needs the eyes of an expert, @jovatn how will this affect existing Styx installations?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah, I see now that the default is the same as the previous hard-coded value in Frr. So less critical, but maybe we should change the default? What do you think @jovatn ...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm a bit in a hurry now, but lets discuss next week if you think we should change.
We have not discussed this, but my main intention was to use FRR defaults as Infix defaults (see initial description)

  • Then we should not need migration scripts
  • And I believe that 100Gbit/s is a better reference bandwidth for the future than 100Mbit/s (or whatever the standard may say).

Still, it is wise to lookup existing styx installations, although I believe/hope that adjustments (if needed) be done on appropriate repo than on mainline Infix.

}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:database" {
deviate not-supported;
Expand Down
3 changes: 3 additions & 0 deletions src/statd/python/cli_pretty/cli_pretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -5250,6 +5250,9 @@ def show_ospf(json_data):

# OSPF Process header
print(f" OSPF Routing Process, Router ID: {router_id}")
refbw = ospf.get('auto-cost', {}).get('reference-bandwidth')
if refbw is not None:
print(f" Reference bandwidth: {refbw} Mbit/s")
print(f" Number of areas attached to this router: {len(areas)}")
print()

Expand Down
23 changes: 23 additions & 0 deletions src/statd/python/yanger/ietf_ospf.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,27 @@ def add_routes(ospf, ipv6=False):
insert(ospf, "ietf-ospf:local-rib", "ietf-ospf:route", routes)


def add_auto_cost(ospf, daemon):
"""Report the auto-cost reference bandwidth (Mbit/s) of an OSPF daemon.

Frr has no JSON for it, and its running-config only lists the value
when it differs from the default, 100000 Mbit/s in both ospfd and
ospf6d. Auto-cost is always enabled in Frr."""
refbw = 100000

cmd = ("vtysh", "-c", f"show running-config {daemon}")
for line in HOST.run(cmd, default="").splitlines():
words = line.split()
if words[:2] == ["auto-cost", "reference-bandwidth"]:
refbw = int(words[2])
break

ospf["ietf-ospf:auto-cost"] = {
"enabled": True,
"reference-bandwidth": refbw,
}


def add_areas(control_protocols):
"""Populate OSPF status"""
cmd = ['/usr/libexec/statd/ospf-status']
Expand Down Expand Up @@ -308,6 +329,7 @@ def add_areas(control_protocols):
area["ietf-ospf:interfaces"]["ietf-ospf:interface"] = interfaces
areas.append(area)

add_auto_cost(control_protocol["ietf-ospf:ospf"], "ospfd")
add_routes(control_protocol["ietf-ospf:ospf"])
control_protocol["ietf-ospf:ospf"]["ietf-ospf:areas"]["ietf-ospf:area"] = areas
insert(control_protocols, "control-plane-protocol", [control_protocol])
Expand Down Expand Up @@ -389,6 +411,7 @@ def add_areas6(control_protocols):
area["ietf-ospf:interfaces"]["ietf-ospf:interface"] = interfaces
areas.append(area)

add_auto_cost(control_protocol["ietf-ospf:ospf"], "ospf6d")
add_routes(control_protocol["ietf-ospf:ospf"], ipv6=True)
control_protocol["ietf-ospf:ospf"]["ietf-ospf:areas"]["ietf-ospf:area"] = areas
insert(control_protocols, "control-plane-protocol", [control_protocol])
Expand Down
5 changes: 5 additions & 0 deletions test/case/routing/Readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Tests verifying standard routing protocols and configuration:
- OSPF with BFD (Bidirectional Forwarding Detection)
- OSPF default route advertisement and propagation
- OSPF debug logging configuration and verification
- OSPF auto-cost reference bandwidth and interface cost
- OSPF point-to-multipoint hybrid (broadcast) interface type
- OSPF point-to-multipoint (non-broadcast) interface type with static neighbors
- RIP basic neighbor discovery and route exchange
Expand Down Expand Up @@ -48,6 +49,10 @@ include::ospf_debug/Readme.adoc[]

<<<

include::ospf_auto_cost/Readme.adoc[]

<<<

include::ospf_point_to_multipoint_hybrid/Readme.adoc[]

<<<
Expand Down
3 changes: 3 additions & 0 deletions test/case/routing/all.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
- name: OSPF Debug Logging
case: ospf_debug/test.py

- name: OSPF Auto-Cost Reference Bandwidth
suite: ospf_auto_cost/test.yaml

- name: OSPF Point-to-Multipoint Hybrid
suite: ospf_point_to_multipoint_hybrid/test.yaml

Expand Down
6 changes: 6 additions & 0 deletions test/case/routing/ospf_auto_cost/Readme.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include::ospfv2.adoc[]

<<<

include::ospfv3.adoc[]

41 changes: 41 additions & 0 deletions test/case/routing/ospf_auto_cost/ospfv2.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
=== OSPFv2 Auto-Cost Reference Bandwidth

ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/ospf_auto_cost]

==== Description

Verifies that the OSPFv2 interface cost follows the configured auto-cost
reference bandwidth. The reference bandwidth must be the same on all
routers in an OSPF domain, so it is changed on both R1 and R2.

The cost of an interface is the reference bandwidth divided by the link
speed, with 1 as the lowest cost. A link of unknown speed, e.g., a virtual
link, counts as 10000 Mbit/s. On a 1 Gbit/s link the cost is:

|===
| Reference bandwidth | Cost
| 100000 Mbit/s (default) | 100
| 10000 Mbit/s | 10
| 1000 Mbit/s | 1
|===

The test reads the link speed on each router to calculate the expected
cost, and reads the reference bandwidth back from the operational
datastore.

==== Topology

image::topology.svg[OSPFv2 Auto-Cost Reference Bandwidth topology, align=center, scaledwidth=75%]

==== Sequence

. Set up topology and attach to target DUTs
. Configure OSPFv2 on R1 and R2
. Wait for OSPFv2 adjacency between R1 and R2
. Verify default reference bandwidth 100000 Mbit/s and link cost
. Set reference bandwidth 10000 Mbit/s on R1 and R2
. Verify reference bandwidth 10000 Mbit/s and link cost
. Set reference bandwidth 1000 Mbit/s on R1 and R2
. Verify reference bandwidth 1000 Mbit/s and link cost


1 change: 1 addition & 0 deletions test/case/routing/ospf_auto_cost/ospfv2.py
41 changes: 41 additions & 0 deletions test/case/routing/ospf_auto_cost/ospfv3.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
=== OSPFv3 Auto-Cost Reference Bandwidth

ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/ospf_auto_cost]

==== Description

Verifies that the OSPFv3 interface cost follows the configured auto-cost
reference bandwidth. The reference bandwidth must be the same on all
routers in an OSPF domain, so it is changed on both R1 and R2.

The cost of an interface is the reference bandwidth divided by the link
speed, with 1 as the lowest cost. A link of unknown speed, e.g., a virtual
link, counts as 10000 Mbit/s. On a 1 Gbit/s link the cost is:

|===
| Reference bandwidth | Cost
| 100000 Mbit/s (default) | 100
| 10000 Mbit/s | 10
| 1000 Mbit/s | 1
|===

The test reads the link speed on each router to calculate the expected
cost, and reads the reference bandwidth back from the operational
datastore.

==== Topology

image::topology.svg[OSPFv3 Auto-Cost Reference Bandwidth topology, align=center, scaledwidth=75%]

==== Sequence

. Set up topology and attach to target DUTs
. Configure OSPFv3 on R1 and R2
. Wait for OSPFv3 adjacency between R1 and R2
. Verify default reference bandwidth 100000 Mbit/s and link cost
. Set reference bandwidth 10000 Mbit/s on R1 and R2
. Verify reference bandwidth 10000 Mbit/s and link cost
. Set reference bandwidth 1000 Mbit/s on R1 and R2
. Verify reference bandwidth 1000 Mbit/s and link cost


1 change: 1 addition & 0 deletions test/case/routing/ospf_auto_cost/ospfv3.py
Loading
Loading