BGP Route Not in the Routing Table: Why It Is Not Installed

The prefix is in the BGP table and show ip route says % Network not in table. The leading status characters are the whole diagnosis. Captured live on IOS XE 17.18.2 in CML, where a missing next-hop-self leaves an iBGP path valid, inaccessible and never installed.

Terminal card showing a BGP path with an inaccessible next hop and no best path, then the same prefix installed as a B route after next-hop-self

You run show ip bgp and the prefix is right there. You run show ip route for the same prefix and get % Network not in table. No neighbor has flapped, the session is Established, the path looks perfectly healthy, and traffic is still going somewhere else.

That gap is not a bug and almost never a mystery. BGP keeps every path it is sent, hands the routing table exactly one path per prefix, and the RIB gets the final say on whether it accepts. A prefix that sits in BGP and never reaches the RIB failed at one of those two steps, and the leading characters on each line of show ip bgp tell you which. Most engineers skim straight past them. For the wider context on how BGP chooses and installs paths, the pillar covers the attribute machinery this article assumes.

One boundary first, because these two problems get conflated constantly. If your neighbor never receives a prefix at all, that is the sending side, covered in why a router is not advertising a prefix to its neighbor. This article owns the receiving side: it arrived, you can see it, and it will not install. Everything below came off a live CML lab of three iol-xe routers on IOS XE 17.18.2, R1 in AS 65001 speaking eBGP to R2 in AS 65002, R2 speaking iBGP to R3.

Read the status codes before you read anything else

Every prefix line in show ip bgp starts with a two or three character status field, and that field is the entire diagnosis. It is explained in a legend at the top of the output that everyone reads once, in their first week, and scrolls past forever after.

*Valid. The path passed sanity checks and BGP is willing to consider it.
>Best. This is the one path BGP offers to the RIB and advertises to peers.
iLearned from an iBGP peer. Installs at AD 200, not 20.
rRIB-failure. BGP picked this path and the routing table refused it.
sSuppressed by aggregation. A summary is being advertised instead.
d / hDampened, or history. The prefix has been flapping and is being penalised.

Two of those matter more than the rest here. A line with * and no > means the path is valid but is not the one BGP is offering the RIB, so the failure happened inside BGP. A line with r means the opposite: BGP selected a best path, tried to install it, and the RIB pushed back. Completely different fix lists, and the difference is one character. (Do not confuse the i in the status field with the trailing origin code at the end of the same line, which is also frequently i. Same letter, different column, unrelated meanings.)

Cause 1: the next hop is not reachable

This is the one. If you take a single reflex from this article, make it "check the next hop first", because unresolved next hops account for more not-installed BGP routes than everything else combined. Here is the broken state, R3 holding 100.100.100.0/24 from its iBGP peer R2:

R3# show ip bgp 100.100.100.0/24
BGP routing table entry for 100.100.100.0/24, version 0
Paths: (1 available, no best path)          <-- one path, and BGP picked none of them
  Flag: 0x8100
  Not advertised to any peer
  Refresh Epoch 1
  65001
    10.0.12.1 (inaccessible) from 10.0.23.2 (2.2.2.2)
      Origin IGP, metric 0, localpref 100, valid, internal
      rx pathid: 0, tx pathid: 0

R3# show ip route 100.100.100.0
% Network not in table

Three things there do all the work: the next hop reads 10.0.12.1 (inaccessible), the summary says no best path despite one path being available, and the attribute line says valid, internal. That last one trips people up, because the path is flagged valid and BGP still refuses to select it. Validity is about the update being well formed, selection is a separate step, and RFC 4271's decision process disqualifies any path whose next hop cannot be resolved in the RIB before the tie-breakers ever run. BGP does not discover topology, it advertises reachability and leans recursively on the local routing table to reach the next hop. R3 has no route to 10.0.12.1, so everything stops there.

Why is the next hop unreachable? 10.0.12.1 is R1's address on the R1 to R2 link, a subnet R3 has no route to. R2 passed the prefix from eBGP into iBGP and left the next hop untouched, which is specified behaviour rather than a bug (the assumption being that everyone inside the AS can reach the AS boundary). If your edge links are not in the IGP, that assumption is false and every downstream speaker inherits a path it cannot use.

Confirm it in one command: take the next hop out of the BGP entry and run show ip route 10.0.12.1. If that returns % Network not in table, you are done diagnosing, with no need to look at attributes or filters at all.

The fix, and what an installed path looks like

Two honest options: advertise the edge subnet into your IGP so every internal router can resolve it, or have the border router rewrite the next hop to itself. The second is the standard answer, and the entire reason next-hop-self exists:

router bgp 65002
 neighbor 10.0.23.1 next-hop-self
!
clear ip bgp 10.0.23.1 soft out

Applied on R2, that rewrites the next hop to R2's own iBGP-facing address, which R3 reaches over a directly connected /30, and the soft clear pushes the updated attributes without tearing the session down. R3 immediately afterwards:

R3# show ip bgp 100.100.100.0/24
BGP routing table entry for 100.100.100.0/24, version 2
Paths: (1 available, best #1, table default)
  65001
    10.0.23.2 from 10.0.23.2 (2.2.2.2)
      Origin IGP, metric 0, localpref 100, valid, internal, best

R3# show ip route 100.100.100.0
Routing entry for 100.100.100.0/24
  Known via "bgp 65002", distance 200, metric 0
  Tag 65001, type internal
  * 10.0.23.2, from 10.0.23.2, 00:00:17 ago

Same prefix, same peer, same AS path. The only change is a next hop the local RIB can resolve, and the path goes from no best path to best #1 and lands in the routing table. Note distance 200 and type internal, because that becomes cause five. If the fields in that entry are not second nature yet, ten minutes on what each part of a Cisco routing table entry actually means pays for itself, since half of BGP troubleshooting is really RIB reading.

Cause 2: valid, but not best

If the prefix has several paths and one carries >, the others are working as designed. BGP is not a load balancer by default: it picks a single winner, and only that winner is offered to the RIB and re-advertised. Every other path sits there as a warm standby.

This becomes a real complaint when the winner is not the one you wanted, which produces the same phone call even though the prefix is in the RIB, just via a next hop nobody expected. Work down the order BGP compares paths in until you find the step that decided it, remembering that weight and local preference sit near the top, so a stray inbound route-map beats any amount of AS path engineering further down. If you want two paths installed, that is maximum-paths: opt-in, fussy about attribute equality, and not a fallback for a path that lost.

Cause 3: it never reached this router in the first place

Look again at one line in the broken capture: Not advertised to any peer. A path that is not best is not propagated, so R3 not only failed to install the prefix, it declined to pass it on, and a single unresolved next hop silently blackholes every device behind it.

The related trap is iBGP split horizon. A route learned from an iBGP peer is never advertised to another iBGP peer, full stop, because there is no AS path loop prevention inside an AS (which is why iBGP needs a full mesh, or route reflectors to fake one). From the far end that looks identical to a filtering problem. Tell them apart at the middle router: prefix present there and absent downstream means split horizon or a non-best path, not a filter. Check the session is genuinely up while you are there, because a peer that keeps resetting shows prefixes appearing and vanishing, which reads as an install problem when it is really a neighbor that is not staying in Established.

Cause 4: synchronisation, and why it is probably not your problem

The old synchronisation rule said a router must not use or advertise an iBGP-learned route until the same prefix appeared in its IGP, so that non-BGP routers in the middle of the AS would not black-hole transit traffic. It has been off by default since IOS 12.2(8)T and stays off on modern IOS XE, so on any current box this is not your problem. It earns a mention only because it appears in CCNP question banks and still lurks in configs copied from a 2003 template.

Cause 5: something with a better administrative distance already owns the prefix

This is what the r code exists for, and it is the most misread symptom in the list. RIB-failure does not mean BGP failed. It means BGP selected a best path, offered it to the routing table, and the routing table declined because it already holds that prefix from a source it trusts more.

The numbers make it obvious. eBGP installs at AD 20, beating OSPF at 110 and EIGRP at 90. iBGP installs at AD 200, losing to essentially every IGP and to any static route. Look back at the working capture: distance 200. Had that prefix also been present via OSPF, OSPF would have won and the BGP path would be flagged r instead. The asymmetry is deliberate, and the full picture of which routing source wins when two protocols offer the same prefix is worth keeping to hand.

Reach for show ip bgp rib-failure, which lists every prefix BGP could not install and why. Note the sting in the tail: a RIB-failed route is still advertised to your peers, so you are telling the world you can reach a prefix while forwarding it by a different protocol's idea of the topology.

Cause 6: inbound filtering, which looks like the same problem

If the prefix is not in show ip bgp at all, the update was either never sent or discarded on arrival. Prove which by comparing what the peer sent against what you kept. With neighbor x.x.x.x soft-reconfiguration inbound configured, show ip bgp neighbors x.x.x.x received-routes gives the pre-policy view and show ip bgp neighbors x.x.x.x routes the post-policy view. A prefix in the first and not the second is your own prefix-list, distribute-list, or route-map eating it.

The subtler version does belong here. An inbound route-map can leave a prefix visible but unusable, most cruelly with set ip next-hop pointing at an address the router cannot resolve, reproducing the (inaccessible) symptom from cause one on a router where the peering is fine and the neighbor is blameless. If the next hop is not an address you expected, read your own inbound policy before you call the other side.

What this was captured on

Three iol-xe nodes in Cisco Modeling Labs on IOS XE 17.18.2. R1 in AS 65001 originates 100.100.100.0/24 from a loopback and peers eBGP with R2 over 10.0.12.0/30. R2 in AS 65002 peers iBGP with R3 over 10.0.23.0/30 and starts without next-hop-self, which is the entire break, and R3 has no route to the edge link. Output was collected on-box by an EEM applet writing show results to syslog, read back through the CML console log API, so everything above is verbatim.

Gotchas

  • "valid" does not mean installable. The capture shows valid, internal alongside no best path in one output. Validity and selection are different gates, with next-hop resolution between them.
  • (inaccessible) ends the investigation. Read the next-hop line before the attribute line, every time.
  • eBGP next hops pass into iBGP unchanged. If your edge links are not in the IGP, the symptom lands on routers that have no idea the eBGP session exists.
  • A non-best path is not advertised onward. One router's next-hop failure shows up downstream as a total absence of the prefix.
  • Use a soft clear. clear ip bgp <peer> soft out re-sends updates without dropping the session. A hard clear ip bgp * on a production edge is a resume-generating event.

Key takeaways

  • The BGP table and the RIB are separate structures. A prefix can live in one and not the other, permanently, with nothing logging an error.
  • Read the status characters first. No > means BGP did not select the path, an r means the RIB refused it. Different problems, different fixes.
  • Check next-hop reachability before anything else. show ip route <next-hop> answers the most common cause in one command, and next-hop-self is the standard fix.
  • An installed iBGP route carries AD 200, so any IGP holding the same prefix wins and pushes BGP into RIB-failure while you keep advertising the prefix to peers.
  • If the prefix is not in show ip bgp at all, that is the other problem, and the diagnosis moves to the sending side and your inbound policy.

Next hop, then best path, then RIB. Three checks in that order resolve almost every instance of this, and all three are quicker than reading configuration. The rest of the BGP troubleshooting and design series covers the attributes and neighbor states either side of this one.

Read next