BGP – Inter-AS Option C
1. Intro
BGP Option C is the most scalable Inter-AS MPLS L3VPN model. Unlike Options A and B, the PE routers exchange VPN routes directly, while the ASBRs only provide MPLS transport between the autonomous systems.
Find next our test topology for this post:

Our aim is to have end to end connectivity for Cust-A VRF, e.g. ping from 192.45.6.1 prefix all the way to R7 192.45.6.7.
2. RR MP-BGP to the other ISP
Between the IPS Route Reflectors (RR2 to RR8) we we will have an eBGP MP-BGP session:
- only the inet-vpn address family (this is all we need with the other ISP RR).
- this is an external session
- the peer is multiple hops away, so we need ‘multihop‘
- the philosophy is to keep the original next hops, so we also need ‘no-nexthop-change’
### BGP MP-BGP to the other ISP:
set protocols bgp group Option-C type external
set protocols bgp group Option-C multihop no-nexthop-change
set protocols bgp group Option-C local-address 17.0.0.2
set protocols bgp group Option-C family inet-vpn unicast
set protocols bgp group Option-C peer-as 200
set protocols bgp group Option-C neighbor 17.0.0.8
2. BGP LU
We need to activate BGP-LU an PE, RR, ASBR:
set protocols bgp group iBGP family inet labeled-unicast rib inet.3
It is the common practice and recommended to add the BGP-LU to the inet.3 table.
Theoretically, we can make the Option C working if we add the BGP-LU prefixes to the default inet.0 table. But it can because confusing to have both unicast and labeled-unicast prefixes in the same inet.0 table. In fact, JunOS will not even let you to activate both inet and labeled unicast to the same BGP neighbor:
set protocols bgp group iBGP family inet labeled-unicast
set protocols bgp group iBGP family inet unicast
root@R1# commit check
[edit protocols]
'bgp'
Error in neighbor 17.0.0.2 of group iBGP:
peer cannot have both inet unicast and inet labeled-unicast nlri
error: configuration check-out failed
So, the config is as follows:
### PE config:
root@R1# show protocols bgp | display set
set protocols bgp group iBGP type internal
set protocols bgp group iBGP local-address 17.0.0.1
set protocols bgp group iBGP family inet labeled-unicast rib inet.3
set protocols bgp group iBGP family inet unicast
set protocols bgp group iBGP family inet-vpn unicast
set protocols bgp group iBGP neighbor 17.0.0.2
### RR config:
root@R2# show protocols bgp group iBGP | display set
set protocols bgp group iBGP type internal
set protocols bgp group iBGP local-address 17.0.0.2
set protocols bgp group iBGP family inet labeled-unicast rib inet.3
set protocols bgp group iBGP family inet unicast
set protocols bgp group iBGP family inet-vpn unicast
set protocols bgp group iBGP cluster 17.0.0.2
set protocols bgp group iBGP neighbor 17.0.0.1
set protocols bgp group iBGP neighbor 17.0.0.4
### ASBR config:
root@R4# show protocols bgp group iBGP | display set
set protocols bgp group iBGP type internal
set protocols bgp group iBGP local-address 17.0.0.4
set protocols bgp group iBGP family inet labeled-unicast rib inet.3
set protocols bgp group iBGP family inet unicast
set protocols bgp group iBGP neighbor 17.0.0.2
3. Configure the ASBR with BGP-LU
We must be sure to capture the Loopbacks (/32 prefixes from subnet 17.0.0.0/24) and advertise them to the peer ISP:
### R4 configuration:
root@R4# show | display set | match "Option-C|BGP-LU-Export"
set policy-options policy-statement BGP-LU-Export term Loopbakcs from route-filter 17.0.0.0/24 prefix-length-range /32-/32
set policy-options policy-statement BGP-LU-Export term Loopbakcs then accept
set policy-options policy-statement BGP-LU-Export term DENY then reject
set protocols bgp group Option-C type external
set protocols bgp group Option-C family inet labeled-unicast rib inet.3
set protocols bgp group Option-C export BGP-LU-Export
set protocols bgp group Option-C peer-as 200
set protocols bgp group Option-C neighbor 17.8.3.2
### At this point we are exchanging prefixes for PEs and RRs:
root@R4# run show route advertising-protocol bgp 17.8.3.2
inet.3: 8 destinations, 8 routes (8 active, 0 holddown, 0 hidden)
Prefix Nexthop MED Lclpref AS path
* 17.0.0.1/32 Self 2000 I
* 17.0.0.2/32 Self 2000 I
* 17.0.0.3/32 Self 1000 I
* 17.0.0.4/32 Self I
root@R4# run show route receive-protocol bgp 17.8.3.2
inet.0: 26 destinations, 26 routes (26 active, 0 holddown, 0 hidden)
inet.3: 8 destinations, 8 routes (8 active, 0 holddown, 0 hidden)
Prefix Nexthop MED Lclpref AS path
* 17.0.0.5/32 17.8.3.2 200 I
* 17.0.0.6/32 17.8.3.2 1000 200 I
* 17.0.0.7/32 17.8.3.2 2000 200 I
* 17.0.0.8/32 17.8.3.2 2000 200 I
As we can see, we are exchanging PE loopbacks (17.0.0.1 and 17.0.0.7) and RRs loopbacks (17.0.0.2 and 17.0.0.8).
4. Back to RR
If we get back to the RR, we notice that the BGP sessions is still down:
### The BGP sessions between RRs is down:
root@R2# run show bgp summary
[...]
Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped...
17.0.0.1 100 60 80 0 1 24:51 Establ
bgp.l3vpn.0: 1/1/1/0
inet.0: 0/0/0/0
inet.3: 0/0/0/0
17.0.0.4 100 2 3 0 2 0 Establ
inet.0: 0/0/0/0
inet.3: 0/0/0/0
17.0.0.8 200 0 0 0 2 2:33 Active
### But we are receiving the RR8 loopback:
root@R2# run show route 17.0.0.8
inet.3: 7 destinations, 7 routes (7 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
17.0.0.8/32 *[BGP/170] 00:02:53, MED 2000, localpref 100, from 17.0.0.4
AS path: 200 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0, Push 300736, Push 299792(top)
This is a problem, RR8 loopback only appears in inet.3. For the TCP session to establish on the BGP port 179 we need the prefix also in inet.0.
### Configure a RIB Group to copy prefixes from inet.3 to inet.0:
set routing-options rib-groups RIB-GLOBAL import-rib inet.3
set routing-options rib-groups RIB-GLOBAL import-rib inet.0
set routing-options rib-groups RIB-GLOBAL import-policy PS-LU-GLOBAL
set policy-options policy-statement PS-LU-GLOBAL term 1 from route-filter 17.0.0.0/24 prefix-length-range /32-/32
set policy-options policy-statement PS-LU-GLOBAL term 1 then accept
set policy-options policy-statement PS-LU-GLOBAL term DENY then reject
set protocols bgp group iBGP family inet labeled-unicast rib-group RIB-GLOBAL
### After we commit we can see the prefix also in inet.0:
root@R2# run show route 17.0.0.8
inet.0: 30 destinations, 30 routes (30 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
17.0.0.8/32 *[BGP/170] 00:00:05, MED 2000, localpref 100, from 17.0.0.4
AS path: 200 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0, Push 300736, Push 299792(top)
inet.3: 7 destinations, 7 routes (7 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
17.0.0.8/32 *[BGP/170] 00:06:47, MED 2000, localpref 100, from 17.0.0.4
AS path: 200 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0, Push 300736, Push 299792(top)
### And the BGP session is now UP:
root@R2# run show bgp summary
[...]
Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped...
17.0.0.1 100 76 103 0 1 31:59 Establ
bgp.l3vpn.0: 1/1/1/0
inet.0: 0/0/0/0
inet.3: 0/0/0/0
17.0.0.4 100 22 18 0 2 7:08 Establ
inet.0: 4/4/4/0
inet.3: 4/4/4/0
17.0.0.8 200 5 3 0 2 19 Establ
bgp.l3vpn.0: 1/1/1/0
### At this point we are exchanging VPN prefixes:
root@R2# run show route receive-protocol bgp 17.0.0.8
[...]
bgp.l3vpn.0: 3 destinations, 3 routes (3 active, 0 holddown, 0 hidden)
Prefix Nexthop MED Lclpref AS path
64512:1:192.45.6.7/32
* 17.0.0.7 200 I
root@R2# run show route advertising-protocol bgp 17.0.0.8
bgp.l3vpn.0: 3 destinations, 3 routes (3 active, 0 holddown, 0 hidden)
Prefix Nexthop MED Lclpref AS path
64512:1:192.45.6.1/32
* 17.0.0.1 I
5. Final checks
Now the everything is in place and working:
root@R1# run show route table Cust-A.inet 192/8
Cust-A.inet.0: 2 destinations, 2 routes (2 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.45.6.1/32 *[Direct/0] 2d 04:38:03
> via lo0.456
192.45.6.7/32 *[BGP/170] 00:04:06, localpref 100, from 17.0.0.2
AS path: 200 I, validation-state: unverified
> to 17.8.1.2 via ge-0/0/2.0, Push 16, Push 300720, Push 299792(top)
### We can see the prefix next hop:
root@R1# run show route table Cust-A.inet 192.45.6.7/32 detail
Cust-A.inet.0: 2 destinations, 2 routes (2 active, 0 holddown, 0 hidden)
192.45.6.7/32 (1 entry, 1 announced)
*BGP Preference: 170/-101
Route Distinguisher: 64512:1
Next hop type: Indirect, Next hop index: 0
Address: 0x7bbf0d4
Next-hop reference count: 3, key opaque handle: 0x0, non-key opaque handle: 0x0
Kernel Table Id: 0
Source: 17.0.0.2
Next hop type: Router, Next hop index: 676
Next hop: 17.8.1.2 via ge-0/0/2.0, selected
Label operation: Push 16, Push 300720, Push 299792(top)
Label TTL action: prop-ttl, prop-ttl, prop-ttl(top)
Load balance label: Label 16: None; Label 300720: None; Label 299792: None;
Label element ptr: 0x9f48f78
Label parent element ptr: 0x9f4a3c8
Label element references: 1
Label element child references: 0
Label element lsp id: 0
Session Id: 140
Protocol next hop: 17.0.0.7
Label operation: Push 16
Label TTL action: prop-ttl
Load balance label: Label 16: None;
Indirect next hop: 0x791e080 1048575 INH Session ID: 334
State: <Secondary Active Int Ext ProtectionCand>
Local AS: 100 Peer AS: 100
Age: 5:03 Metric2: 2000
Validation State: unverified
Task: BGP_100.17.0.0.2
Announcement bits (1): 0-KRT
AS path: 200 I
Communities: target:64512:456
Import Accepted
VPN Label: 16
Localpref: 100
Router ID: 17.0.0.2
Primary Routing Table: bgp.l3vpn.0
Thread: junos-main
### Ping now works:
root@R1# run ping routing-instance Cust-A 192.45.6.7
PING 192.45.6.7 (192.45.6.7): 56 data bytes
64 bytes from 192.45.6.7: icmp_seq=0 ttl=60 time=8.315 ms
64 bytes from 192.45.6.7: icmp_seq=1 ttl=60 time=15.488 ms
64 bytes from 192.45.6.7: icmp_seq=2 ttl=60 time=6.191 ms
^C
--- 192.45.6.7 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 6.191/9.998/15.488/3.978 ms
Note: In this post we are assuming both ISP agreed to use the same Route Targes for the Cust-A VPN, hence there is no need to tweak this on the RR.
External Resources: