← All posts

The Same Router, Three Different Truths

One physical box, several routing identities, and why a node-and-edge graph cannot hold them

Michel Wijnberg

The first four posts in this series were about trust: model the network correctly, observe it safely, reproduce forwarding honestly, and refuse to guess. This one starts a second set, about what it actually takes to hold that line.

And it starts with the thing that breaks most topology tools before they get anywhere near an interesting question: a router is not one thing.


A router with two of everything

Here is nrt1-cr1 from my lab:

The device panel for nrt1-cr1, showing separate ABR·ASBR badges for OSPFv2 and OSPFv3
The device panel for nrt1-cr1, showing separate ABR·ASBR badges for OSPFv2 and OSPFv3

Look at the top right. Not one role badge. Two:

OSPFv2   ABR·ASBR
OSPFv3   ABR·ASBR

And underneath, in Protocols & Areas:

Protocol instanceAreasRole
OSPFv2 · process 1 (ipv4)0.0.0.0, 14.18.20.0ABR · ASBR
OSPFv3 · process 1 (ipv6)0.0.0.0, 14.18.20.0ABR · ASBR

It looks like duplication. It isn’t. These are two independent protocol instances with two independent link-state databases, and nrt1-cr1 earns the ABR title separately in each by being attached to more than one area in that instance. The area labels match because someone numbered them to match, not because they are the same object. In the database they have different UUIDs, because OSPFv2 area 14.18.20.0 and OSPFv3 area 14.18.20.0 are different areas that happen to share a name.

That distinction sounds pedantic right up until the two disagree. Which, as it turns out, they always do.


One wire, two costs, one hundred percent of the time

Here is a single physical link between two routers:

The link panel for lax1-gw1 to lax1-gw2, with Physical, OSPFv2 and OSPFv3 tabs and different costs
The link panel for lax1-gw1 to lax1-gw2, with Physical, OSPFv2 and OSPFv3 tabs and different costs

One cable. Et0/3 to Et0/3, 10G, carrying 172.24.2.13/30 and fddb:10:24:2::6/127. Osprey draws it as one edge, because physically it is one edge, and gives it a tab per protocol.

Now read the costs:

OSPFv2   Area 12.1.24.0   cost 10
OSPFv3   Area 12.1.24.0   cost 1

Same wire. Same area number. Different metric.

I did not stage that for the screenshot. I checked every dual-stack link in AS 200 afterwards, and the result is more interesting than the single example:

Dual-stack links in AS 200124
…where OSPFv2 and OSPFv3 costs differ124 (100%)
at (v2 = 10, v3 = 1)85
at (v2 = 10000, v3 = 10)39

Every single one differs, but look at the two groups: 39 links are a factor 1000 apart, and 85 are a factor 10 apart. That asymmetry is the interesting part, and it took asking the router to explain it.

Routing Process "ospf 1"     Reference bandwidth unit is 100000 mbps
Routing Process "ospfv3 1"   Reference bandwidth unit is 100 mbps

One setting, not two. Cost is reference bandwidth divided by interface bandwidth, so both processes are scaling the same wires by numbers that differ by exactly 1000. On the 10 Mbps links that arrives intact: 10000 against 10. On the 10 Gbps links OSPFv3 computes 100/10000 = 0.01, and the minimum cost a router will advertise is 1. The floor eats the rest.

So the distortion is not uniform, and that is precisely what makes it dangerous. A uniform scaling would be harmless: multiply every cost in a topology by the same constant and the shortest path does not move. Here the constant is 1000 on some links and 10 on others, because a clamp intervened. The two protocols therefore rank the same links differently against each other, and IPv4 and IPv6 traffic can take different paths across this network. You cannot eyeball which ones. You have to compute both.

A tool that renders “one link, one cost” has to pick one of those two numbers. Whichever it picks, it is wrong half the time, and it will never tell you which half you are in.


Why the hierarchy is load-bearing

This is the reason Osprey’s data model is not Node, Edge, Protocol:

Network → Autonomous System → Routing Domain → Protocol Instance → Area → Device
                                                                      ↳ Interface

Each level exists because something in the network can differ across it:

  • Network: the tenant boundary. The same physical box can be monitored under two tenants with different credentials and different views.
  • Autonomous System: the BGP identity, and the scope a BMP feed belongs to.
  • Routing Domain: global table, a VRF, or an L3VPN. Same router, different routing tables, genuinely different reachability.
  • Protocol Instance: unique on (routing domain, protocol, process id, address family). This is the level that makes nrt1-cr1 two routers.
  • Area: where the LSDB actually lives, and therefore where SPF actually runs.
  • Device: many-to-many with areas, via a membership table. Not a foreign key. A foreign key would have forced the lie that a router lives in one area.

And interfaces are scoped by (device_id, if_index, area_id), because the same physical port participates in several protocol instances at once, with a different cost, a different neighbour state and a different address family in each.

Derived roles fall out of that structure instead of being stored as labels:

  • ABR = attached to more than one area within an instance
  • ASBR = the E-bit set in the router’s own LSA (RFC 2328 §A.4.2), which is the router stating that it originates external routing information. Not a membership count: a router can be an ASBR while living in a single area, and it can span several instances without being one
  • VRF-Lite = present in more than one routing domain

Which is why nrt1-cr1 can be an ABR twice, and why the badge is drawn twice. Nobody typed “ABR” anywhere. It is a consequence of the memberships, recomputed from the LSDBs.


The topologies are all real at once

The useful way to think about this is that there is no such thing as the topology. There are several, they are all simultaneously true, and they answer different questions:

TopologyBuilt fromAnswers
PhysicalLLDP / CDP, IP-MIBWhat is cabled to what
L2Bridge/VLAN adjacencyWhat shares a broadcast domain
IGP (per instance)LSDB per protocol per areaWhat each protocol believes
BGPBMP RIBWhat is reachable and via whom
ForwardingEach router’s own tableWhere a packet actually goes

“Are A and B connected?” has five different correct answers depending on which of those you meant. Two routers can share a cable and no IGP adjacency. They can share an IGP adjacency and never forward a packet to each other. They can be BGP peers over a path that crosses three boxes neither of them can see.

Post three was really an argument about the last two rows: that the IGP topology and the forwarding topology are not the same graph, and treating them as one produced fictional paths one time in eight. This post is the same argument one level down: the physical topology and the protocol topology are not the same graph either, and 124 links in my lab prove it with a factor of ten.


What this costs

Being honest about this is not free. It means:

  • Two LSDBs to walk where a simpler tool walks one
  • A membership table instead of a foreign key
  • Roles recomputed rather than stored
  • Every path query needing to know which instance and which address family it is being asked about
  • A UI that has to show a tab strip on a link instead of a number

The alternative is a graph that renders faster, demos better, and quietly picks one of two costs on every dual-stack link in your network.

I have run networks where the IPv4 and IPv6 paths diverged and nobody noticed for months, because every tool on the wall drew one line between two routers. The line was not wrong. It was just answering a question nobody had asked.


Next: what happens when those sources contradict each other outright: When the Network Disagrees With Itself.