← All posts

Three IGPs, One Map

What 192 routers, three carriers and three routing protocols look like on a single pane of glass

Michel Wijnberg

I have a lab. It is not a diagram and it is not a simulator. It is 192 real routers running real protocol stacks, and I use it every day to build Osprey against something that can actually contradict me.

The lab is deliberately awkward. It holds three carriers that share nothing:

TenantASNIGPShape
Harrier-Broadband200OSPFv2 and OSPFv315 areas per protocol, dual-stack on the same wires
Kestrel-Dynamics100EIGRP, IPv4 + IPv6flat, because EIGRP has no areas
Merlin-Carrier300IS-IS, multi-AF17 level-1 areas under a level-2 backbone

Three protocols, three address plans, three ASNs, three sets of credentials. No shared IGP anywhere. This is roughly the worst case a topology tool can be handed, which is exactly why I built it.

The Osprey dashboard: three tenant networks, 192 devices, 441 links, 50 areas
The Osprey dashboard: three tenant networks, 192 devices, 441 links, 50 areas

Everything below is a screenshot of that lab, taken live while writing this post. Nothing is mocked up.


Why the hierarchy comes before the picture

Most topology tools start with a canvas and bolt structure on afterwards. That works until the same physical router legitimately belongs to two different answers at once. In a carrier network, that is Tuesday.

Osprey inverts it. Every object hangs off an explicit hierarchy:

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

That chain is not decoration. It is what lets the product answer “which OSPF process, in which VRF, in which AS, under which tenant” without guessing, and it is why a device can be an ABR in one instance and an ordinary internal router in another without the model tying itself in knots.

The hierarchy sidebar: OSPF 1 and OSPFv3 1 side by side, each with its own 15 areas
The hierarchy sidebar: OSPF 1 and OSPFv3 1 side by side, each with its own 15 areas

Note what the sidebar is showing: OSPF 1 and OSPFv3 1 (v6) are separate protocol instances, each carrying its own set of 15 areas, each with its own LSDB and its own SPF. They run over the same physical links. They are not merged into one hopeful “IGP” abstraction, because they genuinely are not one thing. RFC 5340 gives OSPFv3 its own LSDB and its own topology, and pretending otherwise produces wrong answers the moment the two disagree.


Harrier-Broadband: OSPF, 15 areas, dual-stack

Here is AS 200, coloured by area:

Harrier-Broadband: 64 routers, 151 links, 30 areas, coloured by OSPF area
Harrier-Broadband: 64 routers, 151 links, 30 areas, coloured by OSPF area

64 routers, 151 links, 30 areas (15 in OSPFv2, 15 in OSPFv3). The blue mass in the middle is area 0.0.0.0, the backbone. Every coloured cluster hanging off it is a non-backbone area reaching the backbone through its ABRs.

At this size the picture is still readable. At five times this size it would not be, which is why the same topology can collapse into its areas:

Area cloud overview: 15 areas as clouds around the backbone, with edge-bundle counts
Area cloud overview: 15 areas as clouds around the backbone, with edge-bundle counts

Each cloud is an area; each line is a bundle of inter-area adjacencies with the count on it (, , ). This is the view I actually use to answer “how badly is area 19.5.1.0 attached to the backbone?”. The answer here is “by four links”, which is a very different risk profile from the two-link areas next to it.


Merlin-Carrier: IS-IS, and the address family actually matters

AS 300 runs IS-IS. Same physical shape, completely different protocol model:

Merlin-Carrier: 64 routers under IS-IS, 17 level-1 areas plus the level-2 backbone
Merlin-Carrier: 64 routers under IS-IS, 17 level-1 areas plus the level-2 backbone

IS-IS is where a lot of tools quietly fall over, because IS-IS is not “OSPF with different words”. One IS-IS LSDB can carry reachability for CLNS, IPv4 and IPv6 simultaneously, and the correct shortest path is per address family.

So Osprey computes it per address family, and tells you which one you are looking at:

An IS-IS path with the address-family selector set to CLNS, showing System IDs and circuits
An IS-IS path with the address-family selector set to CLNS, showing System IDs and circuits

Look at the hop table. Because the address family is CLNS, the hops are identified by System ID (0100.6600.8003) and circuit, not by an IPv4 address, which would be meaningless in a CLNS path. Switch the selector to IPv4 or IPv6 and the same path re-renders with the addressing that family actually uses.

(That screenshot is also making an admission about hop-by-hop modelling in IS-IS. That is the subject of a later post and I am not going to bury it here.)


And then there is AS 100:

Kestrel-Dynamics: 64 routers under EIGRP, one colour, because EIGRP has no areas
Kestrel-Dynamics: 64 routers under EIGRP, one colour, because EIGRP has no areas

One colour. Two “areas”. That is not a rendering bug. It is EIGRP being honest about itself.

EIGRP is a distance-vector protocol with no link-state database to join and no area concept to colour by. The two entries are simply the IPv4 and IPv6 instances. EIGRP does form neighbour adjacencies, over its own Hello protocol, but there is no link-state database behind them to walk and no SPF to run: neighbours exchange distance vectors, not a synchronised map. So Osprey reads it read-only from CISCO-EIGRP-MIB and reconstructs the adjacency graph from what each router reports about its own neighbours. In this lab that is 580 live neighbour relationships.

That difference propagates all the way to path computation, and it is visible:

An EIGRP path whose Metric column decreases at every hop
An EIGRP path whose Metric column decreases at every hop

There is no “total cost” on that path, and there was never going to be. EIGRP’s composite metric describes a whole path, not a single hop, so summing hop costs would produce a number that means nothing. What you get instead is each router’s own current computed distance toward the destination, decreasing along the chain: 712704 → 710144 → 658944 → … → 128256. That is exactly what you would read off the routers one at a time. (DUAL’s Feasible Distance is a subtly different quantity: the minimum since the route last went passive, the feasibility threshold. The hop table keeps the two apart rather than labelling one as the other.)

Three protocols, three genuinely different models, three correct answers. Not one abstraction pretending they are the same.


Underneath the picture: the LSDB itself

The canvas is a rendering. The model underneath it is the link-state database, and Osprey keeps it browsable:

The LSDB browser: 13,382 LSAs reconstructed, split by LSA type
The LSDB browser: 13,382 LSAs reconstructed, split by LSA type

13,382 LSAs, split by type: Router (1), Network (2), Summary (3), ASBR (4), External (5) and NSSA (7). The ABR and ASBR flags are derived from the LSAs themselves rather than from a naming convention.

Read the line under the title carefully:

13382 LSAs reconstructed (LSAge, SeqNo, Checksum not available)

These LSAs were reconstructed from SNMP walks, not received over a protocol adjacency. An SNMP walk of the OSPF MIB gives you the LSA contents but not the live header fields. So Osprey shows the contents and states plainly that three fields are missing, rather than rendering three columns of zeroes that would look like data.

That is a small thing. It is also the whole design philosophy in one line, and it is why I trust the other 13,382 numbers on that screen.


The point

The map is not the product. The model is.

Three carriers that share no protocol, no address plan and no ASN sit in one tool without any of them being flattened into a lowest common denominator. OSPF keeps its areas and its dual LSDBs, IS-IS keeps its levels and its address families, EIGRP keeps its DUAL distances and its complete absence of a link-state database.

Where they genuinely differ, the product differs. Where it cannot know something, it says so.


Osprey is passive: no agents on routers, no route injection, no packet forwarding. How that actually works, and what it costs, is the next post.