mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-23 17:33:01 +02:00
Merge pull request #1297 from kernelkit/ospf-debug
Configurable support for OSPF debug
This commit is contained in:
@@ -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
|
||||
-------------------------
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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[]
|
||||
|
||||
<<<
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
test.adoc
|
||||
Executable
+256
@@ -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()
|
||||
@@ -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"]
|
||||
}
|
||||
Reference in New Issue
Block a user