From 7edc3c19f7c63eca08018984d6e3487a7b465107 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 2 Dec 2025 13:35:56 +0100 Subject: [PATCH 1/4] confd: add support for toggling OSPF debug logs Fixes #1281 Signed-off-by: Joachim Wiberg --- src/confd/src/routing.c | 45 ++++++++++++++---- src/confd/yang/confd.inc | 2 +- src/confd/yang/confd/infix-routing.yang | 47 +++++++++++++++++++ ...-12.yang => infix-routing@2025-12-02.yang} | 0 4 files changed, 83 insertions(+), 11 deletions(-) rename src/confd/yang/confd/{infix-routing@2025-11-12.yang => infix-routing@2025-12-02.yang} (100%) diff --git a/src/confd/src/routing.c b/src/confd/src/routing.c index f1400d6c..db0797a0 100644 --- a/src/confd/src/routing.c +++ b/src/confd/src/routing.c @@ -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"); diff --git a/src/confd/yang/confd.inc b/src/confd/yang/confd.inc index 3e102c98..c9bb5e53 100644 --- a/src/confd/yang/confd.inc +++ b/src/confd/yang/confd.inc @@ -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" diff --git a/src/confd/yang/confd/infix-routing.yang b/src/confd/yang/confd/infix-routing.yang index 34224a53..3a75db09 100644 --- a/src/confd/yang/confd/infix-routing.yang +++ b/src/confd/yang/confd/infix-routing.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" { diff --git a/src/confd/yang/confd/infix-routing@2025-11-12.yang b/src/confd/yang/confd/infix-routing@2025-12-02.yang similarity index 100% rename from src/confd/yang/confd/infix-routing@2025-11-12.yang rename to src/confd/yang/confd/infix-routing@2025-12-02.yang From c0646d1a66dbcb1ee193177ade33d782726ac226 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 2 Dec 2025 14:31:00 +0100 Subject: [PATCH 2/4] test: new test to verify ospf debug logging Signed-off-by: Joachim Wiberg --- test/case/routing/Readme.adoc | 5 + test/case/routing/all.yaml | 3 + test/case/routing/ospf_debug/Readme.adoc | 1 + test/case/routing/ospf_debug/test.py | 256 ++++++++++++++++++++++ test/case/routing/ospf_debug/topology.dot | 32 +++ 5 files changed, 297 insertions(+) create mode 120000 test/case/routing/ospf_debug/Readme.adoc create mode 100755 test/case/routing/ospf_debug/test.py create mode 100644 test/case/routing/ospf_debug/topology.dot diff --git a/test/case/routing/Readme.adoc b/test/case/routing/Readme.adoc index 9554ede4..84302db6 100644 --- a/test/case/routing/Readme.adoc +++ b/test/case/routing/Readme.adoc @@ -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[] <<< diff --git a/test/case/routing/all.yaml b/test/case/routing/all.yaml index 3c9c6e10..437d3457 100644 --- a/test/case/routing/all.yaml +++ b/test/case/routing/all.yaml @@ -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 diff --git a/test/case/routing/ospf_debug/Readme.adoc b/test/case/routing/ospf_debug/Readme.adoc new file mode 120000 index 00000000..ae32c841 --- /dev/null +++ b/test/case/routing/ospf_debug/Readme.adoc @@ -0,0 +1 @@ +test.adoc \ No newline at end of file diff --git a/test/case/routing/ospf_debug/test.py b/test/case/routing/ospf_debug/test.py new file mode 100755 index 00000000..d61dbc7f --- /dev/null +++ b/test/case/routing/ospf_debug/test.py @@ -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() diff --git a/test/case/routing/ospf_debug/topology.dot b/test/case/routing/ospf_debug/topology.dot new file mode 100644 index 00000000..788d3e6b --- /dev/null +++ b/test/case/routing/ospf_debug/topology.dot @@ -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 | mgmt2 }", + pos="20,30!", + requires="controller", + ]; + + R1 [ + label="{ mgmt | link} | R1 \n 192.168.100.1/32 \n(lo)", + pos="160,60!", + + requires="infix", + ]; + R2 [ + label="{ link | 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"] +} From 989197e2c346d8636bbafecb11288353aa8bcc7d Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 2 Dec 2025 13:36:18 +0100 Subject: [PATCH 3/4] doc: add information on ospf debug settings Signed-off-by: Joachim Wiberg --- doc/networking.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/doc/networking.md b/doc/networking.md index 59d71fc2..3c59d0c5 100644 --- a/doc/networking.md +++ b/doc/networking.md @@ -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 From 39ffad6b08230869f359ddf6cd13e42c04dae9ff Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 2 Dec 2025 13:37:01 +0100 Subject: [PATCH 4/4] doc: update ChangeLog, new ospf debug settings Signed-off-by: Joachim Wiberg --- doc/ChangeLog.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 72f1b758..9cfcd804 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -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 -------------------------