In this article, I will discuss one of the new features that is supported on the Cisco ASA, starting from version 9.4(1) – Policy Based Routing. There used to be many unsupported features that discouraged placing the ASA at the edge and PBR was one of them.

CCNA Training – Resources (Intense)

Let’s start by discussing the problem before PBR was introduced and then go on to see how PBR solves this issue. Consider the network diagram below:

In this diagram, if we wanted to use both links to the Internet at the same time (via default routes), it would be impossible without PBR. This is because the Cisco ASA does not support equal-cost multi-path (ECMP) across multiple interfaces; it only supports up to three equal cost routes on the same interface.

Note: Beginning with version 9.3(2), the Cisco ASA supports ECMP across multiple interfaces as long as those interfaces are part of the same “traffic zone”.

One of the most effective methods to overcome this load balancing restriction on the Cisco ASA is to redesign the network – use a router as the edge device and let the router take care of load balancing. You can’t really blame Cisco for not enabling advanced routing features on the ASA because its job function is a firewall and not routing.

There are other ways to overcome this restriction. For example, if BGP is configured on the Cisco ASA, then you can apply policies that can effectively load balance across links. But the ASA only started supporting BGP from version 9.2(1). Another method that people tried to use was NAT. You can find an article here that describes how to use NAT to achieve some form of load balancing, even though that setup can have several challenges and is not recommended in a production environment.

Policy-based Routing

Enter PBR. The PBR on the Cisco ASA works similarly to the one on Cisco routers – we use route-maps to configure policies and these route-maps are then applied to an interface.

With PBR, we can match based on several criteria such as source and/or destination address/port, protocol and so on and then perform actions such as setting a specific next-hop, interface, QoS value and so on.

Let’s configure the network above in such a way that traffic from 192.168.10.0/24 will flow through ISP1 while traffic from 192.168.20.0/24 will flow through ISP2. Of course, we also have to put NAT into consideration and for this we will configure interface PAT.

interface GigabitEthernet0/0
 nameif outside1
 security-level 0
 ip address 41.1.1.2 255.255.255.0
!
interface GigabitEthernet0/1
 nameif inside
 security-level 100
 ip address 10.254.254.1 255.255.255.0
!
interface GigabitEthernet0/2
 nameif outside2
 security-level 0
 ip address 41.2.2.2 255.255.255.0
!
route inside 192.168.10.0 255.255.255.0 10.254.254.2 1
route inside 192.168.20.0 255.255.255.0 10.254.254.2 1
!
object network NET1
 subnet 192.168.10.0 255.255.255.0
 nat (inside,outside1) dynamic interface
object network NET2
 subnet 192.168.20.0 255.255.255.0
 nat (inside,outside2) dynamic interface
!
access-list NET1_ACL extended permit ip 192.168.10.0 255.255.255.0 any
access-list NET2_ACL extended permit ip 192.168.20.0 255.255.255.0 any
!
route-map PBR permit 10
 match ip address NET1_ACL
 set ip next-hop 41.1.1.1
!
route-map PBR permit 20
 match ip address NET2_ACL
 set ip next-hop 41.2.2.1
!
interface GigabitEthernet0/1
 policy-route route-map PBR

In the configuration above, I have configured two ACLs: one to match source network of 192.168.10.0/24 to any destination and the other to match source network of 192.168.20.0/24 to any destination. These ACLs are then matched under the ‘PBR’ route map which is then applied under the inside (Gi0/1) interface.

Let us test this configuration. I have configured loopack interfaces on the ISP routers: ISP1 router has a loopback with address 4.2.2.2 while ISP2 router has a loopback with address 8.8.8.8. The two internal networks are also loopback interfaces on the INSIDE router. I will also enable the “debug policy-route” command on the ASA.

We will begin by pinging from 192.168.10.0/24 to 4.2.2.2. Based on our configuration, this traffic should go to ISP1.

INSIDE#ping 4.2.2.2 repeat 2 source lo10
Type escape sequence to abort.
Sending 2, 100-byte ICMP Echos to 4.2.2.2, timeout is 2 seconds:
Packet sent with a source address of 192.168.10.1
!!
Success rate is 100 percent (2/2), round-trip min/avg/max = 76/92/108 ms
!
! ***Debug on Cisco ASA ***
PBR-ASA# debug policy-route
debug policy-route  enabled at level 1
PBR-ASA# pbr: policy based route lookup called for 192.168.10.1/2 to 4.2.2.2/0 proto 1 sub_proto 8 received on interface inside
pbr: First matching rule from ACL(1)
pbr: route map PBR, sequence 10, permit; proceed with policy routing
pbr: evaluating next-hop 41.1.1.1
pbr: policy based routing applied; egress_ifc = outside1 : next_hop = 41.1.1.1

As you can see from the debug on the ASA, the traffic matched sequence 10 in the PBR route map and the next-hop configured under that entry is 41.1.1.1. The ASA then tries to find the egress interface to which that next-hop address is connected. To make this determination, it looks at its input routing table to identify a connected route to the next-hop and then uses the interface associated with that connected route as the egress interface. We can view the input routing table using the show asp table routing input command:

With the egress interface determined, the packet is then forwarded. Notice that we didn’t have to configure a route to the final destination itself (4.2.2.2) on the Cisco ASA; it was enough to provide the next-hop (which is what routing is really).

Let us now test the second network (192.168.20.0/24) by pinging to 8.8.8.8.

INSIDE#ping 8.8.8.8 repeat 2 source lo20
Type escape sequence to abort.
Sending 2, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds:
Packet sent with a source address of 192.168.20.1
!!
Success rate is 100 percent (2/2), round-trip min/avg/max = 12/14/16 ms
!
! ***Debug on Cisco ASA ***
PBR-ASA# pbr: policy based route lookup called for 192.168.20.1/6 to 8.8.8.8/0 proto 1 sub_proto 8 received on interface inside
pbr: First matching rule from ACL(2)
pbr: route map PBR, sequence 20, permit; proceed with policy routing
pbr: evaluating next-hop 41.2.2.1
pbr: policy based routing applied; egress_ifc = outside2 : next_hop = 41.2.2.1

That also works. But what happens if any of the ISPs goes down? Traffic from one network will effectively be blackholed. Thankfully, we can configure the ASA to first verify if the next-hop is up before it forwards traffic to it. Let’s change our configuration a bit:

! *** Change NAT rules to Twice NAT rules so that no matter the ISP being used, there will be a NAT rule available***
object network NET1
 no nat (inside,outside1) dynamic interface
object network NET2
 no nat (inside,outside2) dynamic interface
!
nat (inside,outside1) source dynamic NET1 interface
nat (inside,outside2) source dynamic NET1 interface
nat (inside,outside2) source dynamic NET2 interface
nat (inside,outside1) source dynamic NET2 interface
!
! ***Configure SLA monitor and tracking for ISP routers' IP addresses ***
sla monitor 1
 type echo protocol ipIcmpEcho 41.1.1.1 interface outside1
 frequency 10
sla monitor schedule 1 life forever start-time now
track 1 rtr 1 reachability
!
sla monitor 2
 type echo protocol ipIcmpEcho 41.2.2.1 interface outside2
 frequency 10
sla monitor schedule 2 life forever start-time now
track 2 rtr 2 reachability
!
! *** Remove previous set action and use tracked routes under route-map ***
route-map PBR permit 10
 no set ip next-hop 41.1.1.1
 set ip next-hop verify-availability 41.1.1.1 1 track 1
 set ip next-hop verify-availability 41.2.2.1 2 track 2
!
route-map PBR permit 20
 no set ip next-hop 41.2.2.1
 set ip next-hop verify-availability 41.2.2.1 1 track 2
 set ip next-hop verify-availability 41.1.1.1 2 track 1

As you can see from the configuration above, we can configure more than one action to be performed on traffic that matches a route map entry. You can find the order in which set actions are applied when multiple set statements are configured under a route map entry here.

To view our configuration, we can use the show route-map command:

To test this configuration, I will shut down the ISP1 router’s interface and then try to ping 8.8.8.8 from 192.168.10.0/24. Even though this traffic should normally be forwarded to ISP1, it should now be forwarded to ISP2 because of the “verify-availability” option.

After I shut down the ISP1 router’s interface, the ASA detects that the route is down:

However, the ping from 192.168.10.0/24 to 8.8.8.8 is still successful as discussed:

INSIDE#ping 8.8.8.8 repeat 2 source lo10
Type escape sequence to abort.
Sending 2, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds:
Packet sent with a source address of 192.168.10.1
!!
Success rate is 100 percent (2/2), round-trip min/avg/max = 20/22/24 ms
!
! ***Debug on ASA shows that the next configured next-hop is used ***
PBR-ASA(config)# pbr: policy based route lookup called for 192.168.10.1/11 to 8.8.8.8/0 proto 1 sub_proto 8 received on interface inside
pbr: First matching rule from ACL(1)
pbr: route map PBR, sequence 10, permit; proceed with policy routing
pbr: verified next-hop 41.1.1.1 state is DOWN
pbr: evaluating verified next-hop 41.2.2.1
pbr: policy based routing applied; egress_ifc = outside2 : next_hop = 41.2.2.1

On a final note, let me point out that traffic that does not match any entry in the route map or traffic that is permitted in an ACL but matches a deny entry of a route map is routed via the normal route lookup process.

For example, if we add a third internal network of 192.168.30.0/24, configure NAT for this network, and set the default route of the ASA via ISP1, this traffic will be forwarded to ISP1 because it won’t match any entry of the PBR route-map.

! ***Add new loopback interface on INSIDE router ***
INSIDE(config)#interface lo30
INSIDE(config-if)#ip address 192.168.30.1 255.255.255.0
!
! *** On ASA, Configure NAT rule for new network and also default route pointing to ISP1 ***
PBR-ASA(config)# object network NET3
PBR-ASA(config-network-object)# subnet 192.168.30.0 255.255.255.0
PBR-ASA(config-network-object)# nat (inside,outside1) dynamic interface
PBR-ASA(config-network-object)# exit
PBR-ASA(config)# route inside 192.168.30.0 255.255.255.0 10.254.254.2
PBR-ASA(config)# route outside1 0 0 41.1.1.1

With this configuration, assuming that ISP1 is up, if we ping 4.2.2.2 from the 192.168.30.0/24 network, normal route lookup should be used to forward the packet as shown below:

INSIDE#ping 4.2.2.2 repeat 2 source lo30
Type escape sequence to abort.
Sending 2, 100-byte ICMP Echos to 4.2.2.2, timeout is 2 seconds:
Packet sent with a source address of 192.168.30.1
!!
Success rate is 100 percent (2/2), round-trip min/avg/max = 16/16/16 ms
!
! *** Debug on Cisco ASA ***
PBR-ASA(config)# debug policy-route
debug policy-route  enabled at level 1
PBR-ASA(config)# pbr: policy based route lookup called for 192.168.30.1/1 to 4.2.2.2/0 proto 1 sub_proto 8 received on interface inside
pbr: no route policy found; skip to normal route lookup

Summary

This brings us to the end of this article, which I hope you have found informative. In this article, we have discussed policy based routing (PBR) on the Cisco ASA and also seen how to configure it.

I know there will be several scenarios to which PBR can be applied and we have only looked at one use case; however, you should be familiar enough with it now to play around with this feature.

References and Further reading

  • CLI Book 1: Cisco ASA Series General Operations CLI Configuration Guide, 9.4: Policy Based Routing: http://www.cisco.com/c/en/us/td/docs/security/asa/asa94/configuration/general/asa-general-cli/route-policy-based.html