In iBGP, all routers in the same AS must be fully meshed, meaning every router forms an iBGP session with every other router. This is required because iBGP by default does not advertise routes learned from one iBGP peer to another. The full mesh ensures that every router can learn all the routes.
The problem is that in a large network with many iBGP routers, a full mesh quickly becomes unmanageable. The number of sessions grows rapidly, and you could end up with hundreds of iBGP sessions. If you have 10 iBGP routers and try to build a full mesh, you would need 45 sessions. For n routers, the number of sessions is n × (n – 1) / 2. So with 10 routers, that’s 10 × 9 / 2 = 45.
This is where route reflectors come in. A route reflector reduces the need for full mesh by allowing certain routers to reflect routes to others. With this design, you only need a few sessions instead of a full mesh, making the iBGP setup much more scalable. If you have the same 10 routers, with RR, you only need 9 sessions.

As always, if you find this post helpful, press the ‘clap’ button. It means a lot to me and helps me know you enjoy this type of content. If I get enough claps for this series, I’ll make sure to write more on this specific topic.
BGP Route Reflector Simple Example
In this example, we have r1 in AS 100 advertising the prefix 100.10.10.0/24
. Inside AS 200, we have r2, r3, and r4. r2 peers with r3 over iBGP, and r3 peers with r4 over iBGP. These iBGP sessions use the loopback interfaces, and next-hop self is configured.
Within AS 200, OSPF is running to ensure that all routers know how to reach each other’s loopback addresses. Finally, r4 connects to r5 in AS 300 using eBGP.

!! r1 !!
router bgp 100
bgp router-id 10.0.0.1
neighbor 172.16.1.2 remote-as 200
neighbor 172.16.1.2 description r2
!
address-family ipv4
network 100.10.10.0 mask 255.255.255.0
neighbor 172.16.1.2 activate
!! r2 !!
router bgp 200
bgp router-id 10.0.0.2
neighbor 10.0.0.3 remote-as 200
neighbor 10.0.0.3 description r3
neighbor 10.0.0.3 update-source Loopback0
neighbor 172.16.1.1 remote-as 100
neighbor 172.16.1.1 description r1
!
address-family ipv4
neighbor 10.0.0.3 activate
neighbor 10.0.0.3 next-hop-self
neighbor 172.16.1.1 activate
!! r3 !!
router bgp 200
bgp router-id 10.0.0.3
neighbor 10.0.0.2 remote-as 200
neighbor 10.0.0.2 description r2
neighbor 10.0.0.2 update-source Loopback0
neighbor 10.0.0.4 remote-as 200
neighbor 10.0.0.4 description r4
neighbor 10.0.0.4 update-source Loopback0
!
address-family ipv4
bgp scan-time 5
neighbor 10.0.0.2 activate
neighbor 10.0.0.2 next-hop-self
neighbor 10.0.0.4 activate
neighbor 10.0.0.4 next-hop-self
!! r4 !!
router bgp 200
bgp router-id 10.0.0.4
neighbor 10.0.0.3 remote-as 200
neighbor 10.0.0.3 description r3
neighbor 10.0.0.3 update-source Loopback0
neighbor 172.16.1.14 remote-as 300
neighbor 172.16.1.14 description r5
!
address-family ipv4
bgp scan-time 5
neighbor 10.0.0.3 activate
neighbor 10.0.0.3 next-hop-self
neighbor 172.16.1.14 activate
neighbor 172.16.1.14 advertisement-interval 0
When r1 advertises its prefix 100.10.10.0/24
to r2 over eBGP, r2 can send that route to r3 over the iBGP session. However, r3 is not allowed to send that route to r4 because of the iBGP split-horizon rule.
The split-horizon rule in BGP says that routes learned from one iBGP peer cannot be advertised to another iBGP peer. This rule exists to prevent routing loops inside the AS. The downside is that r4 will never receive the prefix unless it has a direct iBGP session with r2. That means in order for every router to learn every prefix, we would need a full mesh of iBGP sessions, which does not scale.
This is where the route reflector comes in. If we make r3 a route reflector, it can take the route it learned from r2 and “reflect” it to r4. In this setup, r2 and r4 become clients of r3. The reflection process bypasses the split-horizon rule, allowing routes to be shared without needing a full mesh. To configure a route reflector, you simply go to the router acting as the reflector and specify which of its iBGP neighbours are clients.
!! r3 !!
router bgp 200
address-family ipv4
neighbor 10.0.0.2 route-reflector-client
neighbor 10.0.0.4 route-reflector-client
Once we make r3 a route reflector (by specifying the route reflector clients) as shown above, we can immediately see the prefix being reflected to r4. Please note we are also making r2 the RR client, so any routes that r4 learns are also reflected to r2.
!! r4 !!
r4#show ip bgp neighbors 10.0.0.3 routes
BGP table version is 4, local router ID is 10.0.0.4
Network Next Hop Metric LocPrf Weight Path
*>i 100.10.10.0/24 10.0.0.2 0 100 0 100 i
Total number of prefixes 1
What’s interesting here is that even though we have next-hop-self configured, the next-hop did not change when r3 reflected the prefix to r4. From r4’s perspective, the next-hop to reach 100.10.10.0/24 is still r2’s loopback IP.
So we made r3 the route reflector by specifying the two RR clients. r2 sends the prefix to r3, and r3 reflects the prefix to its clients r4 and also back to r2, which is interesting.

The route reflector rule says that any prefixes received from an RR client are reflected to RR clients and non-clients (we will look at non-clients in the next example). However, when r2 receives the prefix back from the RR, it sees itself as the originator and discards it.
If we enable debugging on r2 with debug ip bgp updates
, we can clearly see that r2 is receiving the prefix 100.10.10.0/24 from r3. Since r2 recognizes itself as the originator of this prefix, it rejects the update.
!! r2 !!
BGP(0): 10.0.0.3 rcv UPDATE about 100.10.10.0/24 --
DENIED due to: NEXTHOP is our own address; ORIGINATOR is us;

Originator ID
The Originator_ID
is a 4-byte, optional, nontransitive BGP attribute. This attribute carries the Router_ID
of the route's originator in the local AS (r2's loopback 10.10.0.2
in this case) and is added to the Update
message only by the route reflector. If the update comes back to the originator, it should discard the prefix. Here, we can see that the originator ID is set to 10.0.0.2
for the prefix 100.10.10.0/24
(from r4's perspective)
r4#show ip bgp 100.10.10.0/24
BGP routing table entry for 100.10.10.0/24, version 6
Paths: (1 available, best #1, table default)
Advertised to update-groups:
2
Refresh Epoch 1
100
10.0.0.2 (metric 21) from 10.0.0.3 (10.0.0.3)
Origin IGP, metric 0, localpref 100, valid, internal, best
Originator: 10.0.0.2, Cluster list: 10.0.0.3
rx pathid: 0, tx pathid: 0x0
Updated on Sep 14 2025 19:53:34 UTC

If you look for the Originator_ID
on r2 for the same output, you will not see it because it is only set by the RR.
r2#show ip bgp 100.10.10.0/24
BGP routing table entry for 100.10.10.0/24, version 2
Paths: (1 available, best #1, table default)
Advertised to update-groups:
3
Refresh Epoch 1
100
172.16.1.1 from 172.16.1.1 (10.0.0.1)
Origin IGP, metric 0, localpref 100, valid, external, best
rx pathid: 0, tx pathid: 0x0
Updated on Sep 14 2025 09:28:43 UTC
Originator_ID
to this route. If a route already carries the Originator_ID
attribute, the RR does not create a new one. After receiving the route, a BGP speaker checks whether the Originator_ID
is the same as its router ID. If Originator_ID
is the same as its router ID, the BGP speaker discards this route.Route Reflector Advertising Rules
You may also have a situation where a route reflector serves both clients and non-clients. The non-clients are still routers inside the same AS and have iBGP peering with the RR, but they are not configured as RR clients. In this case, the route reflector follows a simple set of rules.
- Routes learned from a client are reflected to other clients and to non-clients.
- Routes learned from a non-client are only sent to clients, not to other non-clients.
- Routes learned from an eBGP peer are advertised to both clients and non-clients.

In this diagram, all the solid lines inside AS 200 represent iBGP sessions.
- r1 is in AS 200 and receives the prefix
100.10.10.0/24
from p1 in AS 100 via eBGP. - r2 is configured as the Route Reflector (RR). Both r1 and r4 are configured as RR clients.
- r3 and r5 are also part of AS 200 but not configured as clients of the RR.
- r3 connects to p2 in AS 300 via eBGP and learns the prefix
200.10.10.0/24
When p1 in AS 100 advertises the prefix 100.10.10.0/24
to r1, r1 passes it to r2 (the route reflector). From there, r2 reflects the prefix to all its clients (r1 and r4, but r1 discards it) and also to the non-clients (r3 and r5). This way, the prefix from p1 is sent across the entire AS 200.
On the other hand, when p2 in AS 300 advertises the prefix 200.10.10.0/24
to r3, r3 sends it to r2. Because r3 is a non-client, r2 will only reflect that prefix to its clients (r1 and r4). It will not reflect it to another non-client, which means r5 does not receive the route from r3. So, for reachability, you will need to have a direct iBGP session between r3 and r5. Here in r5, you can see it doesn't have a route to 200.10.10.0/24
r5#show ip bgp
BGP table version is 10, local router ID is 10.0.0.5
Network Next Hop Metric LocPrf Weight Path
*>i 100.10.10.0/24 10.0.0.1 0 100 0 100 i
Multiple Route Reflectors
Having a single route reflector creates a single point of failure. If that router goes down, all of its clients lose visibility of routes, which can cause major connectivity issues. To avoid this, you can deploy multiple route reflectors in the same AS.

!! r2 !!
router bgp 200
bgp router-id 10.0.0.2
neighbor 10.0.0.4 remote-as 200
neighbor 10.0.0.4 description r4
neighbor 10.0.0.4 update-source Loopback0
neighbor 10.0.0.5 remote-as 200
neighbor 10.0.0.5 description r5
neighbor 10.0.0.5 update-source Loopback0
!
address-family ipv4
neighbor 10.0.0.4 activate
neighbor 10.0.0.4 next-hop-self
neighbor 10.0.0.5 activate
neighbor 10.0.0.5 next-hop-self
!! r4 !!
router bgp 200
bgp router-id 10.0.0.4
bgp cluster-id 10.0.0.4 <<<<<<<< WE WILL COVER THIS NEXT
neighbor 10.0.0.1 remote-as 200
neighbor 10.0.0.1 description r1
neighbor 10.0.0.1 update-source Loopback0
neighbor 10.0.0.2 remote-as 200
neighbor 10.0.0.2 description r2
neighbor 10.0.0.2 update-source Loopback0
neighbor 10.0.0.3 remote-as 200
neighbor 10.0.0.3 description r3
neighbor 10.0.0.3 update-source Loopback0
neighbor 10.0.0.5 remote-as 200
neighbor 10.0.0.5 description r5
neighbor 10.0.0.5 update-source Loopback0
!
address-family ipv4
neighbor 10.0.0.1 activate
neighbor 10.0.0.1 route-reflector-client
neighbor 10.0.0.1 next-hop-self
neighbor 10.0.0.2 activate
neighbor 10.0.0.2 route-reflector-client
neighbor 10.0.0.2 next-hop-self
neighbor 10.0.0.3 activate
neighbor 10.0.0.3 route-reflector-client
neighbor 10.0.0.3 next-hop-self
neighbor 10.0.0.5 activate
neighbor 10.0.0.5 next-hop-self
!! r5 !!
router bgp 200
bgp router-id 10.0.0.5
bgp cluster-id 10.0.0.4 <<<<<<<< WE WILL COVER THIS NEXT
neighbor 10.0.0.1 remote-as 200
neighbor 10.0.0.1 description r1
neighbor 10.0.0.1 update-source Loopback0
neighbor 10.0.0.2 remote-as 200
neighbor 10.0.0.2 description r2
neighbor 10.0.0.2 update-source Loopback0
neighbor 10.0.0.3 remote-as 200
neighbor 10.0.0.3 description r3
neighbor 10.0.0.3 update-source Loopback0
neighbor 10.0.0.4 remote-as 200
neighbor 10.0.0.4 description r4
neighbor 10.0.0.4 update-source Loopback0
!
address-family ipv4
neighbor 10.0.0.1 activate
neighbor 10.0.0.1 route-reflector-client
neighbor 10.0.0.1 next-hop-self
neighbor 10.0.0.2 activate
neighbor 10.0.0.2 route-reflector-client
neighbor 10.0.0.2 next-hop-self
neighbor 10.0.0.3 activate
neighbor 10.0.0.3 route-reflector-client
neighbor 10.0.0.3 next-hop-self
neighbor 10.0.0.4 activate
neighbor 10.0.0.4 next-hop-self
In the diagram above, r4 and r5 are both configured as route reflectors, and r1, r2, and r3 are their clients. Each client peers with both route reflectors, so if one RR fails, the other can still reflect routes.
r4#show ip bgp summary
BGP router identifier 10.0.0.4, local AS number 200
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.0.0.1 4 200 13 14 5 0 0 00:06:08 1
10.0.0.2 4 200 890 901 5 0 0 13:27:48 0
10.0.0.3 4 200 894 897 5 0 0 13:27:47 1
10.0.0.5 4 200 890 894 5 0 0 13:27:47 0
r5#show ip bgp summary
BGP router identifier 10.0.0.5, local AS number 200
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.0.0.1 4 200 12 14 3 0 0 00:07:20 1
10.0.0.2 4 200 12 13 3 0 0 00:07:20 0
10.0.0.3 4 200 12 13 3 0 0 00:07:20 1
10.0.0.4 4 200 13 14 3 0 0 00:07:16 0
r2#show ip bgp summary
BGP router identifier 10.0.0.2, local AS number 200
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.0.0.4 4 200 902 891 6 0 0 13:28:37 2
10.0.0.5 4 200 893 894 6 0 0 13:28:33 2
Route reflectors can also peer with each other, but that brings up an important question - how do they avoid creating loops when the same routes get reflected around?
Cluster ID
The answer is the Cluster-ID. Each route reflector is assigned a cluster ID. When a route reflector reflects a route, it adds its own cluster ID to the Cluster List attribute (optional non-transitive) of that route. If another route reflector later sees its own cluster ID already in the cluster-list, it knows the route has already passed through its cluster and discards it.
The Route Reflector and its clients form a cluster. In an AS, each Route Reflector is uniquely identified by a Cluster ID. Similar to an AS Path, a Cluster List is composed of a series of Cluster IDs and is generated by an RR. The Cluster List records all the RRs through which a route passes. So, if you have two route reflectors with the same cluster ID, they are considered as part of the same cluster. If you assign different cluster IDs to each, they are considered to be in different clusters.
Using the Same Cluster ID
In the previous example, we've set the cluster-id to 10.0.0.4 on both route reflectors, which is r4’s loopback.

When p1 in AS 100 advertises its prefix 100.10.10.0/24, it reaches r1 and then gets passed to both r4 and r5 (the route reflectors). r4, as a route reflector, adds two attributes before reflecting the route further.
- Originator ID - the loopback of r1 (since r1 originally advertised the prefix in this AS).
- Cluster ID - in this case, 10.0.0.4.
r4 then sends this update to r5. But when r5 receives the route, it notices that its own cluster-id (10.0.0.4) is already in the cluster-list attribute. At that point, r5 concludes 'this looks like a loop' and discards the update.
The same process happens in reverse when r5 reflects a route back toward r4. Because each RR sees its own cluster-id in the cluster-list, the route gets dropped, and loops are prevented. If I turn on debugging with debug ip bgp updates
on r4, I should see that it rejects the update from r5 because the cluster-list already contains its own cluster-id 10.0.0.4.
!! r4 !!
BGP(0): 10.0.0.5 rcv UPDATE about 100.10.10.0/24 --
DENIED due to: reflected from the same cluster
Before we move on to the next section, note that r4 only keeps a single copy of the prefixes in its BGP table. It does not keep any prefixes from r5, because the ones sent by r5 are discarded due to the cluster-id check.
r4#show ip bgp
Network Next Hop Metric LocPrf Weight Path
*>i 100.10.10.0/24 10.0.0.1 0 100 0 100 i
*>i 200.10.10.0 10.0.0.3 0 100 0 300 i
r4#show ip bgp neighbors 10.0.0.5 received-routes
Total number of prefixes 0
Using Different Cluster ID
Now, let’s remove the cluster-id we configured on r5 so that it defaults back to its router ID. So now we are in a situation where we have two separate clusters, with one route reflector serving each cluster.
!! r5 !!
router bgp 200
no bgp cluster-id 10.0.0.4
r5#show ip bgp cluster-ids
Global cluster-id: 10.0.0.5 (configured: 0.0.0.0)
BGP client-to-client reflection: Configured Used
all (inter-cluster and intra-cluster): ENABLED
intra-cluster: ENABLED ENABLED
List of cluster-ids:
Cluster-id #-neighbors C2C-rfl-CFG C2C-rfl-USE
With this change, when r5 sends a prefix to r4, r4 will accept it instead of discarding it. The route may not be selected as the best path, but r4 will still process it and store it in the BGP table. If you look at the output, you’ll see that r4 now has two paths for each prefix.
r4#show ip bgp
Network Next Hop Metric LocPrf Weight Path
* i 100.10.10.0/24 10.0.0.1 0 100 0 100 i
*>i 10.0.0.1 0 100 0 100 i
* i 200.10.10.0 10.0.0.3 0 100 0 300 i
*>i 10.0.0.3 0 100 0 300 i
r4#show ip bgp neighbors 10.0.0.5 received-routes
Network Next Hop Metric LocPrf Weight Path
* i 100.10.10.0/24 10.0.0.1 0 100 0 100 i
* i 200.10.10.0 10.0.0.3 0 100 0 300 i
So the end result of using different cluster IDs is that each router now keeps two copies of the same prefix in its BGP table. However, the router will prefer the path that came directly from the RR client (r1 with the router-id of 10.0.0.1), because that path has a shorter cluster-list (none in this case) compared to the one that comes from r4, which already carries a cluster ID in the list.

So keep in mind, if you plan to deploy multiple route reflectors and want them to belong to the same cluster, you need to manually configure the same cluster-id on each of them.
Closing Up
That wraps up our look at route reflectors. We saw what problem it solves, how it works with clients and non-clients, and how attributes like originator ID and cluster ID prevent loops. If you have questions, drop them in the comments, and if you enjoyed the post, don’t forget to subscribe.
References
https://www.youtube.com/watch?v=c8dJPJLlU08&t=249s
https://packetpushers.net/blog/bgp-rr-design-part-1/
https://blog.ipspace.net/2008/08/bgp-route-reflector-details/
https://blog.ipspace.net/2022/02/bgp-rr-cluster-myths/
https://journey2theccie.wordpress.com/2020/07/08/bgp-convergence-and-scalability/