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
3 changes: 3 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ All notable changes to the project are documented in this file.
- WiFi channel survey is on request: `show hardware <radio> survey`, the
Scan channels button on the WebUI WiFi page, or the `channel-survey`
action. The always-on `survey` container under the radio is gone
- 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`

### Fixes

Expand Down
21 changes: 20 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.
Comment thread
saba8814 marked this conversation as resolved.
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,23 @@ 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.
- (auto-cost) 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.
Auto-cost can not be disabled, but a cost set manually per interface takes precedence.

`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-10-03.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 thread
saba8814 marked this conversation as resolved.
}
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 @@ -5273,6 +5273,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
control_protocols.setdefault("control-plane-protocol", []).append(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
control_protocols.setdefault("control-plane-protocol", []).append(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 @@ -49,6 +50,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