Controlling routes with RTs in MPLS VPN
An RT decides which VRF a route goes into (Route Target (RT) in MPLS VPN). Without touching the VRFs or the RDs, the RTs alone decide which sites can talk to which.
RFC 4364 section 4.3.1 starts by naming the two kinds.
There is a set of Route Targets that a PE router attaches to a route received from site S; these may be called the “Export Targets”. And there is a set of Route Targets that a PE router uses to determine whether a route received from another PE router could be placed in the VRF associated with site S; these may be called the “Import Targets”. The two sets are distinct, and need not be the same.
Export and import are separate sets, and they need not match. The condition for a route to enter a VRF is this.
Note that a particular VPN-IPv4 route is only eligible for installation in a particular VRF if there is some Route Target that is both one of the route’s Route Targets and one of the VRF’s Import Targets.
One of the RTs on the route has to be one of the import targets of the VRF. Everything that follows comes out of that single line.
One RT for everyone gives a full mesh
Section 4.3.5 shows two ways of building a VPN out of this attribute. The first is the one where every site can reach every other.
Suppose it is desired to create a fully meshed closed user group, i.e., a set of sites where each can send traffic directly to the other, but traffic cannot be sent to or received from other sites. Then each site is associated with a VRF, a single Route Target attribute is chosen, that Route Target is assigned to each VRF as both the Import Target and the Export Target, and that Route Target is not assigned to any other VRFs as either the Import Target or the Export Target.
Pick one RT and put it on the export and the import of every VRF. That is the simplest arrangement, and the default shape of an MPLS VPN.
Making them asymmetric cuts the sites off from each other
The second uses two RTs to build a design that goes through a central site.
Alternatively, suppose one desired, for whatever reason, to create a “hub and spoke” kind of VPN. This could be done by the use of two Route Target values, one meaning “Hub” and one meaning “Spoke”. At the VRFs attached to the hub sites, “Hub” is the Export Target and “Spoke” is the Import Target. At the VRFs attached to the spoke site, “Hub” is the Import Target and “Spoke” is the Export Target.
As a table:
| VRF | export | import |
|---|---|---|
| Central site (hub) | Hub | Spoke |
| Branch (spoke) | Spoke | Hub |
A route from a spoke carries Spoke. No other spoke imports Spoke, so the spokes never receive each other’s routes. The hub does import Spoke, so the hub and each spoke can exchange routes.
What this stops is direct traffic between spokes. Carrying traffic between spokes through the hub needs something more: the hub CE has to re-advertise the routes (covered in hub and spoke in MPLS VPN).
An extranet is the same mechanism
Exchanging RTs with the VRF of another customer shares part of one VPN with the other. That is an extranet. The same holds between two VRFs on one PE, as section 4.3.6 spells out.
the decision to distribute a particular route from one VRF to another within a single PE is the same decision that would be made if the VRFs were on different PEs. That is, it depends on the Route Target attribute that is assigned to the route … and the import target of the second VRF.
Just adding the RT brings in every route of the other VRF. To share only part of it, filter by prefix on import. In IOS XR that is import route-policy.
prefix-set B-PRIVATE
10.2.8.1/32
end-set
!
route-policy EXTRANET-IN
if destination in B-PRIVATE then
drop
else
pass
endif
end-policy
!
vrf CUST-A
address-family ipv4 unicast
import route-target
65001:200
!
import route-policy EXTRANET-INThe policy applies to every route being imported. Writing it as “pass only the shared prefix” would drop the routes of your own VPN as well, so the policy drops what should not come in and passes the rest.
The lab
Customer A has a hub (CE-HUB) and two spokes (CE-SP1 and CE-SP2); customer B is a separate VRF. The two spokes are on different PEs. Side by side in one VRF on one PE they could reach each other whatever the RTs say, and the isolation would not be visible. eBGP runs between PE and CE, with a different AS for each CE.
| STEP | Change | What it shows |
|---|---|---|
| 0 | Initial state (every VRF on 65001:100) | Full mesh. Spoke 1 can ping spoke 2 |
| 1 | Asymmetric RTs (hub export 65001:1000 / import 65001:1001, spokes the other way) | The hub is reachable, the spokes are not. The other spoke disappears from the BGP table |
| 2 | Add import 65001:1001 to the VRF of spoke 1 only | The route is there but the ping fails: import is set on the receiving side, so there is no return path |
| 3 | Undo STEP 2 | Back to the state of STEP 1 |
| 4 | Extranet (the hub imports 65001:200 with an import route-policy; CUST-B imports the hub) | Only the shared prefix of customer B gets through. 10.2.8.1/32 never arrives, and the spokes cannot reach customer B |
| 5 | Undo STEP 4 (final state) | Back to the previous state |
One RT for everyone gives a full mesh
In the initial state every VRF has 65001:100 as both its export and its import target.
VRF CUST-A; RD 65001:1; VPN ID not set
VRF mode: Regular
Description not set
Interfaces:
GigabitEthernet0/0/0/0
Address family IPV4 Unicast
Import VPN route-target communities:
RT:65001:100
Export VPN route-target communities:
RT:65001:100
No import route policy
No export route policyThe BGP table of spoke 1 holds both the hub (10.1.1.1/32) and the other spoke (10.1.3.1/32).
RP/0/RP0/CPU0:CE-SP1#show bgp
Mon Oct 12 23:50:55.966 UTC
BGP router identifier 12.12.12.12, local AS number 65102
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0xe0000000 RD version: 8
BGP main routing table version 8
BGP NSR Initial initsync version 3 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs
Status codes: s suppressed, d damped, h history, * valid, > best
i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 10.1.1.1/32 172.16.2.1 0 65001 65101 i
*> 10.1.2.1/32 0.0.0.0 0 32768 i
*> 10.1.3.1/32 172.16.2.1 0 65001 65103 i
*> 172.16.1.0/24 172.16.2.1 0 65001 ?
*> 172.16.2.0/24 172.16.2.1 0 0 65001 ?
*> 172.16.3.0/24 172.16.2.1 0 65001 ?
Processed 6 prefixes, 6 pathsSpoke 1 can ping spoke 2.
RP/0/RP0/CPU0:CE-SP1#ping 10.1.3.1 source 10.1.2.1 count 10 timeout 1
Mon Oct 12 23:47:46.834 UTC
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 10.1.3.1 timeout is 1 seconds:
!!!!!!!!!!
Success rate is 100 percent (10/10), round-trip min/avg/max = 12/14/22 msAsymmetric RTs cut the spokes off from each other
The VRF of the hub exports 65001:1000 and imports 65001:1001; the spokes do the opposite.
vrf CUST-A
address-family ipv4 unicast
import route-target
no 65001:100
65001:1001
!
export route-target
no 65001:100
65001:1000
!
!
!
endvrf CUST-A
address-family ipv4 unicast
import route-target
no 65001:100
65001:1000
!
export route-target
no 65001:100
65001:1001
!
!
!
endThe RT carried in the VPNv4 UPDATE changes with it: a route from the hub now carries 65001:1000. This is No.9 of the attached STEP 1 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:1000 [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: 1000The other spoke is gone from the BGP table of spoke 1. The hub is still there.
RP/0/RP0/CPU0:CE-SP1#show bgp
Mon Oct 12 23:58:18.400 UTC
BGP router identifier 12.12.12.12, local AS number 65102
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0xe0000000 RD version: 14
BGP main routing table version 14
BGP NSR Initial initsync version 3 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs
Status codes: s suppressed, d damped, h history, * valid, > best
i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 10.1.1.1/32 172.16.2.1 0 65001 65101 i
*> 10.1.2.1/32 0.0.0.0 0 32768 i
*> 172.16.1.0/24 172.16.2.1 0 65001 ?
*> 172.16.2.0/24 172.16.2.1 0 0 65001 ?
Processed 4 prefixes, 4 pathsAnd the ping fails.
RP/0/RP0/CPU0:CE-SP1#ping 10.1.3.1 source 10.1.2.1 count 10 timeout 1
Mon Oct 12 23:54:50.213 UTC
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 10.1.3.1 timeout is 1 seconds:
..........
Success rate is 0 percent (0/10)Import is set on the receiving side
65001:1001, which the other spoke exports, is added to the VRF of spoke 1 only.
vrf CUST-A
address-family ipv4 unicast
import route-target
65001:1001
!
!
!
endThe route of the other spoke is back in the BGP table of spoke 1.
RP/0/RP0/CPU0:CE-SP1#show bgp
Tue Oct 13 00:05:30.410 UTC
BGP router identifier 12.12.12.12, local AS number 65102
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0xe0000000 RD version: 16
BGP main routing table version 16
BGP NSR Initial initsync version 3 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs
Status codes: s suppressed, d damped, h history, * valid, > best
i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 10.1.1.1/32 172.16.2.1 0 65001 65101 i
*> 10.1.2.1/32 0.0.0.0 0 32768 i
*> 10.1.3.1/32 172.16.2.1 0 65001 65103 i
*> 172.16.1.0/24 172.16.2.1 0 65001 ?
*> 172.16.2.0/24 172.16.2.1 0 0 65001 ?
*> 172.16.3.0/24 172.16.2.1 0 65001 ?
Processed 6 prefixes, 6 pathsThe ping still fails.
RP/0/RP0/CPU0:CE-SP1#ping 10.1.3.1 source 10.1.2.1 count 10 timeout 1
Tue Oct 13 00:01:48.348 UTC
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 10.1.3.1 timeout is 1 seconds:
..........
Success rate is 0 percent (0/10)Import belongs to the VRF that receives. Spoke 1 can now take the other spoke’s route, but spoke 2 does not take spoke 1’s route, so nothing comes back. Adding it on one side alone does not make a working path.
Extranet
The VRF of the hub imports the RT of customer B (65001:200), and an import route-policy drops the prefix that is not shared.
vrf CUST-A
address-family ipv4 unicast
import route-policy EXTRANET-IN
import route-target
65001:200
!
!
!
prefix-set B-PRIVATE
10.2.8.1/32
end-set
!
route-policy EXTRANET-IN
if destination in B-PRIVATE then
drop
else
pass
endif
end-policy
!
endCustomer B imports the export target of the hub (65001:1000).
vrf CUST-B
address-family ipv4 unicast
import route-target
65001:1000
!
!
!
endOnly the shared prefix of customer B (10.2.9.1/32) is in the BGP table of the hub. 10.2.8.1/32 is not.
RP/0/RP0/CPU0:CE-HUB#show bgp
Tue Oct 13 00:19:07.218 UTC
BGP router identifier 11.11.11.11, local AS number 65101
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0xe0000000 RD version: 18
BGP main routing table version 18
BGP NSR Initial initsync version 3 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs
Status codes: s suppressed, d damped, h history, * valid, > best
i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 10.1.1.1/32 0.0.0.0 0 32768 i
*> 10.1.2.1/32 172.16.1.1 0 65001 65102 i
*> 10.1.3.1/32 172.16.1.1 0 65001 65103 i
*> 10.2.9.1/32 172.16.1.1 0 65001 65201 i
*> 172.16.1.0/24 172.16.1.1 0 0 65001 ?
*> 172.16.2.0/24 172.16.1.1 0 65001 ?
*> 172.16.3.0/24 172.16.1.1 0 65001 ?
*> 172.16.4.0/24 172.16.1.1 0 65001 ?
Processed 8 prefixes, 8 pathsThe pings agree: the shared prefix answers, the other one does not.
RP/0/RP0/CPU0:CE-HUB#ping 10.2.9.1 source 10.1.1.1 count 10 timeout 1
Tue Oct 13 00:15:29.309 UTC
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 10.2.9.1 timeout is 1 seconds:
!!!!!!!!!!
Success rate is 100 percent (10/10), round-trip min/avg/max = 12/23/71 msRP/0/RP0/CPU0:CE-HUB#ping 10.2.8.1 source 10.1.1.1 count 10 timeout 1
Tue Oct 13 00:15:30.334 UTC
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 10.2.8.1 timeout is 1 seconds:
..........
Success rate is 0 percent (0/10)The spokes cannot reach customer B at all, because only the VRF of the hub imports its RT.
RP/0/RP0/CPU0:CE-SP1#ping 10.2.9.1 source 10.1.2.1 count 10 timeout 1
Tue Oct 13 00:16:11.037 UTC
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 10.2.9.1 timeout is 1 seconds:
..........
Success rate is 0 percent (0/10)Verification configs and show output
For every STEP the following files were collected from all eight routers, separated per router. The verification config is ..._run.txt (the final state is the one from the last STEP).
| File | Contents |
|---|---|
..._show.txt | show version / show interface description / the OSPF, LDP, BGP and VRF show commands |
..._log.txt | show logging limited to that STEP |
..._run.txt | show running-config at that STEP (the verification config) |
..._ping.txt | ping and traceroute for that STEP (from every CE to every CE) |
..._trace.txt | show bgp trace (PEs only) |
..._commit.cfg | The configuration actually committed in that STEP (only on routers that changed) |
STEP 0: Initial state (every VRF on 65001:100)
| Router | show | syslog | running-config | ping | trace | committed config |
|---|---|---|---|---|---|---|
| CE-HUB | show | log | run | ping | - | - |
| PE1 | show | log | run | ping | trace | - |
| P1 | show | log | run | ping | - | - |
| PE2 | show | log | run | ping | trace | - |
| CE-SP1 | show | log | run | ping | - | - |
| PE3 | show | log | run | ping | trace | - |
| CE-SP2 | show | log | run | ping | - | - |
| CE-B | show | log | run | ping | - | - |
STEP 1: Asymmetric RTs (hub export 65001:1000 / import 65001:1001, spokes the other way)
| Router | show | syslog | running-config | ping | trace | committed config |
|---|---|---|---|---|---|---|
| CE-HUB | show | log | run | ping | - | - |
| PE1 | show | log | run | ping | trace | commit |
| P1 | show | log | run | ping | - | - |
| PE2 | show | log | run | ping | trace | commit |
| CE-SP1 | show | log | run | ping | - | - |
| PE3 | show | log | run | ping | trace | commit |
| CE-SP2 | show | log | run | ping | - | - |
| CE-B | show | log | run | ping | - | - |
STEP 2: Add import 65001:1001 to the VRF of spoke 1 only
| Router | show | syslog | running-config | ping | trace | committed config |
|---|---|---|---|---|---|---|
| CE-HUB | show | log | run | ping | - | - |
| PE1 | show | log | run | ping | trace | - |
| P1 | show | log | run | ping | - | - |
| PE2 | show | log | run | ping | trace | commit |
| CE-SP1 | show | log | run | ping | - | - |
| PE3 | show | log | run | ping | trace | - |
| CE-SP2 | show | log | run | ping | - | - |
| CE-B | show | log | run | ping | - | - |
STEP 3: Undo STEP 2
| Router | show | syslog | running-config | ping | trace | committed config |
|---|---|---|---|---|---|---|
| CE-HUB | show | log | run | ping | - | - |
| PE1 | show | log | run | ping | trace | - |
| P1 | show | log | run | ping | - | - |
| PE2 | show | log | run | ping | trace | commit |
| CE-SP1 | show | log | run | ping | - | - |
| PE3 | show | log | run | ping | trace | - |
| CE-SP2 | show | log | run | ping | - | - |
| CE-B | show | log | run | ping | - | - |
STEP 4: Extranet (the hub imports 65001:200 with an import route-policy; CUST-B imports the hub)
| Router | show | syslog | running-config | ping | trace | committed config |
|---|---|---|---|---|---|---|
| CE-HUB | show | log | run | ping | - | - |
| PE1 | show | log | run | ping | trace | commit |
| P1 | show | log | run | ping | - | - |
| PE2 | show | log | run | ping | trace | - |
| CE-SP1 | show | log | run | ping | - | - |
| PE3 | show | log | run | ping | trace | commit |
| CE-SP2 | show | log | run | ping | - | - |
| CE-B | show | log | run | ping | - | - |
STEP 5: Undo STEP 4 (final state)
| Router | show | syslog | running-config | ping | trace | committed config |
|---|---|---|---|---|---|---|
| CE-HUB | show | log | run | ping | - | - |
| PE1 | show | log | run | ping | trace | commit |
| P1 | show | log | run | ping | - | - |
| PE2 | show | log | run | ping | trace | - |
| CE-SP1 | show | log | run | ping | - | - |
| PE3 | show | log | run | ping | trace | commit |
| CE-SP2 | show | log | run | ping | - | - |
| CE-B | show | log | run | ping | - | - |
Packet captures were taken per STEP.
| STEP | PE1-P1 | PE2-CE-SP1 |
|---|---|---|
| 0 | pcap | pcap |
| 1 | pcap | pcap |
| 2 | pcap | pcap |
| 3 | pcap | pcap |
| 4 | pcap | pcap |
| 5 | pcap | pcap |
Related articles
- What Is MPLS VPN (L3VPN)
- MPLS VPN VRF (Virtual Routing and Forwarding)
- MPLS VPN RD (Route Distinguisher)
- MPLS VPN Route Target (RT)
- MPLS VPN MP-BGP (Propagating VPNv4 Routes)
- MPLS VPN Label Allocation (per-prefix / per-CE / per-VRF)
- MPLS VPN Forwarding with Two Labels (Transport Label and VPN Label)
- MPLS VPN PE-CE Routing with Static Routes
- MPLS VPN PE-CE Routing with eBGP
- When Several MPLS VPN Sites Share One AS Number (as-override)
- Site of Origin (SoO) in MPLS VPN
- PE-CE routing with OSPF in MPLS VPN
- The OSPF DN bit and the domain tag in MPLS VPN
- Sham links in MPLS VPN (dealing with a backdoor link)
- Controlling routes with RTs in MPLS VPN (extranet, import and export maps)
- Hub and spoke in MPLS VPN