iBGP Update-Source and Next-Hop-Self on Cisco
Two routers in the same autonomous system that each connect to other ASes need an iBGP session between them, and two neighbor options decide whether that session is useful. update-source sets the address the session runs from, so the peering can use loopbacks instead of a physical link. next-hop-self rewrites the next hop on routes a border router passes to its iBGP peer, because by default iBGP hands over the external neighbor's address, which the rest of the AS usually cannot reach.
This guide builds both on IOS XE, shows what each failure looks like in real output, and ends with a checklist for an iBGP route that will not install. It assumes you can already bring up a basic session; if not, start with how to configure eBGP peering.
Part of the BGP learning hub. Practice on hands-on CCNP labs.
The topology used in every example
Four IOS XE routers. R1 and R2 form AS 65001 and run OSPF area 0 between them. Each has one external neighbor, and a link between those two neighbors gives every external prefix two ways into AS 65001.
- R1: Loopback0 10.255.0.1/32, Ethernet0/0 10.0.12.1/30 to R2, Ethernet0/1 10.0.13.1/30 to R3 in AS 65002. Originates 172.16.1.0/24 from Loopback1 (172.16.1.1/24).
- R2: Loopback0 10.255.0.2/32, Ethernet0/0 10.0.12.2/30 to R1, Ethernet0/1 10.0.24.1/30 to R4 in AS 65003. Originates 172.16.2.0/24 from Loopback1 (172.16.2.1/24).
- R3 originates 198.51.100.0/24. R4 originates 203.0.113.0/24 and 192.0.2.0/24. R3 and R4 also peer with each other on 10.0.34.0/30.
- OSPF carries only 10.0.12.0/30 and the two Loopback0 addresses. The eBGP link subnets are not in OSPF, which is common when the far end of the link belongs to another organization.
Step 1 — Carry the loopbacks in the IGP
An iBGP session is a TCP connection on port 179 between the two addresses in the neighbor statements. Peer to a physical interface address and the session depends on that one link. Peer to a loopback interface and the session follows whatever path the IGP finds, so it stays up while any path between the two routers survives. This topology has a single internal link, so the gain shows only in an AS with two or more internal paths, where the session survives a link failure.
The cost is that each loopback must be reachable before BGP can use it. BGP does not find that path; the IGP does. Each router advertises its Loopback0 into OSPF with a host network statement next to the internal link. The OSPF syntax is covered in how to configure single-area OSPF.
iBGP does not need ebgp-multihop. That command raises the TTL of eBGP packets, which default to 1. IOS already sends iBGP packets with a TTL of 255, as the Step 3 output shows.
R1(config)# interface Loopback0
R1(config-if)# ip address 10.255.0.1 255.255.255.255
R1(config-if)# exit
R1(config)# router ospf 1
R1(config-router)# router-id 10.255.0.1
R1(config-router)# network 10.0.12.0 0.0.0.3 area 0
R1(config-router)# network 10.255.0.1 0.0.0.0 area 0
R2(config)# interface Loopback0
R2(config-if)# ip address 10.255.0.2 255.255.255.255
R2(config-if)# exit
R2(config)# router ospf 1
R2(config-router)# router-id 10.255.0.2
R2(config-router)# network 10.0.12.0 0.0.0.3 area 0
R2(config-router)# network 10.255.0.2 0.0.0.0 area 0Loopback0 and OSPF on both AS 65001 routers. The eBGP link subnets are left out on purpose.
Confirm the route to the peer's loopback
Check this before touching BGP. R1 should know 10.255.0.2/32 from OSPF. If that route is missing, the iBGP session cannot come up, however the BGP lines are written.
R1# show ip route 10.255.0.2
Routing entry for 10.255.0.2/32
Known via "ospf 1", distance 110, metric 11, type intra area
Last update from 10.0.12.2 on Ethernet0/0, 00:00:47 ago
Routing Descriptor Blocks:
* 10.0.12.2, from 10.255.0.2, 00:00:47 ago, via Ethernet0/0
Route metric is 11, traffic share count is 1Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
Step 2 — Peer to the loopback and set update-source
Point each neighbor statement at the other router's Loopback0 and add update-source Loopback0. The remote-as value is your own AS number, which is what makes the session iBGP.
The update-source line matters because of how BGP accepts connections. A router accepts an incoming BGP connection only when its source address matches one of the router's neighbor statements. Without update-source, IOS sources the connection from the interface that routes toward the peer, which here is Ethernet0/0. R2 would see a connection from 10.0.12.1, find no neighbor with that address, and refuse it.
Set bgp router-id as well. Without it BGP takes the highest loopback address — on R1 that is 172.16.1.1 on Loopback1, which reads confusingly next to a session between 10.255.0.x addresses.
R1(config)# router bgp 65001
R1(config-router)# bgp router-id 10.255.0.1
R1(config-router)# neighbor 10.255.0.2 remote-as 65001
R1(config-router)# neighbor 10.255.0.2 update-source Loopback0
R1(config-router)# neighbor 10.0.13.2 remote-as 65002
R1(config-router)# network 172.16.1.0 mask 255.255.255.0
R2(config)# router bgp 65001
R2(config-router)# bgp router-id 10.255.0.2
R2(config-router)# neighbor 10.255.0.1 remote-as 65001
R2(config-router)# neighbor 10.255.0.1 update-source Loopback0
R2(config-router)# neighbor 10.0.24.2 remote-as 65003
R2(config-router)# network 172.16.2.0 mask 255.255.255.0The iBGP and eBGP neighbor statements on both AS 65001 routers.
How IOS stores these lines
Read the configuration back instead of trusting what you typed. An IPv4-only configuration prints as one flat block: remote-as, update-source, the network statement and the next-hop-self line that Step 5 adds all sit directly under router bgp, and IOS adds bgp log-neighbor-changes on its own. Configure anything under address-family ipv4 and IOS reprints the same settings with the network, activate and next-hop-self lines indented inside that block.
IOS prints the block in its own order, not yours: the network statement first, then neighbors by address, so eBGP neighbor 10.0.13.2 sits above the iBGP neighbor typed before it. Read it whenever a session will not come up — nothing else names a missing update-source.
R1# show running-config | section router bgp
router bgp 65001
bgp router-id 10.255.0.1
bgp log-neighbor-changes
network 172.16.1.0 mask 255.255.255.0
neighbor 10.0.13.2 remote-as 65002
neighbor 10.255.0.2 remote-as 65001
neighbor 10.255.0.2 update-source Loopback0
neighbor 10.255.0.2 next-hop-selfOutput captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
Step 3 — Verify the session runs between the loopbacks
An Established session proves the two neighbor statements agree; the neighbor detail proves which addresses carry it. On R2, filter show ip bgp neighbors down to the lines that matter:
internal linkon the first line confirms the peer is in your own AS.BGP state = Establishedmeans the session is up and exchanging updates.- The TTL line shows an outgoing TTL of 255, the iBGP default.
Local hostandForeign hostare the two TCP endpoints. Both should be Loopback0 addresses. A physical interface address here means the session is not using the loopback.- In
show ip bgp summary, a number under State/PfxRcd means the session is up and counts the prefixes from that neighbor: 2 from R1 here, 3 from the eBGP neighbor 10.0.24.2. A state name there means the session is not up.
R2# show ip bgp neighbors 10.255.0.1 | include BGP neighbor is|BGP state|TTL|Local host|Foreign host
BGP neighbor is 10.255.0.1, remote AS 65001, internal link
BGP state = Established, up for 00:01:24
Connection is ECN Disabled, Mininum incoming TTL 0, Outgoing TTL 255
Local host: 10.255.0.2, Local port: 179
Foreign host: 10.255.0.1, Foreign port: 49345
R2# show ip bgp summary
BGP router identifier 10.255.0.2, local AS number 65001
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.0.24.2 4 65003 15 18 14 0 0 00:06:20 3
10.255.0.1 4 65001 9 9 14 0 0 00:01:24 2Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
What a missing update-source looks like
Remove update-source from both routers and the session never forms. Each router opens its connection from Ethernet0/0, 10.0.12.1 or 10.0.12.2, and the other router has no neighbor statement for that address, so it refuses the connection. On R1, show ip bgp summary shows a state name for 10.255.0.2 instead of a prefix count — Idle in the capture below, with 0 messages sent and 0 received — while the eBGP session to R3 is untouched at 3 prefixes. That is the pattern to look for: one failed session on a router whose other sessions are up points at that session's addressing, not at the router.
The OSPF route to the loopback is still there, and a ping between the loopbacks still succeeds, so reachability tests alone will not find this. Check that update-source is present under router bgp on both routers. Other reasons a session sits in Idle or Active are covered in BGP neighbor states.
R1# show ip bgp summary
BGP router identifier 10.255.0.1, local AS number 65001
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.0.13.2 4 65002 13 15 17 0 0 00:04:59 3
10.255.0.2 4 65001 0 0 1 0 0 00:00:28 Idle
R1# show ip bgp neighbors 10.255.0.2 | include BGP state
BGP state = Idle, down for 00:00:28
R1# ping 10.255.0.2 source Loopback0
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 10.255.0.2, timeout is 2 seconds:
Packet sent with a source address of 10.255.0.1
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 msOutput captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
Missing on one side only
With update-source removed from R2 alone, the session still comes up. R2's own attempts, sourced from 10.0.12.2, are refused, but R1 opens the connection from 10.255.0.1, which matches R2's neighbor statement, so R2 accepts it. The result looks healthy: Established, with both TCP endpoints on the loopbacks.
Local port: 179 says the peer opened this connection rather than R2, but Step 3's healthy session shows the same thing, so the port proves nothing on its own. Nothing in show ip bgp neighbors marks the half-configured case — only the configuration on both routers does, and the session can only ever be rebuilt from R1's side.
R2# show ip bgp neighbors 10.255.0.1 | include BGP state|Local host|Foreign host
BGP state = Established, up for 00:00:02
Local host: 10.255.0.2, Local port: 179
Foreign host: 10.255.0.1, Foreign port: 64465Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
Step 4 — See why external next hops break iBGP
When R2 learns 203.0.113.0/24 from R4, the next hop is 10.0.24.2, R4's address on their shared link. When R2 passes that route to an iBGP peer, BGP leaves the next hop alone: RFC 4271 says a speaker should not modify NEXT_HOP on a route it did not originate when sending it to an internal peer, unless it is configured to announce its own address. R1 therefore receives 203.0.113.0/24 with next hop 10.0.24.2.
A BGP path is usable only if its next hop resolves through the routing table. R1 has no route to 10.0.24.2, because that subnet is not in OSPF, so R1 marks the next hop inaccessible and never selects the path. The output below was captured with next-hop-self removed from R2. R2 holds two paths: the one from R4 with next hop 10.0.24.2, best on AS-path length, and the same prefix from R1 the long way round. The next hop on that best path is what R2 passes to R1 unchanged.
R2# show ip bgp 203.0.113.0/24
BGP routing table entry for 203.0.113.0/24, version 6
Paths: (2 available, best #2, table default)
Advertised to update-groups:
5
Refresh Epoch 1
65002 65003
10.255.0.1 (metric 11) from 10.255.0.1 (10.255.0.1)
Origin IGP, metric 0, localpref 100, valid, internal
...
Refresh Epoch 1
65003
10.0.24.2 from 10.0.24.2 (10.255.0.4)
Origin IGP, metric 0, localpref 100, valid, external, best
...Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
What R1 sees
R1 holds two paths to 203.0.113.0/24. The one from 10.255.0.2 carries next hop 10.0.24.2, tagged (inaccessible), and show ip route 10.0.24.2 answers % Subnet not in table. The best path is the other one, through R3, with AS path 65002 65003. Both of R4's prefixes install that way, [20/0] via 10.0.13.2, so traffic for AS 65003 leaves through AS 65002 — a longer path nobody chose. With a single exit there would be no usable path at all and the prefix would be missing from the routing table.
R2's own prefix, 172.16.2.0/24, still installs via 10.255.0.2 at distance 200. The problem applies to the routes R2 learned from outside the AS, not to the ones it originates.
R1# show ip bgp 203.0.113.0/24
BGP routing table entry for 203.0.113.0/24, version 22
Paths: (2 available, best #2, table default)
Advertised to update-groups:
4
Refresh Epoch 1
65003
10.0.24.2 (inaccessible) from 10.255.0.2 (10.255.0.2)
Origin IGP, metric 0, localpref 100, valid, internal
...
Refresh Epoch 1
65002 65003
10.0.13.2 from 10.0.13.2 (10.255.0.3)
Origin IGP, localpref 100, valid, external, best
...
R1# show ip route 10.0.24.2
% Subnet not in table
R1# show ip route bgp | begin Gateway
Gateway of last resort is not set
172.16.0.0/16 is variably subnetted, 3 subnets, 2 masks
B 172.16.2.0/24 [200/0] via 10.255.0.2, 00:05:30
B 192.0.2.0/24 [20/0] via 10.0.13.2, 00:00:56
B 198.51.100.0/24 [20/0] via 10.0.13.2, 00:09:23
B 203.0.113.0/24 [20/0] via 10.0.13.2, 00:00:56Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
Step 5 — Set next-hop-self on both border routers
next-hop-self makes a router put its own address in the next hop of the routes it sends to that neighbor. The address it uses is the session's source, and because of update-source, that is Loopback0. R1 then resolves 203.0.113.0/24 recursively: next hop 10.255.0.2 is reachable through OSPF, and OSPF says to forward to 10.0.12.2 out Ethernet0/0.
Configure it on every router that has external neighbors, toward each iBGP peer. R1 needs it for the routes it learns from R3, just as R2 needs it for R4's. The setting changes only outbound updates, so refresh them with clear ip bgp 10.255.0.1 soft out, which resends the updates without resetting the session.
R2(config)# router bgp 65001
R2(config-router)# neighbor 10.255.0.1 next-hop-self
R2(config-router)# end
R2# clear ip bgp 10.255.0.1 soft out
R1(config)# router bgp 65001
R1(config-router)# neighbor 10.255.0.2 next-hop-selfnext-hop-self toward the iBGP peer on each border router, then a soft outbound refresh.
Verify the next hop and the forwarding path
On R1 the routing table now lists 203.0.113.0/24 as [200/0] via 10.255.0.2, where 200 is the administrative distance of iBGP. In the BGP entry the path from 10.255.0.2 carries next hop 10.255.0.2, resolved through OSPF at (metric 11), and is best again, winning on AS-path length — 65003 against 65002 65003. show ip cef shows the recursion already resolved to 10.0.12.2 on Ethernet0/0, and the traceroute leaves through 10.0.12.2 before reaching R4 at 10.0.24.2.
R1# show ip route bgp | include 203.0.113.0
B 203.0.113.0/24 [200/0] via 10.255.0.2, 00:00:56
R1# show ip bgp 203.0.113.0/24
BGP routing table entry for 203.0.113.0/24, version 26
Paths: (2 available, best #1, table default)
Advertised to update-groups:
1
Refresh Epoch 1
65003
10.255.0.2 (metric 11) from 10.255.0.2 (10.255.0.2)
Origin IGP, metric 0, localpref 100, valid, internal, best
...
Refresh Epoch 1
65002 65003
10.0.13.2 from 10.0.13.2 (10.255.0.3)
Origin IGP, localpref 100, valid, external
...
R1# show ip cef 203.0.113.0/24
203.0.113.0/24
nexthop 10.0.12.2 Ethernet0/0
R1# traceroute 203.0.113.1 source Loopback1
Type escape sequence to abort.
Tracing the route to 203.0.113.1
VRF info: (vrf in name/id, vrf out name/id)
1 10.0.12.2 1 msec 0 msec 0 msec
2 10.0.24.2 1 msec * 1 msecOutput captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
The alternative: advertise the external link into the IGP
The other way to make an external next hop reachable is to route to it. Add the eBGP link subnet to OSPF on the border router and make that interface passive, so the subnet is advertised without OSPF trying to form an adjacency toward the external neighbor. Of the two, next-hop-self is the more common choice.
R2(config)# router ospf 1
R2(config-router)# passive-interface Ethernet0/1
R2(config-router)# network 10.0.24.0 0.0.0.3 area 0R2 advertises the link toward AS 65003 into OSPF without speaking OSPF on it.
| Aspect | next-hop-self | External link in the IGP |
|---|---|---|
| Configured on | Each border router, per iBGP neighbor | The IGP on each border router |
| Next hop iBGP peers receive | The border router's session address (its loopback) | The external neighbor's address, unchanged |
| What the IGP carries | Internal links and loopbacks only | Internal links, loopbacks and every eBGP link subnet |
| New eBGP neighbor on an existing border router | Nothing to add | One more subnet to add to the IGP |
What OSPF shows on R2
The columns to read are Area and Nbrs F/C. Ethernet0/1 is now in area 0 with 0/0 neighbors — a passive interface never sends hellos — while Ethernet0/0 keeps its single adjacency with R1 at 1/1. Ethernet0/1's State column reads WAIT because the capture came seconds after the change, while the DR-election wait timer was still running.
R2# show ip ospf interface brief
Interface PID Area IP Address/Mask Cost State Nbrs F/C
Lo0 1 0 10.255.0.2/32 1 LOOP 0/0
Et0/1 1 0 10.0.24.1/30 10 WAIT 0/0
Et0/0 1 0 10.0.12.2/30 10 DR 1/1Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
What R1 sees with the link in OSPF
This output was captured with the link in OSPF and next-hop-self still removed from R2. The path from 10.255.0.2 still carries next hop 10.0.24.2, but the (inaccessible) tag has been replaced by (metric 20), the cost of the OSPF route that now resolves it, and the path is best.
R1# show ip bgp 203.0.113.0/24
BGP routing table entry for 203.0.113.0/24, version 24
Paths: (2 available, best #1, table default)
Advertised to update-groups:
1
Refresh Epoch 1
65003
10.0.24.2 (metric 20) from 10.255.0.2 (10.255.0.2)
Origin IGP, metric 0, localpref 100, valid, internal, best
...
Refresh Epoch 1
65002 65003
10.0.13.2 from 10.0.13.2 (10.255.0.3)
Origin IGP, localpref 100, valid, external
...
R1# show ip route 10.0.24.2
Routing entry for 10.0.24.0/30
Known via "ospf 1", distance 110, metric 20, type intra area
Last update from 10.0.12.2 on Ethernet0/0, 00:00:42 ago
Routing Descriptor Blocks:
* 10.0.12.2, from 10.255.0.2, 00:00:42 ago, via Ethernet0/0
Route metric is 20, traffic share count is 1Output captured on Cisco IOL (IOS XE 17.16) in Cisco Modeling Labs.
When an iBGP route still will not install
Work through these in order on the router that is missing the route.
- Confirm the session is up with
show ip bgp summary. A state name instead of a prefix count means no routes are arriving; check the neighbor addresses andupdate-sourceon both routers. - Run
show ip bgpwith the prefix. If the prefix is absent, look at the sending router: it may not have the route, or it may be holding it back under the iBGP rule that a route learned from one iBGP peer is not passed to another. - Read the next hop on each path.
(inaccessible)means the routing table has no route to that address. - Run
show ip routefor the next hop. If it is an external address, setnext-hop-selfon the border router that learned the route, or advertise the link into the IGP. If it is a loopback, fix the IGP. - After changing outbound policy, run
clear ip bgpwith the neighbor address andsoft outon the sending router, then check again. - If the path is usable but not best, path attributes are deciding. See BGP best path selection.
Frequently asked questions
Do both iBGP routers need update-source?
Configure it on both. With it on only one side, the session can still come up, because that router opens the connection from its loopback and the other router accepts it, but the second router's own connection attempts are refused. With it missing on both sides, the session never forms.
Does iBGP over loopbacks need ebgp-multihop?
No. The ebgp-multihop command raises the TTL of eBGP packets, which is 1 by default. IOS sends iBGP packets with a TTL of 255, so an iBGP peer can be several hops away as long as the IGP has a route to its loopback.
Why is an iBGP route in show ip bgp but not in the routing table?
The usual cause is an unreachable next hop. A route learned from an eBGP neighbor keeps that neighbor's address as its next hop when it crosses iBGP, and if the IGP has no route to that address, the path is marked inaccessible and never becomes best. Set next-hop-self on the border router, or advertise the external link into the IGP.
Does next-hop-self change anything toward eBGP neighbors?
Rarely. A router normally sets the next hop to its own address when it advertises to an eBGP neighbor. The exception is a shared subnet, where the router can pass on another router's address on that subnet as the next hop. The command exists mainly for iBGP sessions, where the next hop otherwise passes through unchanged.
Do I have to reset the session after adding next-hop-self?
No. The setting changes outbound updates, so a soft outbound refresh is enough. The clear ip bgp command with the neighbor address and the soft out keywords resends the updates without dropping the session.
Labs to practice iBGP
Build iBGP over loopbacks on real IOS, then get the config graded.
This is what grading your config looks like
A sample result — 4 of 5 requirements met. This is exactly what you see the moment you submit.
bgp-lab-export.yaml — read 3 device configs
- Passed: BGP process running as AS 65001 on R1
- Passed: eBGP neighbor 10.0.13.2 in AS 65002
- Passed: Session to 10.0.13.2 is Established
- Passed: 172.16.1.0/24 originated by an exact match
- Failed: next-hop-self toward the iBGP peer — missing on R2
Solution revealed
The full node-by-node answer key unlocks the moment you submit — so you see exactly what you missed.
Don't just read it — configure it
Reading is step one. Build BGP on real Cisco IOS and have your own config graded.