OSPF Deep Dive Part 7: Cisco IOS/IOS-XE Implementation and Gotchas

CORE-CSR has been the Cisco router in this series’ lab since Part 1. This post is where it actually gets configured, and where Cisco’s specific defaults and quirks get called out against the vendor-neutral theory from Parts 1 through 6.

Process ID is local, and that trips people up exactly once

router ospf 1 creates a process numbered 1 on this router. That number has no significance to any other router in the domain, including a neighboring Cisco router. Two Cisco routers running router ospf 1 and router ospf 200 respectively form adjacencies with each other just fine, because the process ID never appears in an OSPF packet. It’s a purely local handle for referencing this process in configuration and show commands. The confusion this causes is almost always in the other direction: someone assumes mismatched process IDs are the reason two routers won’t form an adjacency, spends time renumbering, and the actual cause (area ID, hello timers, authentication, from Parts 1 and 6) goes unexamined the whole time.

Where process ID does matter is running multiple OSPF processes on the same router, a legitimate but uncommon design for deliberately separating two routing domains that share a device. Redistributing between two local processes on the same box requires an explicit redistribute ospf <other-process-id> statement, exactly as if the second process were a different protocol, which is worth knowing precisely because a lot of engineers only ever configure router ospf 1 and never encounter this.

Two ways to add an interface to an area

CORE-CSR’s Area 0 configuration can be built with the classic network-statement style:

router ospf 1
 router-id 10.0.0.1
 network 10.0.0.0 0.0.0.3 area 0

or the interface-level style that IOS-XE also supports:

interface GigabitEthernet0/1
 ip ospf 1 area 0

Both put the same interface into the same area under the same process. The interface-level form is usually clearer in a mixed-vendor shop specifically because FortiOS and Junos both configure OSPF interface membership at the interface level as their only option, so writing Cisco the same way keeps the mental model consistent across a multi-vendor config review instead of requiring a translation step every time. The wildcard mask in the network-statement form (0.0.0.3 matching a /30) is also a recurring source of errors on its own: it’s an inverse mask, not a subnet mask, and getting it backwards either matches nothing or matches far more than intended without any error message pointing at the mistake.

Passive-interface-default is the right default posture, with one sharp edge

Cisco’s own recommended pattern, passive-interface default followed by no passive-interface on each interface that should actually form adjacencies, inverts OSPF’s native behavior (every interface active unless told otherwise) into a safer one (every interface passive unless told otherwise). This matters because an interface added to an area via a broad network statement, say network 10.0.0.0 0.0.0.255 area 0 covering a /24, silently starts forming adjacencies on every matching interface unless something already suppresses it, including an interface facing a segment that was never meant to run OSPF at all.

The sharp edge: applying passive-interface default on a router that already has active OSPF adjacencies immediately makes every interface passive, including the ones that need to stay active, until the corresponding no passive-interface lines are reapplied. It’s not additive. It’s a blanket flip that depends entirely on the no passive-interface exceptions already being in the running configuration, or being added in the same maintenance window, not after it.

Router-id: the loopback-priority rule from Part 1, in practice

CORE-CSR’s router-id of 10.0.0.1 was chosen deliberately for this series rather than left to auto-selection, which is the actual best practice regardless of lab or production: always configure router-id explicitly. Left to Cisco’s default algorithm, the router-id is the highest IP address on any loopback interface if one exists, or the highest IP address on any active physical interface if it doesn’t. That’s a real design decision hiding as an implementation detail, because a router-id chosen from a physical interface can change if that specific interface goes down and a different one now holds the highest address, silently changing the router-id of every LSA this router originates on the next reload.

Just as important: changing router-id in the configuration does not take effect immediately on a running process. The new value is stored but the process keeps using the old router-id until it’s cleared, clear ip ospf process, which resets every adjacency on that process. This is a deliberately disruptive operation and it’s easy to configure a new router-id, see no apparent effect, and not realize the change is sitting inert until the next reload or manual clear.

Reference-bandwidth: a warning that only fires once, locally

Part 3 covered why every router in a domain needs a matching reference-bandwidth. On IOS-XE, configuring auto-cost reference-bandwidth 10000 (to make a 10 Gbps interface cost 1 instead of the default-reference-bandwidth cost of 1 that a mere 100 Mbps interface also gets) prints a one-time CLI warning at the moment it’s configured, reminding the operator to apply the same value everywhere. It is not an ongoing protocol check. Nothing in OSPF itself ever verifies that every router agrees, and no LSA carries reference-bandwidth information. A router with a stale value from before a domain-wide change goes unnoticed until someone actually inspects its configuration or its route costs look wrong compared to its neighbors, which is a strong argument for the reference-bandwidth value living in whatever configuration-management baseline generates OSPF configs in the first place, rather than being hand-set per device.

MTU and mtu-ignore

Part 1 flagged MTU mismatch as the leading cause of a neighbor stuck at ExStart. ip ospf mtu-ignore makes CORE-CSR stop checking the MTU field in a neighbor’s DBD packets entirely, which does get the adjacency to Full, and is also close to always the wrong fix. It doesn’t resolve the underlying MTU mismatch, it just stops OSPF from refusing to proceed despite it, which means actual large packets can still black-hole on the path even though the control-plane adjacency reports healthy. The correct fix is nearly always making the interface MTUs match; mtu-ignore is a diagnostic tool for confirming MTU is the actual cause, not a production setting to leave in place.

Part 8 does the same pass for FortiOS, where OSPF sits inside a VDOM boundary that has no Cisco equivalent at all.