Merge pull request #1297 from kernelkit/ospf-debug

Configurable support for OSPF debug
This commit is contained in:
Joachim Wiberg
2025-12-03 11:20:09 +01:00
committed by GitHub
11 changed files with 432 additions and 11 deletions
+10
View File
@@ -3,6 +3,16 @@ Change Log
All notable changes to the project are documented in this file.
[v26.01.0][UNRELEASED]
-------------------------
### Changes
- Add support for configurable OSPF debug logging, issue #1281. Debug options
can now be enabled per category (bfd, packet, ism, nsm, default-information,
nssa). All debug options are disabled by default to prevent log flooding in
production environments. See the documentation for usage examples
[v25.11.0][] - 2025-12-02
-------------------------
+42
View File
@@ -1502,6 +1502,48 @@ routes`.
admin@example:/>
For more detailed troubleshooting, OSPF debug logging can be enabled to
capture specific protocol events. Debug messages are written to the
routing log file (`/var/log/routing`).
> [!CAUTION]
> Debug logging significantly increases log output and may impact
> performance. Only enable debug categories needed for troubleshooting,
> and disable them when done.
To enable specific OSPF debug categories:
admin@example:/> configure
admin@example:/config/> edit routing control-plane-protocol ospfv2 name default ospf debug
admin@example:/config/routing/…/ospf/debug/> set bfd true
admin@example:/config/routing/…/ospf/debug/> set nsm true
admin@example:/config/routing/…/ospf/debug/> leave
admin@example:/>
Available debug categories include:
- `bfd`: BFD (Bidirectional Forwarding Detection) events
- `packet`: Detailed packet debugging (all OSPF packets)
- `ism`: Interface State Machine events
- `nsm`: Neighbor State Machine events
- `default-information`: Default route origination
- `nssa`: Not-So-Stubby Area events
All debug options are disabled by default. Refer to the `infix-routing`
YANG model for the complete list of available debug options.
To view current debug settings:
admin@example:/> show running-config routing control-plane-protocol
To disable all debug logging, simply delete the debug settings or set
all options back to `false`:
admin@example:/> configure
admin@example:/config/> delete routing control-plane-protocol ospfv2 name default ospf debug
admin@example:/config/> leave
admin@example:/>
### View routing table
+35 -10
View File
@@ -133,15 +133,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)
{
const char *static_debug = "! OSPF default debug\
debug ospf bfd\n\
debug ospf packet all detail\n\
debug ospf ism\n\
debug ospf nsm\n\
debug ospf default-information\n\
debug ospf nssa\n\
! OSPF configuration\n";
struct lyd_node *areas, *default_route;
struct lyd_node *areas, *default_route, *debug;
const char *router_id;
int bfd_enabled = 0;
int num_areas = 0;
@@ -154,7 +146,40 @@ debug ospf nssa\n\
}
fputs(FRR_STATIC_CONFIG, fp);
fputs(static_debug, fp);
/* Handle OSPF debug configuration */
debug = lydx_get_child(ospf, "debug");
if (debug) {
int any_debug = 0;
if (lydx_get_bool(debug, "bfd")) {
fputs("debug ospf bfd\n", fp);
any_debug = 1;
}
if (lydx_get_bool(debug, "packet")) {
fputs("debug ospf packet all detail\n", fp);
any_debug = 1;
}
if (lydx_get_bool(debug, "ism")) {
fputs("debug ospf ism\n", fp);
any_debug = 1;
}
if (lydx_get_bool(debug, "nsm")) {
fputs("debug ospf nsm\n", fp);
any_debug = 1;
}
if (lydx_get_bool(debug, "default-information")) {
fputs("debug ospf default-information\n", fp);
any_debug = 1;
}
if (lydx_get_bool(debug, "nssa")) {
fputs("debug ospf nssa\n", fp);
any_debug = 1;
}
if (any_debug)
fputs("!\n", fp);
}
areas = lydx_get_child(ospf, "areas");
router_id = lydx_get_cattr(ospf, "explicit-router-id");
+1 -1
View File
@@ -26,7 +26,7 @@ MODULES=(
"ieee802-dot1q-types@2022-10-29.yang"
"infix-ip@2025-11-02.yang"
"infix-if-type@2025-02-12.yang"
"infix-routing@2025-11-12.yang"
"infix-routing@2025-12-02.yang"
"ieee802-dot1ab-lldp@2022-03-15.yang"
"infix-lldp@2025-05-05.yang"
"infix-dhcp-common@2025-11-09.yang"
+47
View File
@@ -23,6 +23,14 @@ module infix-routing {
contact "kernelkit@googlegroups.com";
description "Deviations and augments for ietf-routing and ietf-ospf.";
revision 2025-12-02 {
description "Add configurable OSPF debug logging container.
Allows users to enable specific OSPF debug categories
(bfd, packet, ism, nsm, default-information, nssa) for troubleshooting.
All debug options default to disabled to prevent log flooding.";
reference "Issue #1281";
}
revision 2025-11-12 {
description "Add area-id augmentation to OSPF local-rib routes.
Add uptime, role, and interface-name augmentations to OSPF neighbor state.
@@ -306,6 +314,45 @@ module infix-routing {
}
}
}
augment "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf" {
description "Add support for configurable OSPF debug logging.
Allows users to enable specific OSPF debug categories for troubleshooting.
All debug options default to disabled to prevent log flooding in
production environments.";
container debug {
description "OSPF debug logging configuration";
leaf bfd {
type boolean;
default false;
description "Enable OSPF BFD (Bidirectional Forwarding Detection) debug messages";
}
leaf packet {
type boolean;
default false;
description "Enable detailed OSPF packet debug messages (all packet types)";
}
leaf ism {
type boolean;
default false;
description "Enable OSPF Interface State Machine debug messages";
}
leaf nsm {
type boolean;
default false;
description "Enable OSPF Neighbor State Machine debug messages";
}
leaf default-information {
type boolean;
default false;
description "Enable OSPF default route origination debug messages";
}
leaf nssa {
type boolean;
default false;
description "Enable OSPF NSSA (Not-So-Stubby Area) debug messages";
}
}
}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:areas/ospf:area/ospf:interfaces/ospf:interface" {
deviate add {
must "count(../../../../ospf:areas/ospf:area/ospf:interfaces/ospf:interface[ospf:name=current()/name]) <= 1" {
+5
View File
@@ -9,6 +9,7 @@ Tests verifying standard routing protocols and configuration:
- OSPF multi-area configuration and inter-area routing
- OSPF with BFD (Bidirectional Forwarding Detection)
- OSPF default route advertisement and propagation
- OSPF debug logging configuration and verification
- Route preference handling for OSPF routes
- Route preference handling for DHCP-learned routes
- Administrative distance configuration (route preference 255)
@@ -37,6 +38,10 @@ include::ospf_default_route_advertise/Readme.adoc[]
<<<
include::ospf_debug/Readme.adoc[]
<<<
include::route_pref_ospf/Readme.adoc[]
<<<
+3
View File
@@ -25,3 +25,6 @@
- name: OSPF Default route advertise
case: ospf_default_route_advertise/test.py
- name: OSPF Debug Logging
case: ospf_debug/test.py
+1
View File
@@ -0,0 +1 @@
test.adoc
+256
View File
@@ -0,0 +1,256 @@
#!/usr/bin/env python3
"""OSPF Debug Logging
Verifies OSPF debug logging by configuring two routers (R1 and R2) with
OSPF on their interconnecting link. The test enables specific OSPF debug
categories and verifies that appropriate debug messages appear in
/var/log/debug.
This test specifically validates:
- Debug messages appear when debug options are enabled
- No excessive debug messages when debug options are disabled
- Individual categories (ism, nsm, packet) can be toggled independently
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def verify_debug_messages_present(ssh, logfile):
"""Verify OSPF debug messages are present in the log file."""
def check_log():
rc = ssh.runsh(f"cat /var/log/{logfile} 2>/dev/null")
log_content = rc.stdout if rc.returncode == 0 else ""
# Check for ISM (Interface State Machine) debug messages
# Example: "ISM[e5:192.168.50.1]: Down (InterfaceUp)"
has_ism = "ISM[" in log_content
# Check for NSM (Neighbor State Machine) debug messages
# Example: "NSM[e5:192.168.50.1:192.168.200.1:default]: Down (HelloReceived)"
has_nsm = "NSM[" in log_content
# Check for packet debug messages - look for Hello packet details
# Example: "Type 1 (Hello)" or "ospf_recv_packet"
has_packet = "ospf_recv_packet" in log_content or "Type 1 (Hello)" in log_content
return has_ism and has_nsm and has_packet
return check_log
def verify_debug_messages_minimal(ssh, logfile):
"""Verify OSPF debug messages are minimal/absent in the log file."""
def check_log():
rc = ssh.runsh(f"cat /var/log/{logfile} 2>/dev/null")
log_content = rc.stdout if rc.returncode == 0 else ""
# When debug is disabled, we shouldn't see verbose debug messages
lines = log_content.split('\n')
# Look for ISM, NSM, and detailed packet dumps
ospf_debug_lines = [l for l in lines if "ISM[" in l or "NSM[" in l or "ospf_recv_packet" in l or "Type 1 (Hello)" in l]
# Allow some residual messages but not many
return len(ospf_debug_lines) <= 10
return check_log
def config_target1(target, link, enable_debug=False):
ospf_config = {
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
"hello-interval": 1,
"dead-interval": 3
}]
},
}]
}
}
}
if enable_debug:
ospf_config["ospf"]["debug"] = {
"ism": True,
"nsm": True,
"packet": True
}
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.100.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R1"
}
},
"ietf-syslog": {
"syslog": {
"actions": {
"file": {
"log-file": [{
"name": "file:ospf-debug",
"infix-syslog:property-filter": {
"property": "programname",
"operator": "isequal",
"value": "ospfd"
},
"facility-filter": {
"facility-list": [{
"facility": "all",
"severity": "debug"
}]
}
}]
}
}
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [ospf_config]
}
}
}
})
def config_target2(target, link):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.200.1",
"prefix-length": 32
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "R2"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
"hello-interval": 1,
"dead-interval": 3
}]
}
}]
}
}
}]
}
}
}
})
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUTs"):
env = infamy.Env()
R1 = env.attach("R1", "mgmt")
R1ssh = env.attach("R1", "mgmt", "ssh")
R2 = env.attach("R2", "mgmt")
with test.step("Clean up old log files from previous test runs"):
R1ssh.runsh("sudo rm -f /var/log/ospf-debug")
with test.step("Configure R1 and R2 without debug enabled"):
_, R1link = env.ltop.xlate("R1", "link")
_, R2link = env.ltop.xlate("R2", "link")
parallel(config_target1(R1, R1link, enable_debug=False),
config_target2(R2, R2link))
with test.step("Wait for OSPF adjacency to form"):
until(lambda: route.ipv4_route_exist(R1, "192.168.200.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "192.168.100.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
with test.step("Enable OSPF debug logging on R1"):
config_target1(R1, R1link, enable_debug=True)
with test.step("Verify OSPF debug messages appear in log file"):
until(verify_debug_messages_present(R1ssh, "ospf-debug"), attempts=30)
with test.step("Remove log file before disabling debug"):
R1ssh.runsh("sudo rm -f /var/log/ospf-debug")
with test.step("Disable OSPF debug logging on R1"):
config_target1(R1, R1link, enable_debug=False)
with test.step("Verify no OSPF debug messages when disabled"):
until(verify_debug_messages_minimal(R1ssh, "ospf-debug"), attempts=30)
test.succeed()
+32
View File
@@ -0,0 +1,32 @@
graph "ospf_debug" {
layout="neato";
overlap="false";
esep="+20";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <mgmt2> mgmt2 }",
pos="20,30!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <link> link} | R1 \n 192.168.100.1/32 \n(lo)",
pos="160,60!",
requires="infix",
];
R2 [
label="{ <link> link | <mgmt> mgmt } | R2 \n 192.168.200.1/32 \n(lo)",
pos="160,30!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
R1:link -- R2:link [headlabel="192.168.50.2/24", taillabel="192.168.50.1/24", labeldistance=1, fontcolor="black", color="black"]
}