BGP on IOS-XR: Route Policy Language (RPL)

I've been learning BGP on IOS-XR recently. Configuring inbound or outbound BGP policies on IOS-XR is quite different than on IOS-XE or regular IOS. On this platform we use RPL (Route Policy Language) for configuring BGP policies instead of route-maps, filter-lists or prefix-list. It can be a lot more easier using this than using route-maps in my opinion, but we have to learn the basics of how RPL works.

 

In this lab we're going to focus on XR3 which runs IOS-XR. First let's take a look how we configure basic BGP peering:

RP/0/0/CPU0:XR3(config)#router bgp 65001
RP/0/0/CPU0:XR3(config-bgp)#address-family ipv4 unicast 
RP/0/0/CPU0:XR3(config-bgp-af)#exit
RP/0/0/CPU0:XR3(config-bgp)#neighbor 1.1.3.1
RP/0/0/CPU0:XR3(config-bgp-nbr)#remote-as 100
RP/0/0/CPU0:XR3(config-bgp-nbr)#address-family ipv4 unicast 
RP/0/0/CPU0:XR3(config-bgp-nbr-af)#exit
RP/0/0/CPU0:XR3(config-bgp-nbr)#exit
RP/0/0/CPU0:XR3(config-bgp)#neighbor 10.4.4.4
RP/0/0/CPU0:XR3(config-bgp-nbr)#remote-as 65001
RP/0/0/CPU0:XR3(config-bgp-nbr)#update-source lo0
RP/0/0/CPU0:XR3(config-bgp-nbr)#address-family ipv4 unicast 
RP/0/0/CPU0:XR3(config-bgp-nbr-af)#next-hop-self 
RP/0/0/CPU0:XR3(config-bgp-nbr-af)#commit

We have to enable the address-family 'globally', directly under the router bgp command, and also specifically for every neighbor, later we'll configure every policy-related command under the address-family of a given neighbor.

After just configuring the basic BGP peerings on all of the routers without any policy we can see that XR3 only gets the prefix from the Route Reflector (XR4), and he does not receive anything from R1, his eBGP peer (at this point we only advertise 1.1.1.1/32 on R1): 

RP/0/0/CPU0:XR3(config-bgp-nbr-af)#do show bgp ipv4 unicast | begin Network
Sat Aug  9 09:37:25.943 UTC
   Network            Next Hop            Metric LocPrf Weight Path
*>i1.1.1.1/32         10.2.2.2                 0    100      0 100 i

Processed 1 prefixes, 1 paths

That's because the default policy is already applied to every eBGP peer. By default on IOS-XR we drop everything from any eBGP peer, and we don't advertise anything to eBGP peers. We don't have a such a restriction for iBGP neighbors: we accept everything from anyone and we can advertise to any iBGP neighbor just like on IOS-XE. So first we have to configure a policy with a simple pass statement in order to receive or send prefixes:

RP/0/0/CPU0:XR3(config)#router bgp 65001
RP/0/0/CPU0:XR3(config-bgp)#neighbor 1.1.3.1
RP/0/0/CPU0:XR3(config-bgp-nbr)#address-family ipv4 unicast 
RP/0/0/CPU0:XR3(config-bgp-nbr-af)#show commit changes diff
Sat Aug  9 09:44:07.745 UTC
Building configuration...
!! IOS XR Configuration 6.1.3
   !
+  route-policy JUST_PASS
+    pass
+  end-policy
end

RP/0/0/CPU0:XR3(config-bgp-nbr-af)#route-policy JUST_PASS in
RP/0/0/CPU0:XR3(config-bgp-nbr-af)#route-policy JUST_PASS out
RP/0/0/CPU0:XR3(config-bgp-nbr-af)#commit

After committing the changes we can accept the NLRI from the eBGP peer and put into the BGP table:

RP/0/0/CPU0:XR3(config-bgp-nbr-af)#do show bgp ipv4 unicast | begin Network
Sat Aug  9 09:45:12.751 UTC
   Network            Next Hop            Metric LocPrf Weight Path
*> 1.1.1.1/32         1.1.3.1                  0             0 100 i
* i                   10.2.2.2                 0    100      0 100 i

Processed 1 prefixes, 2 paths

Of course we prefer the route from the eBGP peer if every other attribute is equal as you can see above. So that's different on IOS-XR, keep in mind that by default the router won't advertise anything to eBGP peers and discards every Updates from eBGP peers.

Now let's experiment, and practice configuring BGP policies. I shut down the peering between R1 and R2, so that XR3 is the only router connected to AS 100, and I send a bunch of prefixes from R1:

RP/0/0/CPU0:XR3#show ip bgp | begin Network
Sat Aug  9 15:12:32.059 UTC
   Network            Next Hop            Metric LocPrf Weight Path
*> 1.1.1.1/32         1.1.3.1                 11             0 100 i
*> 100.1.1.0/24       1.1.3.1                  1             0 100 100 100 i
*> 100.1.2.0/24       1.1.3.1                111             0 100 200 300 400 500 i
*> 100.1.3.0/24       1.1.3.1              12345             0 100 i
*> 111.1.0.0/16       1.1.3.1               9999             0 100 1 i
*> 111.2.0.0/16       1.1.3.1                100             0 100 1 2 3 4 5 6 i

Processed 6 prefixes, 6 paths

As you can see I did some AS-Path prepending, and assigned different MED values to the prefixes. Now let's take a look at few examples how can we configure inbound BGP policies with RPS.

Task 1: Accept only /32 prefixes, or prefixes originated from AS 500 and set the Local Preference to 3333 for the accepted prefixes. Discard everything else.

route-policy TASK_ONE
  if destination in (0.0.0.0/0 ge 32) or as-path originates-from '500'  then
    set local-preference 3333
  else
    drop
  endif
end-policy

 neighbor 1.1.3.1
  remote-as 100
  address-family ipv4 unicast
   route-policy TASK_ONE in
   route-policy JUST_PASS out

We usually use the if-then structure which you can see above: we don't have to create prefix-lists, and link the prefix-lists with match statements to route-maps. Also we don't have to create as-path access-listsand write regular expressions like on IOS-XE. This is one of the biggest advantage of RPL in my opinion, the feature to match on the AS-Path attribute is already included in the language. Look at how many options we have:

RP/0/0/CPU0:XR3(config-rpl)#if destination in (0.0.0.0/0 ge 32) or as-path ?
  in               Member of a set
  is-local         Route originates in this AS
  length           Length of BGP AS-path
  neighbor-is      BGP AS-path neighbor is
  originates-from  BGP AS-path originates-from
  passes-through   BGP AS-path passes-through
  unique-length    Length of BGP AS-path ignoring duplicates

With as-path access-list we would configure the originates-from option like this: _500$ in this case. Or the is-local would be this: ^$. You don't really have to know regex if you're using RPL. So based on the task requirements above we should only accept 1.1.1.1/32 and 100.1.2.0/24. And this is how the BGP table looks like after committing the changes:

RP/0/0/CPU0:XR3#show bgp ipv4 unicast | begin Net
Sat Aug  9 15:26:26.851 UTC
   Network            Next Hop            Metric LocPrf Weight Path
*> 1.1.1.1/32         1.1.3.1                 11   3333      0 100 i
*> 100.1.2.0/24       1.1.3.1                111   3333      0 100 200 300 400 500 i

Processed 2 prefixes, 2 paths

Task 2: Drop the prefix if the AS-Path contains AS 1 and the MED is higher than 100. If the prefix is /24 or more specific set the Local Preference to 33. Accept every other prefix unchanged.

route-policy TASK_TWO
  if as-path passes-through '1'  and med ge 101 then
    drop
  elseif destination in (0.0.0.0/0 ge 24) then
    set local-preference 33
  else
    pass
  endif
end-policy

RP/0/0/CPU0:XR3(config-bgp-nbr-af)#route-policy TASK_TWO in

If you wanted to do the passes-through statement with regex, it'd be this: _1_. So based on the requirements we should drop 111.1.0.0/16 and set the Local Preference to 33 for everything except 111.2.0.0/16 which we should just accept unchanged:

RP/0/0/CPU0:XR3(config-bgp-nbr-af)#do show ip bgp | begin Net  
Sat Aug  9 15:50:25.473 UTC
   Network            Next Hop            Metric LocPrf Weight Path
*> 1.1.1.1/32         1.1.3.1                 11     33      0 100 i
*> 100.1.1.0/24       1.1.3.1                  1     33      0 100 100 100 i
*> 100.1.2.0/24       1.1.3.1                111     33      0 100 200 300 400 500 i
*> 100.1.3.0/24       1.1.3.1              12345     33      0 100 i
*> 111.2.0.0/16       1.1.3.1                100             0 100 1 2 3 4 5 6 i

Task 3: Discard prefixes which are at least four AS away, or with MED greater or equal than 10000. For prefix 1.1.1.1/32 we should do AS-Path prepending. Accept everything else unchanged.

route-policy TASK_THREE
  if as-path length ge 4 or med ge 10000 then
    drop
  elseif destination in (1.1.1.1/32) then
    prepend as-path most-recent 5
  else
    pass
  endif
end-policy


RP/0/0/CPU0:XR3(config-bgp-nbr-af)#route-policy TASK_THREE in

If we had to do the as-path length with regex, it'd be a really complex expression, like this: ^[0-9]+_[0-9]+_[0-9]+_[0-9]+?. This one is so much more easier with RPL. So according to the task description we only accept 1.1.1.1/32 (and do prepending for this one), 100.1.1.0/24 and 111.1.0.0/16:

RP/0/0/CPU0:XR3(config-bgp-nbr-af)#do show ip bgp | begin Net
Sat Aug  9 16:13:42.117 UTC
   Network            Next Hop            Metric LocPrf Weight Path
*> 1.1.1.1/32         1.1.3.1                 11             0 100 100 100 100 100 100 i
*> 100.1.1.0/24       1.1.3.1                  1             0 100 100 100 i
*> 111.1.0.0/16       1.1.3.1               9999             0 100 1 i