OSPF on Linux Part 5: Troubleshooting OSPF on Linux

OSPF Deep Dive Part 10 laid out a vendor-neutral troubleshooting sequence: confirm Layer 1/2 and IP reachability first, then neighbor state, then LSDB content, then route installation, in that order, because each layer’s problems look different and chasing the wrong one wastes time. Part 11 turned that sequence into a three-vendor show-command table. This post adds FRR as a fourth column, then covers the failure modes that are specific to Linux and don’t have an equivalent on Cisco, FortiOS, or Junos at all.

The show-command table, now with FRR

TaskCisco IOS-XEFortiOSJunosFRR (vtysh)
Neighbor statesshow ip ospf neighborget router info ospf neighborshow ospf neighborshow ip ospf neighbor
Interface OSPF config/stateshow ip ospf interface briefget router info ospf interfaceshow ospf interfaceshow ip ospf interface brief
Full LSDB summaryshow ip ospf databaseget router info ospf databaseshow ospf databaseshow ip ospf database
One LSA in full detailshow ip ospf database router <id>get router info ospf database router <id>show ospf database extensiveshow ip ospf database router <id>
Routes as OSPF calculated themshow ip route ospfget router info routing-table ospfshow ospf routeshow ip route ospf
Process-wide summaryshow ip ospfget router info ospf statusshow ospf overviewshow ip ospf
Live event debuggingdebug ip ospf adj / debug ip ospf eventsdiagnose ip router ospf level infoshow ospf log / traceoptionsdebug ospf adj / debug ospf events

The pattern from Part 11 holds: read the state field carefully. FRR appends the DR/BDR role directly to the state field the same way Cisco and FortiOS do, Full/DR, Full/- on a point-to-point link, the format LAB-LNX showed against CORE-CSR in Part 4. debug ospf ... commands are enabled per-session and don’t persist across a restart unless written into the config explicitly, same caveat as debug ip ospf on Cisco.

Failure modes that are specific to Linux

None of these have a real equivalent on an appliance, because an appliance’s vendor has already made the decision each one represents. On Linux, they’re all still open questions the operating system leaves to you.

IP forwarding is off by default. net.ipv4.ip_forward is 0 on a stock Linux install, and OSPF adjacencies form and the LSDB syncs perfectly normally with it off, because none of that requires forwarding, only that zebra can install routes and the interfaces can send and receive OSPF packets. What breaks silently is everything downstream: the router looks fully converged, show ip ospf neighbor says Full, show ip route ospf lists the expected routes, and transit traffic still doesn’t pass, because the kernel was never told to forward it in the first place. sysctl net.ipv4.ip_forward=1, and net.ipv4.conf.all.forwarding=1 if the interfaces were brought up before the change, persisted in /etc/sysctl.d/. Check this before anything protocol-specific, it’s a one-line fix for a symptom that otherwise looks like a routing problem.

A firewall dropping protocol 89. OSPF isn’t TCP or UDP, it runs directly over IP protocol 89, and a default-deny nftables or iptables ruleset written with only TCP and UDP in mind passes right over it, no rule matches, nothing logs, the packets are just gone. The fix is a rule that matches on protocol rather than port:

nft add rule inet filter input ip protocol ospf accept

or, iptables equivalent:

iptables -A INPUT -p ospf -j ACCEPT

This is worth checking specifically before assuming a hello-parameter mismatch from OSPF Deep Dive Part 1, because the symptom looks identical from the neighbor state table, stuck at Down, no neighbor entry at all, which is exactly the “nothing OSPF-specific has happened yet” row from Part 10’s troubleshooting table.

Multicast group membership. OSPF hellos on a broadcast segment go to 224.0.0.5 (AllSPFRouters), DR/BDR-directed updates go to 224.0.0.6 (AllDRouters). ospfd joins these groups on its own when an interface is enabled for OSPF, but a restrictive nftables multicast rule, an interface that came up before ospfd did, or a virtual interface (a veth pair, a bridge) that doesn’t propagate multicast the way a physical NIC does, can all block hello delivery specifically while leaving unicast traffic on the same link completely fine. ip maddr show <interface> lists the multicast groups an interface has actually joined, and confirming 224.0.0.5 is there is the fast check before looking anywhere else.

The wrong network namespace. A Linux box running FRR inside a container or a ip netns sandbox, the same primitive covered in Linux Networking from the Ground Up, has its own isolated network stack, and ospfd only sees the interfaces that exist inside its own namespace. An interface moved to a namespace after FRR started, or a veth end left in the wrong namespace during setup, produces no error from ospfd at all, the interface simply isn’t there from the daemon’s point of view. ip netns exec <ns> vtysh runs the CLI inside the correct namespace directly; ip netns exec <ns> ip link confirms which interfaces actually live there before spending time in ospfd’s own output.

veth MTU defaults. OSPF Deep Dive Part 7 covered ip ospf mtu-ignore as a diagnostic tool, not a fix, for an ExStart-stuck adjacency caused by mismatched MTU. Linux veth pairs default to 1500 like a physical Ethernet interface, so this usually isn’t a problem connecting to a physical router, but it becomes one the moment a veth pair sits behind a tunnel, an overlay, or a bridge with a lower MTU somewhere in the path, and the two ends of the OSPF adjacency disagree on what the link actually supports. ip link show <interface> reports the current MTU directly; matching it explicitly on both ends of a link is the actual fix, the same conclusion Part 7 reached for the appliance case.

tcpdump: the view none of the three appliances give you as easily

This is the genuine advantage of troubleshooting OSPF from a Linux box specifically: full packet capture is a command away, not a licensed feature or a separate diagnostic mode.

tcpdump -i eth0 -n proto ospf

proto ospf is a BPF filter Linux resolves to protocol 89 directly, no manual ip proto 89 needed, matching the net 10.0.0.0/24-style filters already used on the tcpdump deep dive post on this site. Capturing a hello exchange during ExStart shows the actual DBD sequence-number negotiation from OSPF Deep Dive Part 1’s state table happening on the wire, not just the state name ospfd reports after the fact, which is the fastest way to confirm a stuck ExStart really is an MTU disagreement, the DBD packet size in the capture will show it directly, rather than treating mtu-ignore as a first move instead of a last one.

That closes this series. Five posts: where FRR came from, why it’s the default choice today, how to install and configure it, a fourth router wired live into the OSPF Deep Dive lab, and where to look when any of it breaks, on the one platform in this whole run of posts where you get to watch the protocol happen instead of just being told the result.