BGP Neighbor Stuck in Active, Idle or Connect: Decode the State

Active is a failure state and Idle is where the FSM gives up. Organised by the state you are looking at right now, with a lab finding that matters: on IOS XE 17.18.2 both "no route to peer" and "TCP 179 blocked" showed up as Idle.

Terminal card showing a BGP neighbor stuck in Idle with no active TCP connection, then reaching Established after OSPF installs the peer loopback

You have a BGP session that will not come up, and the right-hand column of show ip bgp summary is showing you a word instead of a number. That word is the whole reason you are here: Idle, Active or Connect, sitting there and not moving. This article is organised around that word, because the state you are staring at is the fastest way to narrow the search, and because two of the three names mean roughly the opposite of what they sound like.

Start with the naming, since it trips up almost everyone. Active does not mean the session is active. It means the router is actively trying to open a TCP connection and failing, which is a broken state. Idle does not mean waiting politely. It is where the FSM falls back to when something has gone wrong, and where a session starts before it has any reason to try. Only Established is good. If you want the formal machine, the full walk through every BGP neighbor state from Idle to Established covers the transitions in order; this page is about what to do when one of them will not advance. For the wider protocol picture, the complete BGP configuration and troubleshooting guide maps the whole cluster in reading order.

Everything below was captured on live routers: two iol-xe nodes running IOS XE 17.18.2 in Cisco Modeling Labs, back to back over 10.0.12.0/30, peering iBGP in AS 65001 across their loopbacks. One of the three labs produced a finding that changes how you should read the state column, so read to the end before you change any configuration.

First, read the summary correctly

The State/PfxRcd column is doing double duty, and that is the source of a lot of wasted time. It shows either a state name or a prefix count, and which one you get is itself the diagnosis:

  • A word (Idle, Connect, Active, OpenSent, OpenConfirm) means the session is not up. There is nothing to receive prefixes into.
  • A number means the session is Established and that is how many prefixes the peer has sent you. A session showing 0 is up and healthy, it just has nothing to advertise yet.

Here is the broken lab, held stable across samples from 06:34:33 to 06:37:03 so there was no argument about it being transient:

R1# show ip bgp summary
Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
2.2.2.2         4        65001       0       0        1    0    0 never    Idle

Three numbers on that line matter as much as the state. MsgSent 0 and MsgRcvd 0 mean not a single BGP message has ever crossed, so this is not a policy, capability or authentication problem (those all need a TCP session first). And Up/Down never means the session has never been Established in the lifetime of this process, which rules out flapping and a peer that reset you.

What each state is actually claiming

Each state is a statement about how far the router got before it stopped, and each one points at a different half of the problem.

Idle
Router isNot trying
Usual causeNo route to peer
First checkshow ip route peer
Connect
Router isWaiting on TCP
Usual causeSYN unanswered
First checkPeer BGP running
Active
Router isRetrying, failing
Usual causeTCP 179 blocked
First checkACLs, update-source
OpenSent / OpenConfirm
Router isNegotiating
Usual causeAS or RID mismatch
First checkLast NOTIFICATION

The line to draw is between the first three and the last two. Idle, Connect and Active all sit below the TCP layer, so the problem is transport: routing, filtering, source address, TTL. OpenSent and OpenConfirm mean TCP succeeded and the routers are arguing about the OPEN message, so the problem is configuration: a wrong remote-as, a duplicate router ID, an authentication mismatch. Those two halves need completely different investigations, and knowing why BGP runs over a TCP session in the first place makes the split obvious rather than arbitrary.

Connect deserves one note because it is the state people see least. A router in Connect has sent a SYN and is sitting on the ConnectRetry timer waiting for the handshake, so catching a session there usually means the far end is silently discarding the SYN or its BGP process is not listening. Connect is short lived, and the FSM drops back to Active or Idle when the retry timer expires, which is why you rarely find a session parked in it.

Case one: Idle because there is no route to the neighbor

This is the classic, and in the lab it is the iBGP-over-loopbacks trap. R1 peers with 2.2.2.2, which is R2's Loopback0, but nothing advertises the loopbacks into an IGP and there is no update-source statement. Here is what the router says when you ask it properly:

R1# show ip bgp neighbors 2.2.2.2
  BGP state = Idle, down for never
  Last reset never
  No active TCP connection

R1# show ip route 2.2.2.2
% Network not in table

That is the diagnosis in two lines. % Network not in table means R1 has no idea how to reach the address it was told to peer with, so it never attempts the TCP connection, which is exactly what No active TCP connection reports. Nothing is wrong with the BGP configuration. The routing table is the problem, and BGP is the thing complaining about it.

Peering over loopbacks needs two things and people routinely supply only one. You need a route to the peer's loopback, normally from the IGP, and you need update-source Loopback0 so your packets are sourced from the address the peer expects. Miss the route and you get what is above. Miss the update-source and your SYN arrives from the physical interface address, the peer does not recognise it as a configured neighbor, and refuses the connection. Both look identical in the summary. The correct way to build an iBGP peering across loopbacks is worth a re-read if you inherited the config rather than writing it.

The fix, and the proof that it was the fix

The repair is the two things above, applied together:

router ospf 1
 network 2.2.2.2 0.0.0.0 area 0
!
router bgp 65001
 neighbor 2.2.2.2 update-source Loopback0

What makes this convincing is not that the session came up, but the order in which it came up. In the fixed lab the routers booted with BGP already configured and OSPF not yet converged, so the session started out looking exactly like the broken lab:

*Jul 20 06:38:45: (still Idle at boot - OSPF not converged yet)
    R1# show ip bgp summary
    2.2.2.2  4  65001  0  0  1  0  0  never  Idle
    R1# show ip route 2.2.2.2
    % Network not in table

Then OSPF finished loading and BGP came up 353 milliseconds later, unprompted:

*Jul 20 06:39:22.595: %OSPF-5-ADJCHG: Process 1, Nbr 2.2.2.2 on Ethernet0/0 from LOADING to FULL, Loading Done
*Jul 20 06:39:22.948: %BGP-5-ADJCHANGE: neighbor 2.2.2.2 Up

That gap is the causal link. BGP was not reconfigured, cleared or touched. The instant the IGP installed 2.2.2.2/32 in the RIB, the FSM walked Idle to Connect to OpenSent to OpenConfirm to Established on its own. If your session is waiting on an OSPF adjacency reaching FULL, fix the IGP and stop looking at BGP.

R1# show ip bgp summary
Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
2.2.2.2         4        65001       2       2        1    0    0 00:00:12        0

R1# show ip bgp neighbors 2.2.2.2
  BGP state = Established, up for 00:00:13

R1# show ip route 2.2.2.2
Routing entry for 2.2.2.2/32
  Known via "ospf 1", distance 110, metric 11, type intra area
  * 10.0.12.2, from 2.2.2.2, 00:00:14 ago, via Ethernet0/0

Note the 0 in the State/PfxRcd column. That is a healthy session receiving zero prefixes, not a broken one. If you have got this far and your peer is up but nothing is in the RIB, that is a different article: why a BGP route is missing from the routing table is the failure you hit next.

Case two: the route is there and the session still will not come up

The third lab is the one that changes how you should read the state column. Both routers have update-source Loopback0, OSPF has converged and the peer loopback is in the RIB. The only difference is an inbound ACL on R2:

ip access-list extended BLOCKBGP
 deny tcp host 1.1.1.1 host 2.2.2.2 eq bgp
 deny tcp host 1.1.1.1 eq bgp host 2.2.2.2
 permit ip any any
!
interface Ethernet0/0
 ip access-group BLOCKBGP in

That permit ip any any at the bottom is why this is nasty in production. Pings work, traceroute works, OSPF hits FULL. Only TCP 179 between those two addresses disappears, and it disappears silently, with no ICMP unreachable to tell the sender anything. Here is what R1 reported, held for over four minutes of samples:

R1# show ip bgp summary
Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
2.2.2.2         4        65001       0       0        1    0    0 never    Idle

R1# show ip bgp neighbors 2.2.2.2
  BGP state = Idle, down for never
  Connections established 0; dropped 0
  Last reset never
  No active TCP connection

R1# show ip route 2.2.2.2
Routing entry for 2.2.2.2/32
  Known via "ospf 1", distance 110, metric 11, type intra area
  * 10.0.12.2, from 2.2.2.2, via Ethernet0/0

Read the state, then read the route. The state is Idle, identical to case one, and the route is present. That combination is the finding: on this IOS XE 17.18 build, a session with TCP 179 blocked reported Idle, not Active, for the entire test. Every article you have read (including the textbook, and including the state table earlier on this page) says a router failing to complete TCP shows Active. Classic IOS usually does. This build did not.

So the state name narrows the search but it does not identify the cause. What identifies the cause is the pair of outputs, not either one alone.

The two-command triage that actually separates the causes

Run these two on the router showing the stuck state, and read them together:

Stuck state + "% Network not in table"No route to the peer. Fix the IGP or the update-source.
Stuck state + route present + "No active TCP connection"TCP 179 is being dropped. Hunt the ACL, firewall or ttl-security.
Route present + TCP connected + OpenSentTransport is fine. Read the last NOTIFICATION for the real error.

The commands themselves are unglamorous:

show ip bgp summary
show ip bgp neighbors <peer>      ! read "BGP state" and the TCP connection line
show ip route <peer>              ! is there a route at all?
ping <peer> source Loopback0      ! test from the address BGP will actually use

That last one matters more than it looks. A plain ping 2.2.2.2 sources from the outgoing interface and can succeed while the BGP session, sourced from the loopback, is dropped by a filter matching the loopback address. And if the route is present but TCP will not open, the filter is not always on your side: in this lab the ACL was on the peer's inbound interface and R1 had no way to see it. Check both ends, and check how an inbound ACL is evaluated on IOS XE before you assume a rule that permits everything else must be innocent.

What this was captured on

R1 and R2 are iol-xe nodes running IOS XE 17.18.2 in CML, connected back to back on Ethernet0/0 in 10.0.12.0/30, peering iBGP in AS 65001 between Loopback0 addresses 1.1.1.1 and 2.2.2.2. Three separate labs were built: one with no IGP and no update-source (stuck Idle), one with OSPF area 0 advertising the loopbacks plus update-source Loopback0 (Established), and one identical to the second except for the inbound BLOCKBGP ACL on R2.

One note on method. The PyATS console path was unavailable during this run, so show output was captured by an on-box EEM applet logging to syslog, read back through the CML console-log API. The text is verbatim device output either way, and the repeated sampling is why the stuck states are described as stable for minutes rather than as a snapshot.

Gotchas

  • The state name is a hint, not a verdict. The same word covered two completely different root causes on the same software version. Pair the state with show ip route <peer> every single time.
  • Active is a failure state. If you report "the neighbor is Active" in a change call and someone relaxes, correct them. The router is failing and retrying.
  • A number in State/PfxRcd is good news, including zero. A peer showing 0 is Established. Do not troubleshoot a working session because the column looks empty.
  • MsgSent 0 rules out an entire class of causes. No messages sent means no TCP session, so it cannot be an AS mismatch, a password mismatch or a capability problem (those all need OPEN messages to have crossed). The order in which BGP messages are exchanged tells you which failures are still possible at a given state.
  • Ping is not proof. An ACL that denies only TCP 179 and permits everything else leaves the link passing every test a reasonable engineer runs first.
  • Check the far end. The blocking filter, the missing neighbor statement and the wrong remote-as are invisible from the router showing the symptom.
  • If the session did come up once, this is not your article. A session that reaches Established and then drops is a hold-timer, max-prefix or link-quality problem. The systematic checklist for a BGP adjacency that flaps or gets rejected covers flapping, NOTIFICATION decoding and authentication in detail.

Key takeaways

  • A word in State/PfxRcd means the session is down. A number, even 0, means it is Established.
  • Idle, Connect and Active are pre-TCP states, so the cause is transport: routing, filtering, source address or TTL. OpenSent and OpenConfirm mean TCP worked and the OPEN was rejected.
  • Active is a broken state despite the name, and Idle is where the FSM falls back to when it has given up.
  • The state alone does not identify the cause. On IOS XE 17.18.2 both "no route to peer" and "TCP 179 blocked by an ACL" presented as Idle with No active TCP connection and MsgSent 0.
  • show ip route <peer> is the command that separates them. No route means fix the IGP or the update-source. Route present means hunt the filter, at both ends of the link.
  • For iBGP over loopbacks you need the IGP route and update-source Loopback0. In the lab BGP came up 353 ms after OSPF reached FULL, with no BGP change at all.

The habit worth building is to stop treating the state column as an answer and start treating it as the first of two data points. Collect the state, the route and the TCP connection line together, and most stuck sessions resolve in under two minutes. When the peering is up and you move on to why the prefixes are not where you expect them, the rest of the series, from peering design through path attributes and best-path selection, picks up from there.

Read next