What is an MPLS VPN Route Target?
A Route Target (RT) is a tag attached to a route that decides which VRFs may import it. In an MPLS VPN, the RT is what determines which sites can reach which.
RFC 4364 section 4.3.1 states:
Any route associated with Route Target T must be distributed to every PE router that has a VRF associated with Route Target T.
A PE attaches RTs when it puts a route into MP-BGP (export), and a receiving PE compares them with the RTs configured on its VRFs, importing only the routes that match. A route whose RT does not match never enters the VRF, even though it arrives.
Export and import are separate
RT configuration is split into export on the sending side and import on the receiving side, and the two are independent. Using the same value on both is the normal practice, but nothing requires it.
| Setting | When it applies | Effect |
|---|---|---|
export route-target | When a route is put into MP-BGP | Attaches the RT to the route |
import route-target | When a route is received from MP-BGP | Imports routes carrying a matching RT |
Because they are independent, changing either one has the same result: remove the import on the receiver or change the export on the sender, and in both cases the values no longer match. STEP 1 and STEP 2 of the lab below confirm this symmetry.
A single route can carry several RTs, and a single VRF can import several. Hub-and-spoke and extranet designs are built from these combinations (the design side is covered in MPLS VPN route control with RTs).
RD and RT are different things
The RD and the RT share the same <AS>:<number> notation, which invites confusion, but their roles are entirely different.
| RD | RT | |
|---|---|---|
| What it does | Makes a prefix unique | Decides where the route goes |
| Where it lives | In the NLRI (part of the prefix) | In an extended community (a path attribute) |
| Size | 8 bytes | 8 bytes |
| Relation to a VRF | One per VRF | Several imports and exports per VRF |
RFC 4364 section 4.1 states explicitly that an RD identifies neither the origin of a route nor the set of VPNs it is distributed to. Distribution is decided by the RT alone (see MPLS VPN Route Distinguisher (RD)).
An RT is carried as a BGP extended community. The 8-byte structure and the type values themselves are covered in BGP Extended Communities.
Configuring RTs on IOS XR
On IOS XR the RT is configured on the VRF definition (vrf <name>), unlike the RD, which lives under router bgp.
vrf CUST-A
address-family ipv4 unicast
import route-target
65001:100
!
export route-target
65001:100
!
!
!To use several RTs, list the values under import route-target or export route-target.
vrf CUST-A
address-family ipv4 unicast
export route-target
65001:100
65001:300
!
!
!Lab setup
Eight XRd routers, with customer A and customer B using exactly the same addresses. The effect of an RT shows up as whether routes leak across customers or not, so both customers are needed.
| Node | Role |
|---|---|
| PE1 / PE2 | Hold VRF CUST-A (RD 65001:1, RT 65001:100) and CUST-B (RD 65001:2, RT 65001:200). Each customer gets its own interface towards the CE, and both carry the same 172.16.1.1 (172.16.2.1 on PE2) |
| P1 / P2 | Core only (OSPF area 0 + LDP). They run no BGP |
| CE-A1 / CE-B1 | Site 1. Both use LAN 10.1.1.0/24 and 172.16.1.2 towards the PE |
| CE-A2 / CE-B2 | Site 2. Both use LAN 10.1.2.0/24 and 172.16.2.2 towards the PE |
The RDs never change throughout the test. Only the RTs move. PE-CE runs static routes, redistributed into the VRF’s BGP with redistribute static.
| STEP | Change | What it shows |
|---|---|---|
| 0 | Initial state | The routes carry RT 65001:100. Both customers have reachability |
| 1 | Remove import route-target from CUST-A on PE2 | The route arrives but does not enter the VRF. Customer A loses reachability |
| 2 | Restore the import, change CUST-A’s export on PE1 to 65001:199 | Still not imported. Changing the sending side gives the same result |
| 3 | Restore the export and add a second RT, 65001:300 | One route now carries two RTs. Reachability is unchanged |
| 4 | Make CUST-B on PE2 import 65001:300 as well | Customer B imports customer A’s routes |
| 5 | Return to the STEP 0 configuration | The leak stops |
Only routes whose RT matches enter the VRF (STEP 0-2)
At STEP 0, PE2 imports the 10.1.1.0/24 it received from PE1 into CUST-A.
RP/0/RP0/CPU0:PE2#show bgp vpnv4 unicast rd 65001:1 10.1.1.0/24
Mon Sep 21 09:11:04.781 UTC
BGP routing table entry for 10.1.1.0/24, Route Distinguisher: 65001:1
Versions:
Process bRIB/RIB SendTblVer
Speaker 19 19
Last Modified: Sep 21 09:03:19.023 for 00:07:45
Paths: (1 available, best #1)
Not advertised to any peer
Path #1: Received by speaker 0
Not advertised to any peer
Local, (received & used)
1.1.1.1 (metric 4) from 1.1.1.1 (1.1.1.1)
Received Label 24005
Origin incomplete, metric 0, localpref 100, valid, internal, best, group-best, import-candidate, imported
Received Path ID 0, Local Path ID 1, version 19
Extended community: RT:65001:100
Source AFI: VPNv4 Unicast, Source VRF: CUST-A, Source Route Distinguisher: 65001:1Extended community: RT:65001:100 is the RT carried on the route. (received & used) and imported mean it was taken in and is in use.
Give the prefix as rd <RD> <prefix>. show bgp vpnv4 unicast 10.1.1.0/24 cannot identify a VPN-IPv4 address and returns %% Network not in table.
STEP 1 removes import route-target from CUST-A on PE2, and the same command now reports:
Paths: (1 available, no best path)
Not advertised to any peer
Path #1: Received by speaker 0
Not advertised to any peer
Local, (received-only)
1.1.1.1 (metric 4) from 1.1.1.1 (1.1.1.1)
Received Label 24005
Origin incomplete, metric 0, localpref 100, valid, internal, import-candidate, imported, not-in-vrf
Received Path ID 0, Local Path ID 0, version 0
Extended community: RT:65001:100
Source AFI: VPNv4 Unicast, Source VRF: CUST-A, Source Route Distinguisher: 65001:1The route itself still arrives. The label and the RT are unchanged and it is still valid. What changed is (received-only), not-in-vrf and no best path — the three markers that say it did not enter the VRF.
The received-routes listing says the same thing. Only the CUST-A line (RD 65001:1) is * i, valid but not best, while the CUST-B line (RD 65001:2) is still *>i.
Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 65001:1 (default for vrf CUST-A)
Route Distinguisher Version: 20
* i10.1.1.0/24 1.1.1.1 0 100 0 ?
Route Distinguisher: 65001:2 (default for vrf CUST-B)
Route Distinguisher Version: 17
*>i10.1.1.0/24 1.1.1.1 0 100 0 ?
Processed 2 prefixes, 2 pathsA route that is not in the VRF cannot forward. Customer A loses reachability; customer B is untouched.
RP/0/RP0/CPU0:CE-A2#ping 10.1.1.1 source 10.1.2.1 count 50 timeout 1
Mon Sep 21 09:19:03.753 UTC
Type escape sequence to abort.
Sending 50, 100-byte ICMP Echos to 10.1.1.1 timeout is 1 seconds:
..................................................
Success rate is 0 percent (0/50)STEP 2 restores the import and instead changes CUST-A’s export on PE1 to 65001:199. Only the sending side changed, and the result is the same.
Paths: (1 available, no best path)
Not advertised to any peer
Path #1: Received by speaker 0
Not advertised to any peer
Local, (received-only)
1.1.1.1 (metric 4) from 1.1.1.1 (1.1.1.1)
Received Label 24005
Origin incomplete, metric 0, localpref 100, valid, internal, import-candidate, not-in-vrf
Received Path ID 0, Local Path ID 0, version 0
Extended community: RT:65001:199 The RT is now 65001:199 and no longer matches PE2’s import (65001:100). The packet carries the same value. The UPDATE PE1 re-sent right after changing the export is No.9 in the attached STEP 2 capture.
Path Attribute - EXTENDED_COMMUNITIES
Flags: 0xc0, Optional, Transitive, Complete
1... .... = Optional: Set
.1.. .... = Transitive: Set
..0. .... = Partial: Not set
...0 .... = Extended-Length: Not set
.... 0000 = Unused: 0x0
Type Code: EXTENDED_COMMUNITIES (16)
Length: 8
Carried extended communities: (1 community)
Route Target: 65001:199 [Transitive 2-Octet AS-Specific]
Type: Transitive 2-Octet AS-Specific (0x00)
0... .... = IANA Authority: Allocated on First Come First Serve Basis
.0.. .... = Transitive across ASes: Transitive
Subtype (AS2): Route Target (0x02)
2-Octet AS: 65001
4-Octet AN: 199One route can carry several RTs (STEP 3)
STEP 3 puts the export back to 65001:100 and adds a second RT, 65001:300.
Paths: (1 available, best #1)
Not advertised to any peer
Path #1: Received by speaker 0
Not advertised to any peer
Local, (received & used)
1.1.1.1 (metric 4) from 1.1.1.1 (1.1.1.1)
Received Label 24005
Origin incomplete, metric 0, localpref 100, valid, internal, best, group-best, import-candidate, imported
Received Path ID 0, Local Path ID 1, version 24
Extended community: RT:65001:100 RT:65001:300
Source AFI: VPNv4 Unicast, Source VRF: CUST-A, Source Route Distinguisher: 65001:1Two RTs now sit side by side. 65001:100 is still there, so the import into CUST-A is unaffected, and CE-A2 still has 100 percent reachability.
Each extended community is 8 bytes, and they are listed inside the attribute. No.4 in the attached STEP 3 capture is the UPDATE PE1 re-sent at this point.
Path Attribute - EXTENDED_COMMUNITIES
Flags: 0xc0, Optional, Transitive, Complete
1... .... = Optional: Set
.1.. .... = Transitive: Set
..0. .... = Partial: Not set
...0 .... = Extended-Length: Not set
.... 0000 = Unused: 0x0
Type Code: EXTENDED_COMMUNITIES (16)
Length: 16
Carried extended communities: (2 communities)
Route Target: 65001:100 [Transitive 2-Octet AS-Specific]
Type: Transitive 2-Octet AS-Specific (0x00)
0... .... = IANA Authority: Allocated on First Come First Serve Basis
.0.. .... = Transitive across ASes: Transitive
Subtype (AS2): Route Target (0x02)
2-Octet AS: 65001
4-Octet AN: 100
Route Target: 65001:300 [Transitive 2-Octet AS-Specific]
Type: Transitive 2-Octet AS-Specific (0x00)
0... .... = IANA Authority: Allocated on First Come First Serve Basis
.0.. .... = Transitive across ASes: Transitive
Subtype (AS2): Route Target (0x02)
2-Octet AS: 65001
4-Octet AN: 300Length went from 8 to 16: adding one RT grows the attribute by exactly 8 bytes.
Adding an RT puts the route into another customer’s VRF (STEP 4-5)
STEP 4 adds an import of 65001:300 to CUST-B on PE2, and customer A’s route enters customer B’s VRF.
Because both customers use the same 10.1.1.0/24 here, show route vrf CUST-B cannot tell them apart. The leak shows up in the number of paths in the BGP table.
Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 65001:2 (default for vrf CUST-B)
Route Distinguisher Version: 17
*>i10.1.1.0/24 1.1.1.1 0 100 0 ?
*> 10.1.2.0/24 172.16.2.2 0 32768 ?
Processed 2 prefixes, 2 paths Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 65001:2 (default for vrf CUST-B)
Route Distinguisher Version: 25
*>i10.1.1.0/24 1.1.1.1 0 100 0 ?
* i 1.1.1.1 0 100 0 ?
*> 10.1.2.0/24 172.16.2.2 0 32768 ?
Processed 2 prefixes, 3 paths Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 65001:2 (default for vrf CUST-B)
Route Distinguisher Version: 27
*>i10.1.1.0/24 1.1.1.1 0 100 0 ?
*> 10.1.2.0/24 172.16.2.2 0 32768 ?
Processed 2 prefixes, 2 pathsOnly at STEP 4 does 10.1.1.0/24 gain a second line — the * i with an empty Network column — and the count reads Processed 2 prefixes, 3 paths. That extra path is customer A’s route, imported through RT 65001:300. CUST-B’s import list holds two RTs at STEP 4 only.
Import VPN route-target communities:
RT:65001:200
RT:65001:300STEP 5 removes that import, the count returns to two paths and the leak stops. Whether a route crosses between customers is decided by the RTs alone. The RDs stayed at 65001:1 and 65001:2 from beginning to end.
References
| Standard | Title | What this article used |
|---|---|---|
| RFC 4364 | BGP/MPLS IP Virtual Private Networks (VPNs) | 4.1 (an RD does not indicate distribution), 4.3 (VRF import / export), 4.3.1 (routes go to PEs whose RTs match) |
| RFC 4360 | BGP Extended Communities Attribute | Carried as an extended community (Type 16) |
Books: Luc De Ghein, MPLS Fundamentals (Cisco Press, 2006), Chapter 7; Mobeen Tahir et al., Cisco IOS XR Fundamentals (Cisco Press, 2009), Chapter 9
Test environment: Cisco IOS XRd 26.1.1 (Cisco Modeling Labs)
Configurations and show output
Five kinds of file were captured from all eight routers at every STEP, one file per router. The configurations under test are these ..._run.txt files (the final state is the one from the last STEP).
| File | Contents |
|---|---|
..._show.txt | show version, show vrf all detail, show bgp vpnv4 unicast, show bgp vpnv4 unicast rd <RD> <prefix>, the three-command set (advertised-routes / routes / received routes), show route vrf, show cef vrf, show mpls forwarding and others |
..._log.txt | show logging narrowed to that STEP. A marker is written with logmsg at the start of each STEP and its timestamp passed to show logging start |
..._run.txt | show running-config at that STEP (the configuration under test) |
..._ping.txt | The ping and traceroute results for that STEP |
..._commit.cfg | Only the configuration committed in that STEP, for the routers that were changed |
The final state (STEP 5) is back to the same configuration as STEP 0.
STEP 0: Initial state
| Router | show | syslog | running-config | ping | committed config |
|---|---|---|---|---|---|
| PE1 | show | log | run | ping | - |
| PE2 | show | log | run | ping | - |
| P1 | show | log | run | ping | - |
| P2 | show | log | run | ping | - |
| CE-A1 | show | log | run | ping | - |
| CE-A2 | show | log | run | ping | - |
| CE-B1 | show | log | run | ping | - |
| CE-B2 | show | log | run | ping | - |
STEP 1: Remove import route-target from CUST-A on PE2
| Router | show | syslog | running-config | ping | committed config |
|---|---|---|---|---|---|
| PE1 | show | log | run | ping | - |
| PE2 | show | log | run | ping | commit |
| P1 | show | log | run | ping | - |
| P2 | show | log | run | ping | - |
| CE-A1 | show | log | run | ping | - |
| CE-A2 | show | log | run | ping | - |
| CE-B1 | show | log | run | ping | - |
| CE-B2 | show | log | run | ping | - |
STEP 2: Restore the import, change CUST-A’s export on PE1 to 65001:199
| Router | show | syslog | running-config | ping | committed config |
|---|---|---|---|---|---|
| PE1 | show | log | run | ping | commit |
| PE2 | show | log | run | ping | commit |
| P1 | show | log | run | ping | - |
| P2 | show | log | run | ping | - |
| CE-A1 | show | log | run | ping | - |
| CE-A2 | show | log | run | ping | - |
| CE-B1 | show | log | run | ping | - |
| CE-B2 | show | log | run | ping | - |
STEP 3: Restore the export and add a second RT, 65001:300
| Router | show | syslog | running-config | ping | committed config |
|---|---|---|---|---|---|
| PE1 | show | log | run | ping | commit |
| PE2 | show | log | run | ping | - |
| P1 | show | log | run | ping | - |
| P2 | show | log | run | ping | - |
| CE-A1 | show | log | run | ping | - |
| CE-A2 | show | log | run | ping | - |
| CE-B1 | show | log | run | ping | - |
| CE-B2 | show | log | run | ping | - |
STEP 4: Make CUST-B on PE2 import 65001:300 as well
| Router | show | syslog | running-config | ping | committed config |
|---|---|---|---|---|---|
| PE1 | show | log | run | ping | - |
| PE2 | show | log | run | ping | commit |
| P1 | show | log | run | ping | - |
| P2 | show | log | run | ping | - |
| CE-A1 | show | log | run | ping | - |
| CE-A2 | show | log | run | ping | - |
| CE-B1 | show | log | run | ping | - |
| CE-B2 | show | log | run | ping | - |
STEP 5: Return to the STEP 0 configuration (final state)
| Router | show | syslog | running-config | ping | committed config |
|---|---|---|---|---|---|
| PE1 | show | log | run | ping | commit |
| PE2 | show | log | run | ping | commit |
| P1 | show | log | run | ping | - |
| P2 | show | log | run | ping | - |
| CE-A1 | show | log | run | ping | - |
| CE-A2 | show | log | run | ping | - |
| CE-B1 | show | log | run | ping | - |
| CE-B2 | show | log | run | ping | - |
| Packet captures were taken per STEP. |
| STEP | PE1-P1 |
|---|---|
| 0 | pcap |
| 1 | pcap |
| 2 | pcap |
| 3 | pcap |
| 4 | pcap |
| 5 | pcap |