← All posts

What Osprey Refuses to Guess

The most important thing I built is a set of refusals

Michel Wijnberg

A network tool that guesses is worse than one that admits ignorance, and the reason is not philosophical. It is operational.

If a tool says “I don’t know”, you go and find out. If it produces a plausible answer, you act on it. And nothing on the screen distinguishes a correct answer from a confident one, so the failure mode is not “the tool was wrong”, it is “the tool was wrong and I had no reason to check”.

So Osprey has a rule that overrides every product instinct I have: state the evidence, or state that there is none. Never interpolate. Never render a placeholder that looks like data.

Here is what that actually looks like in a shipping product.


1. “I cannot compute this path the good way”

The previous post was about the hop-by-hop forwarding chain, following every router’s own routing table instead of drawing one source-rooted corridor, validated exactly against all 4,032 router pairs in AS 200.

That engine works for OSPFv2. It does not work for IS-IS, and Osprey says so rather than quietly falling back:

An IS-IS path with an explanation step declaring the forwarding chain unavailable
An IS-IS path with an explanation step declaring the forwarding chain unavailable

4. Hop-by-hop forwarding chain unavailable Showing the source’s own shortest-path view, which every intermediate router may legitimately disagree with. Osprey does not model this protocol’s inter-area reachability hop-by-hop (IS-IS carries inter-level reachability differently from OSPF and has no Type-3 equivalent to persist, so Osprey stores nothing from which L1↔L2 route leaking could be reconstructed. An L1-only source in particular forwards on the attached-bit default toward its nearest L1/L2 router, not by end-to-end cost; EIGRP has its own observed chain).

Three things about that message.

It names the model that answered: the source’s shortest-path view, so you know which of two engines you are looking at. It names the reason: Osprey stores nothing it could reconstruct L1↔L2 route leaking from. That is a limit of Osprey’s model, not of the protocol: IS-IS has no Type-3 summary LSA because it never needed one, carrying inter-level reachability in L2 LSPs and the attached bit instead. And it names the specific consequence, which is the part that would actually bite you: an L1-only source does not forward by end-to-end cost at all. It follows the attached bit to its nearest L1/L2 router, per ISO 10589. Its real first hop may have nothing to do with the drawn path.

The path is still shown, because a shortest-path view is genuinely useful. It is just not permitted to masquerade as the stronger answer.

The same discipline applies to OSPFv3, to a scope holding only part of a protocol instance’s areas, to areas carrying a virtual link, and to routers living in two protocol instances that can both carry the address family. Each gets its own named reason. None of them silently reinstates the old picture.


2. “This number would not mean anything”

EIGRP is not a link-state protocol. There is no database to join, no SPF to run, and, importantly, no meaningful way to add up hop costs, because EIGRP’s composite metric describes an entire path rather than a single link.

So Osprey does not print a total:

An EIGRP path with a Metric column and no total cost
An EIGRP path with a Metric column and no total cost

Observed EIGRP forwarding chain EIGRP has no link-state database; this path follows the routers’ own DUAL result (per-hop topology tables), so there is no summed cost to show: 3 RIB-installed variant(s) shown alongside (the RIB holds equal next-hops).

What you get instead is each router’s own computed distance toward the destination, decreasing along the chain: 712704 → 710144 → 658944 → 556544 → 505344 → 428544 → 223744 → 133120 → 128256.

Every one of those numbers came off a router. None of them were derived. The empty “total cost” field is not a gap in the implementation. It is the correct rendering of a quantity that does not exist.

The same rule fires across an AS boundary, where an OSPF cost and an IS-IS cost are numbers in unrelated metric spaces:

Per-segment costs (never summed) | 15 hops


3. “Here is exactly how confident I am, per segment”

Cross-domain paths cannot be computed. They can only be stitched from evidence, and the evidence is not uniformly good, so Osprey grades it per segment rather than issuing one blanket confidence for the whole path:

A cross-domain path with per-segment confidence badges: AS 200 resolved, AS 300 inferred
A cross-domain path with per-segment confidence badges: AS 200 resolved, AS 300 inferred

AS 200 ospfv2/1 cost 20051 is resolved. AS 300 isis/LAB cost 1320 is inferred. Same path, same screen, different epistemic status, both labelled.

Behind those badges is a strict ladder, tried in order:

RungEvidenceConfidence
aA RIB row at a border in that domain covering the destinationresolved
a2A route server whose own BMP RIB covers the destination via the next ASinferred (bmp-rib-rs)
bAn established eBGP session toward the next AS on the chaininferred
cNothingopaque: rendered as a segment with a note, no hops drawn

Rung (c) is the one that matters. When Osprey cannot establish how traffic enters a domain, it does not interpolate a plausible-looking set of hops. It draws an explicitly opaque segment and explains itself, and where the cause is actionable, it says the actionable thing rather than a generic apology. The message takes this shape:

AS 65000 has no areas in the selected scope. Include its areas to trace through this domain

That is a message you can do something with. “Entry point unknown” is not. (The lab paths in these posts all resolve, so that particular note is not one of the screenshots here. It fires when a scope genuinely omits a transit AS.)

Rung (a2) exists for a specific reason worth calling out: a transparent route server never appears in the AS_PATH. Without reading the route server’s own RIB there is no way to see an IX detour at all. The path would look direct when it is not.


4. “These ports are a fact / a guess / genuinely ambiguous”

When Osprey annotates an eBGP transition with physical ports, it distinguishes four situations rather than collapsing them into one confident answer:

  • Exactly one link pair, no fabric alternative → ports stated as fact: jfk1-gw1 Et1/1 → i-jfk1-gw1 Et1/2
  • Parallel links → an aggregate, with the uncertainty named: “3 parallel L2 links: Gi2↔Et1/0, … (session link undetermined)”
  • Both borders on a shared bridge, no direct link → fabric presence with attachment ports, a statement that a bridge exists between them, never a claim that the session crosses it
  • Both a direct link and a shared fabric → explicit ambiguity naming both and choosing neither

Plus the supporting rules: rows must be fresher than 13 hours, age is disclosed above 6 hours, and a bridge matched only on sysname vetoes a port claim without ever being displayed as fact.

The strongest rung upgrades a guess to a fact, when both BGP session addresses resolve to specific ports through the devices’ IP-MIB bindings, the annotation becomes ip-bound and overrides the ambiguity gates, because at that point it is no longer an inference.


5. “These fields are not available”

The subtlest one, and my favourite:

The LSDB browser stating that LSAge, SeqNo and Checksum are not available
The LSDB browser stating that LSAge, SeqNo and Checksum are not available

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

Those LSAs were reconstructed from SNMP walks rather than received over a protocol adjacency, and an SNMP walk of the OSPF MIB gives you LSA contents but not the live header fields.

The tempting implementation is three columns of zeroes. They would render beautifully, sort fine, and be a lie. And worse, an undetectable lie, because an LSA with age 0 looks like a freshly flooded LSA rather than a missing measurement.

So the columns are absent and the reason is printed at the top of the panel.


6. Refusing to use my own best engine

The one I am most pleased with, because it cost me a feature.

Osprey’s simulation mode lets you fail links, drop nodes, change metrics and watch traffic shift. The obvious move is to run the shiny new hop-by-hop chain engine against the mutated topology.

Osprey deliberately does not.

A post-mutation forwarding chain is not computable. Following each router’s own table requires knowing what each router’s table would be after the change, and that depends on the Type-3 summary LSAs the surviving ABRs would re-originate. Those LSAs do not exist yet. They cannot be synthesised without guessing, and guessing them would produce a hop-by-hop path with all the authority of the validated engine and none of the validation.

So both sides of simulation stay on the clearly-labelled SPF projection, and say so in the notices. The better-looking answer was available. It just would not have been true.


Why this is a feature and not an apology

I sell a network topology product. Every one of the behaviours above makes a screenshot slightly less impressive than a competitor’s, and I have had the conversation where someone points out that a confident answer demos better.

It does. It also destroys the only thing that makes the tool worth having.

An engineer at 03:00 with a partitioned area does not need a beautiful picture. They need to know which parts of the picture they can bet on. A product that grades its own evidence (resolved, inferred, opaque, unavailable, not computable) lets them spend their scepticism where it belongs instead of distributing it evenly across everything on screen.

The measurement in the previous post is what earns that trust: 4,032 of 4,032 router pairs reproduced exactly against ground truth read off the routers. The refusals in this one are what protect it. A tool that is right 4,032 times and then quietly bluffs on the 4,033rd has taught you nothing about which case you are in.

Say what you know. Say how you know it. Say when you don’t.


This closes the first series. The lab tour is here, the passive-discovery architecture here, and the hop-by-hop path engine here. A second series, on holding several truths at once, ranking conflicting evidence, and proving your own product wrong, starts with The Same Router, Three Different Truths.