VRF Export Maps

By stretch | Thursday, September 26, 2013 at 10:48 p.m. UTC

VRFs are an excellent tool for maintaining segregated routing topologies for separate customers or services. I've previously covered inter-VRF routing using route targets, but what if we only want to export a subset of the routes within a VRF? Here's a scenario in which this would be desirable.

topology1.png

Customers A and B each have a site network and a colocation network, and both customers need access to the 192.168.0.0/24 network in the Services VRF. The customers must utilize unique IP space in order to prevent overlapping networks, so each customer has been allocated dedicated IP space from their common provider out o 10.0.0.0/8. Unfortunately, customer A is still has some networks within the 172.16.0.0/16. These networks need to access services in the host colo, but the service provider can't allow this space to be advertised into the Services VRF as it's not approved IP space.

Our goal is to export only the networks within the 10.0.0.0/8 space from the customer VRFs to the Services VRF. How can we accomplish this?

Let's have a look at the initial network state. (This lab was performed using a single router for simplicity. In the real world, these customers would typically be connected via an MPLS VPN.) Each customer and colo network has its own VRF and dedicated route target (RT). The Services VRF has been configured with an import/export RT pair for scalability reasons. No export among VRFs has yet been configured.

ip vrf Customer_A
 rd 65000:1001
 route-target export 65000:1001
 route-target import 65000:1001
!
ip vrf Customer_A_Colo
 rd 65000:2001
 route-target export 65000:2001
 route-target import 65000:2001
!
ip vrf Customer_B
 rd 65000:1002
 route-target export 65000:1002
 route-target import 65000:1002
!
ip vrf Customer_B_Colo
 rd 65000:2002
 route-target export 65000:2002
 route-target import 65000:2002
!
ip vrf Services
 rd 65000:100
 route-target export 65000:100
 route-target import 65000:100
 route-target import 65000:101
!
interface Loopback100
 ip vrf forwarding Services
 ip address 192.168.0.1 255.255.255.0
!
interface Loopback1001
 ip vrf forwarding Customer_A
 ip address 172.16.0.1 255.255.0.0 secondary
 ip address 10.1.1.1 255.255.255.0
!
interface Loopback1002
 ip vrf forwarding Customer_B
 ip address 10.1.2.1 255.255.255.0
!
interface Loopback2001
 ip vrf forwarding Customer_A_Colo
 ip address 10.2.1.1 255.255.255.0
!
interface Loopback2002
 ip vrf forwarding Customer_B_Colo
 ip address 10.2.2.1 255.255.255.0
!
router bgp 65000
 !
 address-family ipv4 vrf Services
  redistribute connected
 exit-address-family
 !
 address-family ipv4 vrf Customer_B_Colo
  redistribute connected
 exit-address-family
 !
 address-family ipv4 vrf Customer_B
  redistribute connected
 exit-address-family
 !
 address-family ipv4 vrf Customer_A_Colo
  redistribute connected
 exit-address-family
 !
 address-family ipv4 vrf Customer_A
  redistribute connected
 exit-address-family

First, we want to enable route exchange between each customer VRF and its respective colo. This is easily accomplished by adding an additional import RT to each customer VRF:

ip vrf Customer_A
 route-target import 65000:2001
!
ip vrf Customer_A_Colo
 route-target import 65000:1001
!
ip vrf Customer_B
 route-target import 65000:2002
!
ip vrf Customer_B_Colo
 route-target import 65000:2001

topology2.png

The Customer_A VRF now has a route for the Customer_A_Colo networks, and vice versa. The same goes for Customer_B and its colo network. You could check the routing table for each VRF independently (show ip route vrf NAME), or you can use the command show ip bgp vpnv4 all to quickly dump the routes from all VRFs:

Router# show ip bgp vpnv4 all
BGP table version is 18, local router ID is 1.1.1.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
              r RIB-failure, S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

Network          Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65000:100 (default for vrf Services)
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1001 (default for vrf Customer_A)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1002 (default for vrf Customer_B)
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2001 (default for vrf Customer_A_Colo)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2002 (default for vrf Customer_B_Colo)
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?

Notice that the Customer_A and Customer_A_Colo VRFs both contain the same set of routes, as do the two VRFs for Customer B. (If the routes don't appear to be exchanged, ensure that MP-BGP is running and has a router ID configured.)

Next, we need to exchange routes among the four customer VRFs and the common services VRF. We do this by adding the import and export RT for the Services VRF.

ip vrf Customer_A
 route-target import 65000:100
 route-target export 65000:101
!
ip vrf Customer_A_Colo
 route-target import 65000:100
 route-target export 65000:101
!
ip vrf Customer_B
 route-target import 65000:100
 route-target export 65000:101
!
ip vrf Customer_B_Colo
 route-target import 65000:100
 route-target export 65000:101

topology3.png

We can see that the Services VRF now see all customer routes, and all customer VRFs have a route to the services network:

Router# show ip bgp vpnv4 all
BGP table version is 38, local router ID is 1.1.1.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
              r RIB-failure, S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

Network          Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65000:100 (default for vrf Services)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1001 (default for vrf Customer_A)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1002 (default for vrf Customer_B)
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2001 (default for vrf Customer_A_Colo)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2002 (default for vrf Customer_B_Colo)
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?

But now we have a problem: The legacy 172.16.0.0/16 prefix from Customer_A is polluting the Services VRF. We need to find a way to prevent it from being exported to the Services VRF while still permitting the valid 10.1.1.0/24 route. This is where export maps come in handy.

Export Maps

Let's take a closer look at the routes being exported from the Customer_A VRF:

Router# show ip bgp vpnv4 vrf Customer_A 10.1.1.0
BGP routing table entry for 65000:1001:10.1.1.0/24, version 25
Paths: (1 available, best #1, table Customer_A)
  Not advertised to any peer
  Local
    0.0.0.0 from 0.0.0.0 (1.1.1.1)
      Origin incomplete, metric 0, localpref 100, weight 32768, valid, sourced, best
      Extended Community: RT:65000:101 RT:65000:1001
      mpls labels in/out 18/aggregate(Customer_A)
Router# show ip bgp vpnv4 vrf Customer_A 172.16.0.0
BGP routing table entry for 65000:1001:172.16.0.0/16, version 42
Paths: (1 available, best #1, table Customer_A)
  Not advertised to any peer
  Local
    0.0.0.0 from 0.0.0.0 (1.1.1.1)
      Origin incomplete, metric 0, localpref 100, weight 32768, valid, sourced, best
      Extended Community: RT:65000:101 RT:65000:1001
      mpls labels in/out 17/aggregate(Customer_A)

Recall that a route target is just a type of BGP community. Here we can see that the two route targets (communities) we configured using the route-target export command under VRF configuration have been attached to both routes from this VRF, as expected. The 65000:101 RT is what's causing the Services VRF to import these routes. What we want to do is prevent the 65000:101 RT from being added to the 172.16.0.0/16 route while still including it on the 10.1.1.0/24 route.

We can define a route-map to overwrite the set of RTs attached to a route with whatever we want, and apply it to the Customer_A VRF as an export map. We'll use a prefix list to match any routes within 172.16.0.0/16.

ip prefix-list Customer_A_Legacy seq 5 permit 172.16.0.0/16 le 32
!
route-map Customer_A_Export permit 10
 match ip address prefix-list Customer_A_Legacy
 set extcommunity rt  65000:1001

Note that the set extcommunity command in this instance is not adding an RT (because we did not include the additive keyword). Rather, we are overwriting the existing set of RTs with our own set (which happens to be only a single RT). Essentially, this line says, "Get rid of any existing RTs and add an RT for 65000:1001."

The route map is applied to the VRF using the export map command:

ip vrf Customer_A
 export map Customer_A_Export

Let's take a look at those two routes again:

Router# show ip bgp vpnv4 vrf Customer_A 10.1.1.0
BGP routing table entry for 65000:1001:10.1.1.0/24, version 25
Paths: (1 available, best #1, table Customer_A)
  Not advertised to any peer
  Local
    0.0.0.0 from 0.0.0.0 (1.1.1.1)
      Origin incomplete, metric 0, localpref 100, weight 32768, valid, sourced, best
      Extended Community: RT:65000:101 RT:65000:1001
      mpls labels in/out 18/aggregate(Customer_A)
Router# show ip bgp vpnv4 vrf Customer_A 172.16.0.0
BGP routing table entry for 65000:1001:172.16.0.0/16, version 45
Paths: (1 available, best #1, table Customer_A)
Flag: 0xA00
  Not advertised to any peer
  Local
    0.0.0.0 from 0.0.0.0 (1.1.1.1)
      Origin incomplete, metric 0, localpref 100, weight 32768, valid, sourced, best
      Extended Community: RT:65000:1001
      mpls labels in/out 17/aggregate(Customer_A)

Success! The route for 172.16.0.0/16 no longer has the 65000:101 RT attached to it, which means it should no longer be imported by the Services VRF. The Customer_A_Colo VRF will still import the route because of the 65000:1001 RT.

Router# show ip bgp vpnv4 all
BGP table version is 47, local router ID is 1.1.1.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
              r RIB-failure, S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

Network          Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65000:100 (default for vrf Services)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1001 (default for vrf Customer_A)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1002 (default for vrf Customer_B)
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2001 (default for vrf Customer_A_Colo)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2002 (default for vrf Customer_B_Colo)
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?

Great, that's exactly what we wanted!

By the way, did you notice that our route map is not permitting any other routes, yet the 10.1.1.0/24 network is still exported? This is contrary to how route maps typically work and an important caveat to remember. Think of it this way: Your export map matches exported routes which you want to modify, not the routes you want to export in the first place.

There's one last concern to address with our solution. The current configuration explicitly denies certain routes and allows all others. This is contrary to the preferred practice of allowing only routes which we explicitly permit and denying everything else. If customer A was to announce another unwanted network (e.g. 172.17.0.0/16), our export map wouldn't prevent it from being exported to the Services VRF.

We can fix this by inverting our VRF export logic: Instead of removing the 65000:101 RT from routes we don't want, we'll only add it to routes we do want. First, let's remove the route-target export 65000:101 from the Customer_A VRF. This will remove both Customer_A routes from the Services VRF.

ip vrf Customer_A
 no route-target export 65000:101
 no export map Customer_A_Export

Next, we'll recreate our prefix list and route-map to reflect the new logic:

no route-map Customer_A_Export
no ip prefix-list Customer_A_Legacy
!
ip prefix-list Customer_A_Networks permit 10.1.1.0/24
!
route-map Customer_A_Export permit 10
 match ip address prefix-list Customer_A_Networks
 set extcommunity rt  65000:101 additive
!
ip vrf Customer_A
 export map Customer_A_Export

We still see the same BGP communities as with the previous configuration: Only the 10.1.1.0/24 network has the 65000:101 RT attached.

Router# show ip bgp vpnv4 vrf Customer_A 10.1.1.0
BGP routing table entry for 65000:1001:10.1.1.0/24, version 71
Paths: (1 available, best #1, table Customer_A)
  Not advertised to any peer
  Local
    0.0.0.0 from 0.0.0.0 (1.1.1.1)
      Origin incomplete, metric 0, localpref 100, weight 32768, valid, sourced, best
      Extended Community: RT:65000:101 RT:65000:1001
      mpls labels in/out 18/aggregate(Customer_A)
Router# show ip bgp vpnv4 vrf Customer_A 172.16.0.0
BGP routing table entry for 65000:1001:172.16.0.0/16, version 65
Paths: (1 available, best #1, table Customer_A)
  Not advertised to any peer
  Local
    0.0.0.0 from 0.0.0.0 (1.1.1.1)
      Origin incomplete, metric 0, localpref 100, weight 32768, valid, sourced, best
      Extended Community: RT:65000:1001
      mpls labels in/out 17/aggregate(Customer_A)

But now, if we add a second rogue network to the Customer_A VRF, it won't get exported to the Services VRF because it won't be matched by our prefix list.

Router# show ip bgp vpnv4 all
BGP table version is 76, local router ID is 1.1.1.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
              r RIB-failure, S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

Network          Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65000:100 (default for vrf Services)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1001 (default for vrf Customer_A)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 172.17.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:1002 (default for vrf Customer_B)
*> 10.1.2.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2001 (default for vrf Customer_A_Colo)
*> 10.1.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 172.16.0.0       0.0.0.0                  0         32768 ?
*> 172.17.0.0       0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?
Route Distinguisher: 65000:2002 (default for vrf Customer_B_Colo)
*> 10.2.1.0/24      0.0.0.0                  0         32768 ?
*> 10.2.2.0/24      0.0.0.0                  0         32768 ?
*> 192.168.0.0      0.0.0.0                  0         32768 ?

There's one important caveat to address before we wrap up. Although the Services VRF doesn't have a route to the 172.16.0.0/16 network at customer A, it's still possible for customer A to send traffic from this network into the Services VRF. Return traffic won't make it back, however this leaves the door open for denial of service attacks (for example, spoofing traffic so that it appears to come from customer B, and flooding that customer with responses). Additional controls such as unicast RPF or even plain old access lists are needed at the customer edge to block invalid traffic.

About the Author

Jeremy Stretch is a network engineer living in the Raleigh-Durham, North Carolina area. He is known for his blog and cheat sheets here at Packet Life. You can reach him by email or follow him on Twitter.

Posted in Routing

Comments


Spikes
September 26, 2013 at 10:51 p.m. UTC

One of the best primers I have read on this topic, by far. Thank you.


Stefan (guest)
September 27, 2013 at 7:45 a.m. UTC

I follow your blog since some time now and I have to say I really like how clear and concise the explanations are. I rarely see that in a tech blog. Great job!


Gernot (guest)
September 27, 2013 at 2:21 p.m. UTC

This is a really great and especially clear explanation!


Lakers0044 (guest)
September 27, 2013 at 6:21 p.m. UTC

Jeremy,

I assume there is a typo in the diagram for Customer_B. Should it be 10.1.2.0/24?


emilio1973
September 30, 2013 at 7:14 p.m. UTC

Great job!!


MattE (guest)
October 3, 2013 at 12:55 p.m. UTC

Great addition to an excellent set of VRF blogs!


networkdude1 (guest)
October 18, 2013 at 4:37 p.m. UTC

ip vrf Customer_B_Colo
route-target import 65000:2001

Should this not be importing 65000:1002 for Customer B 10.2.1.0/24 network ?

If configured as per the example Customer B colo will be importing Customer_A colo routes.


djfader
October 29, 2013 at 7:10 p.m. UTC

networkdude1 (guest)

Of course you are right there is a typo

B Colo shall import 65000:1002


JPI
November 26, 2013 at 7:04 a.m. UTC

Excellent writing. Thanks a LOT.

What is the reason for importing the routes of a VRF into the same originating VRF? This looks like a re-import. I know of running installations of such VRF export/import scenarios that do not have it.

ip vrf Customer_A
 rd 65000:1001
 route-target export 65000:1001
 route-target import 65000:1001 ⇦ ??

thepacketgeek
November 29, 2013 at 2:49 a.m. UTC

@JPI,

Importing the route-target will grab those MPBGP vpnv4 routes that were exported to that same route-target from other routers. This is necessary if you have the same VRF on multiple routers and they are sharing routes via MPBGP.

Stretch explains this well in his previous blog post here: http://packetlife.net/blog/2013/jun/10/route-distinguishers-and-route-targets/


xiaoliang (guest)
February 28, 2014 at 2:26 a.m. UTC

It's very clear and helpful for me!
Thank you very much, Jeremy!


Shuja (guest)
July 4, 2014 at 4:00 p.m. UTC

Can you please write an article of importing and exporting routes using mpls vpn..so let say PE-A is connected to PE-B and PE-C and PE-A is sending vrf B route to PE-B and vrf C routes to PE-C, I nee to leak routes between B and C over the mpls hub. How can I do that?

Leave a Comment


Optional; will not be displayed publicly or given out.
No commercial links. Only personal (e.g. blog, Twitter, or LinkedIn) and/or on-topic links, please.
Which interior routing protocol has a 15-hop limit?