VyOSXLIX · Monitoring and Observability IntegrationMonitoring
OSPF telemetry — LSDB export, SPF runtimes, and FRR per-LSA monitoring
What you'll learn
- Identify the canonical OSPF state (LSDB, neighbours, areas, SPF runs, LSA counts)
- Configure FRR's `show ip ospf json` for ad-hoc inspection and automation
- Stream OSPF state via gNMI telemetry subscriptions
- Use the custom textfile collector for derived metrics (per-area LSA count, SPF runtime)
- Validate the OSPF telemetry pipeline end-to-end before alerting on it
Prerequisites
Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling) · 2026-08-15
An “OSPF is broken” report is not OSPF until the operator has LSDB (Link-State Database) size, neighbour state, and SPF (Shortest Path First) runtime evidence. The OSPF LSDB is the canonical source of truth: every LSA (Link-State Advertisement) the router has learned, every area, every topology. The operator who cannot read the LSDB in five minutes will spend an hour guessing whether OSPF is in convergence, whether a flapping link is causing SPF storms, or whether an area design is causing instability.
This lesson is the production reference for OSPF telemetry on VyOS 1.5 LTS: the four transport options (FRR JSON, gNMI, SNMP OSPF-MIB, custom textfile), what each one gives the operator, what each one costs, and the validation discipline that prevents the OSPF telemetry layer from becoming the next source of incidents.
The four transports
flowchart LR
subgraph ROUTER["VyOS 1.5 router (control plane)"]
O["FRR ospfd<br/>LSDB, neighbours, SPF"]
end
subgraph COLLECT["Collection plane"]
FRR["FRR northbound<br/>show ip ospf json"]
GNMI["gNMI telemetry<br/>subscription"]
SNMP["SNMP OSPF-MIB<br/>(RFC 5643)"]
TF["Custom textfile<br/>collector"]
end
subgraph CONSUME["Consumption plane"]
TS["Time-series DB<br/>(Prometheus)"]
NMS["NMS / Grafana"]
end
O --> FRR
O --> GNMI
O --> SNMP
O --> TF
FRR --> TS
GNMI --> TS
SNMP --> NMS
TF --> TS
FRR’s show ip ospf json is the canonical ad-hoc inspection pattern. The JSON output is machine-readable, the operator can parse it with jq, and the operator can write automation playbooks that alert on LSDB size or SPF runtime. The cost: the operator must poll (FRR does not push), and the polling rate is limited by the user’s patience.
gNMI telemetry is the streaming-evidence alternative. The operator subscribes to the OSPF YANG model and receives state updates on a configurable cadence. The cost: gNMI requires the vyos-gnmi package (often not in the default image), and the OSPF YANG model is still maturing.
SNMP OSPF-MIB (RFC 5643) is the legacy alternative. The ospfNbrState, ospfNbrLsdbSum, ospfSpfRuns, ospfAreaLsaCount provide aggregate state. The cost: the OSPF-MIB does not provide per-LSA state (only summary counters), and the counters are 32-bit.
Custom textfile collector is the modern pattern for derived metrics. The operator writes a shell script that extracts per-area LSA counts and SPF runtimes from show ip ospf json and writes them in Prometheus text format. The cost: the operator must write and maintain the script; the discipline is to make the script idempotent and to validate the format.
The canonical OSPF state
The operator must know which OSPF state structures to monitor. The four canonical state structures:
flowchart TD
subgraph OSPF_STATE["OSPF state"]
NB["Neighbour state<br/>(Down, Attempt, Init, 2-Way, Exstart, Exchange, Loading, Full)"]
LS["LSDB state<br/>(per-area LSA counts)"]
SPF["SPF state<br/>(runs, runtime, last event)"]
AT["Area state<br/>(area ID, type, topology)"]
end
NB --> LS
LS --> SPF
SPF --> AT
Neighbour state is the OSPF adjacency FSM. The operator monitors ospfNbrState (or Neighbor State in show ip ospf neighbor) to know whether the adjacency is full. An adjacency that is bouncing between 2-Way and Exstart is failing to exchange DBDs; an adjacency that is Full but flapping every few minutes is a hello or dead-interval issue.
LSDB state is the database of LSAs. The operator monitors the per-area LSA counts (router-LSAs, network-LSAs, summary-LSAs, external-LSAs, NSSA-LSAs). A spike in any LSA type indicates a topology change or a misconfiguration. The operator also monitors the LSDB checksum, which is a tamper-evident hash of the LSDB content.
SPF state is the SPF computation. The operator monitors ospfSpfRuns (the number of SPF runs) and ospfSpfLastRunTime (the timestamp of the last SPF run). A spike in SPF runs indicates a flapping link or a topology change. The operator also monitors ospfSpfLastDuration (the duration of the last SPF run); a long duration indicates a large LSDB or a complex topology.
Area state is the area topology. The operator monitors the area ID, the area type (backbone, stub, NSSA, totally stub), the area’s LSA count, and the area’s SPF run count. The discipline is to keep the per-area LSA count below the operational threshold (e.g., 50,000 LSAs per area for an OSPFv2 backbone).
Step 1 — Use FRR’s show ip ospf json
The operator uses show ip ospf json to inspect the OSPF state in a machine-readable format. This is the canonical pattern for ad-hoc inspection and automation.
$ vtysh -c "show ip ospf json" | jq .
{
"routerId": "10.255.0.1",
"tosRoutes": 0,
"routes": 12345,
"externalRoutes": 6789,
"areaTotals": [
{
"areaId": 0,
"areaType": "normal",
"spfRuns": 1234,
"lsaCount": {
"routerLsa": 12,
"networkLsa": 5,
"summaryLsa": 100,
"asbrSummaryLsa": 0,
"externalLsa": 6789,
"totalLsa": 6906
}
},
{
"areaId": 1,
"areaType": "stub",
"spfRuns": 567,
"lsaCount": {
"routerLsa": 8,
"networkLsa": 3,
"summaryLsa": 50,
"asbrSummaryLsa": 0,
"externalLsa": 0,
"totalLsa": 61
}
}
]
}
The output is JSON. The operator uses jq to extract the relevant fields:
$ vtysh -c "show ip ospf json" | \
jq '.areaTotals[] | {areaId, spfRuns, totalLsa: .lsaCount.totalLsa}'
The operator can also inspect the per-neighbour state:
$ vtysh -c "show ip ospf neighbor json" | jq .
{
"neighbors": {
"10.0.1.1": {
"state": "Full",
"deadTime": "00:00:35",
"address": "10.0.1.1",
"interface": "eth0:10.0.1.1"
},
"10.0.1.2": {
"state": "Full",
"deadTime": "00:00:38",
"address": "10.0.1.2",
"interface": "eth1:10.0.1.2"
}
}
}
For the per-LSA detail, the operator uses show ip ospf database json:
$ vtysh -c "show ip ospf database json" | \
jq '.areas[] | {areaId, routerLsaCount: .routerLsas | length}'
The discipline: use show ip ospf json for the canonical view, and use jq to extract the fields the operator needs. The operator who tries to parse the text output of show ip ospf is rebuilding the JSON parser; the operator who uses the JSON output is composing the parser with jq.
Step 2 — Stream OSPF state via gNMI
The operator enables the gNMI server and subscribes to the OSPF YANG model:
configure
set service gnmi listen-address '10.0.0.1'
set service gnmi port '57400'
set service gnmi authentication username 'gnmi-user'
set service gnmi authentication password 'GNm1-2026-Q3'
commit
The operator then uses a gNMI client to subscribe to the OSPF state:
$ gnmic -a 10.0.0.1:57400 -u gnmi-user -p 'GNm1-2026-Q3' \
subscribe --path '/network-instances/network-instance[name=default]/protocols/protocol[identifier=OSPF]/ospf' \
--stream-mode sample --sample-interval 30s
The stream produces OSPF state updates every 30 seconds. The operator feeds the stream into a time-series database. The cost: gNMI requires the vyos-gnmi package, and the OSPF YANG model is still maturing.
Step 3 — Configure SNMP OSPF-MIB
The operator enables SNMPv3 and the OSPF-MIB on the router:
configure
set service snmp v3 engineid '0x80004f7e9c3a1b2c'
set service snmp v3 group default mode 'ro'
set service snmp v3 view full oid '1' include
set service snmp v3 user monitoring-auth group default auth plaintext-key 'AuthPass-2026-Q3'
set service snmp v3 user monitoring-auth group default auth type 'sha'
set service snmp v3 user monitoring-auth group default privacy plaintext-key 'PrivPass-2026-Q3'
set service snmp v3 user monitoring-auth group default privacy type 'aes'
commit
The operator then queries the OSPF-MIB:
$ snmpwalk -v3 -u monitoring-auth -l authPriv -a SHA -A 'AuthPass-2026-Q3' -x AES -X 'PrivPass-2026-Q3' 10.0.0.1 ospfNbrState
OSPF-MIB::ospfNbrState.10.0.1.1.0 = INTEGER: full(8)
OSPF-MIB::ospfNbrState.10.0.1.2.0 = INTEGER: full(8)
The OSPF-MIB provides aggregate state (neighbour state, LSA counts, SPF runs) but not per-LSA detail. The operator uses OSPF-MIB for the NMS-level view and the FRR JSON for the per-LSA detail.
Step 4 — Configure the custom textfile collector
The operator writes a shell script that extracts per-area LSA counts and SPF runtimes from show ip ospf json and writes them in Prometheus text format. The textfile collector is the canonical pattern for derived metrics.
#!/bin/bash
TEXTFILE=/var/lib/node_exporter/textfile/ospf-stats.prom
TMPFILE=$(mktemp)
echo "# HELP vyos_ospf_lsa_count Number of LSAs per OSPF area" > $TMPFILE
echo "# TYPE vyos_ospf_lsa_count gauge" >> $TMPFILE
echo "# HELP vyos_ospf_spf_runs Number of SPF runs per OSPF area" >> $TMPFILE
echo "# TYPE vyos_ospf_spf_runs counter" >> $TMPFILE
vtysh -c "show ip ospf json" | jq -r '
.areaTotals[] |
"vyos_ospf_lsa_count{area=\"\(.areaId)\",type=\"\(.areaType)\"} \(.lsaCount.totalLsa)",
"vyos_ospf_spf_runs{area=\"\(.areaId)\",type=\"\(.areaType)\"} \(.spfRuns)"
' >> $TMPFILE
mv $TMPFILE $TEXTFILE
The script runs on a 5-minute cron, the exporter reads the file on every scrape, and the Prometheus server sees the metric as a gauge (for LSA counts) or a counter (for SPF runs).
Validation discipline
Every OSPF telemetry metric must be validated before it becomes an alert. The validation discipline:
- Confirm the FRR JSON output is parseable. The operator runs
vtysh -c "show ip ospf json" | jq .and confirms the JSON is valid. - Confirm the gNMI subscription is receiving updates. The operator runs the gNMI client and confirms updates are arriving at the expected cadence.
- Confirm the SNMP OSPF-MIB is responding. The operator runs
snmpwalkagainst the OSPF-MIB and confirms the counters are present. - Confirm the textfile collector script is producing valid output. The operator runs the script manually and inspects the output file.
- Confirm the metric is changing. A metric that is present but constant is stale. The operator reads the metric twice, 5 seconds apart, and confirms the counter has incremented.
- Confirm the alert fires under the expected condition. The operator tests the alert by stopping an OSPF neighbour and confirming the NMS alerts.
Production failure modes
The OSPF telemetry failure modes the operator encounters:
- LSDB overflow. The per-area LSA count exceeds the LSDB overflow threshold (default 50,000 for OSPFv2, 30,000 for OSPFv3). The router stops accepting new LSAs and the OSPF instance is in a degraded state. Fix: increase the LSDB overflow threshold (
set protocols ospf parameters router-id <id>andset protocols ospf area <id> lsa-overview); investigate the cause of the LSA spike. - SPF storm. A flapping link causes continuous SPF runs. The router consumes 100% CPU on
ospfd; the routing table is recomputed continuously. Fix: stabilise the link (cable, SFP, switch port); enable dampening (set protocols ospf timers throttle spf 200 1000 5000). - LSA storm. A misconfigured stub area causes every router in the area to originate new LSAs. Fix: check the area type and the area configuration; stabilise the topology.
- FRR JSON output is truncated. The
show ip ospf jsonoutput is truncated for very large LSDBs. Fix: filter the output (show ip ospf database json self-originatefor the local LSAs) or use the textfile collector with a custom extractor. - gNMI subscription overruns the collector. A 1-second sample interval on 10,000 OSPF paths produces 10,000 updates per second. Fix: increase the sample interval or use on-change subscriptions.
- Textfile collector script fails silently. The script produces an empty output file; the exporter reports stale metrics. Fix: add error handling to the script (exit on error, log to syslog); monitor the file’s mtime.
Rollback
OSPF telemetry changes are typically configuration-only, but the impact can be cross-cutting. The rollback discipline:
- FRR JSON, gNMI, SNMP, textfile collector — all are in the VyOS tree or in the operator’s filesystem. The rollback is
rollback Nandcommit(for the tree changes) orrm(for the script files). - The custom textfile collector script — installed in
/usr/local/bin. The rollback is to remove the script and the cron entry. - NMS configuration — the NMS is a separate system. The rollback is to revert the NMS configuration, not the router.
For every change, use commit-confirm:
configure
# ... make the change ...
commit-confirm 5
# If the change has unintended consequences, the auto-rollback
# fires after 5 minutes and the previous configuration is restored.
Production discipline
Cross-course references
- Part XX (
vyos-xx-01-area-types) covers the OSPF area types that the telemetry layer distinguishes. - Part XXII (
vyos-xxii-01-neighbour-stuck) covers the OSPF neighbour troubleshooting that the telemetry layer supports. - Part XIX (
vyos-xix-04-ospf-redistribute) covers the OSPF redistribution that the telemetry layer monitors. - The Observability course covers the consumer side: Prometheus, Grafana, alerting on OSPF state deviation.
- The Ansible course’s
XLII-Ansible-BeyondLinuxcovers the automation hand-off (rolling out the textfile collector to a fleet via a single playbook). - The Linux course’s
XXII-Linux-NetTroubleshootcovers the underlying file descriptor and TCP session primitives that gNMI uses.
Quiz
Knowledge check · 4 questions
Q1. An operator needs to inspect the per-area LSA count on a VyOS 1.5 LTS router in a machine-readable format. Which command is the canonical pattern?
Q2. A sudden spike in `ospfSpfRuns` from 1 per hour to 100 per second for 5 minutes indicates a flapping link and the operator should investigate the link layer.
Q3. An operator needs to expose the per-area LSA count as a Prometheus metric on a VyOS 1.5 LTS router. The built-in node_exporter does not have an 'OSPF LSA count' collector. The operator decides to use the textfile collector. What is the canonical pattern?
R1 has three OSPF areas: area 0 (backbone), area 1 (stub), and area 2 (NSSA). The NMS polls the per-area LSA count every 5 minutes and alerts if any area's LSA count grows by more than 10% in a 24-hour window. The built-in `node_network_*` metrics cover the interface counters but not the OSPF state. The operator must build a derived metric.
Q4. An operator's Prometheus alert `vyos_ospf_lsa_count{area="0"} > 50000` fires. The operator runs `vtysh -c 'show ip ospf json'` and sees area 0 has 52,000 LSAs (mostly externalLsa). The OSPF instance is in a degraded state. What is the root cause and what is the fix?
R1 is a VyOS 1.5 LTS edge router that is an ASBR (Autonomous System Boundary Router) redistributing BGP routes into OSPF. The operator has not configured summarisation or route filtering. The OSPF backbone (area 0) has 52,000 external LSAs, exceeding the default LSDB overflow threshold of 50,000. The router is in a degraded state and is not accepting new LSAs. The operator must investigate the root cause.
Passing score: 75%. Answers are checked in this browser.