1.6 Policy-Based Routing¶
Blueprint 1.6: Configure and verify policy-based routing
- Route maps for PBR:
matchclauses (ACL, packet length) andsetclauses (next hop, interface, default next hop) - Applying PBR to transit traffic (
ip policy route-map) and to router-generated traffic (ip local policy route-map) - Tracking the next hop:
set ip next-hop verify-availabilitywith IP SLA and object tracking - Verifying and troubleshooting:
show ip policy,show route-map,debug ip policy, traceroute
Why PBR exists¶
Normal IP routing looks at one thing: the destination address. The longest match in the routing table wins, whatever the source, application or packet size. Policy-based routing (PBR) lets the router make a forwarding decision on other fields before (or instead of) that lookup. Typical business reasons:
- Send guest or bulk traffic out a cheap Internet link while corporate traffic uses the MPLS link.
- Send voice from one subnet over a low-latency carrier.
- Push traffic from a specific source through a firewall or WAN optimiser that is not in the normal routing path.
- Drop traffic from a source entirely (
set interface Null0) without touching the routing table.
PBR is local to the router that runs it. It does not change what the router advertises, so neighbours know nothing about it. That matters when troubleshooting: the routing tables on every router can look perfect while traffic takes an unexpected path, or the reverse.
graph TB
P["Packet arrives on Gi0/0<br/>ip policy route-map WAN-PBR"] --> S{"Route-map sequence<br/>matches?"}
S -->|"permit sequence matches"| SET["Apply set clauses<br/>in precedence order"]
S -->|"deny sequence matches"| NR["Normal routing<br/>destination lookup"]
S -->|"no sequence matches"| NR
SET --> OK{"Chosen next hop or<br/>interface usable?"}
OK -->|"yes"| PBR["Policy routed"]
OK -->|"no"| NR
How a PBR route map is processed¶
PBR reuses the route-map structure from 1.2, but the meaning of permit and deny is different from route filtering.
| Route-map result | In redistribution or BGP filtering | In PBR |
|---|---|---|
| Matches a permit sequence | Route is allowed (and set applies) |
Packet is policy routed using the set clauses |
| Matches a deny sequence | Route is filtered | Packet is routed normally (not dropped) |
| Matches no sequence (implicit deny) | Route is filtered | Packet is routed normally (not dropped) |
Inside a sequence, the ACL in match ip address only decides whether the packet matches. An ACL deny line means "this sequence does not match", so the router moves on to the next sequence. It does not drop the packet.
Match clauses¶
| Clause | Matches on |
|---|---|
match ip address ACL |
Numbered or named standard/extended ACL: source, destination, protocol, ports, DSCP |
match length MIN MAX |
Layer 3 packet length, for example small packets for interactive traffic |
match ipv6 address ACL |
IPv6 ACL, for IPv6 PBR |
If a sequence lists several ACLs on one match ip address line, a packet that matches any of them matches (logical OR). Separate match lines of different types are ANDed.
Set clauses and their precedence¶
| Clause | Uses the routing table first? | Typical use |
|---|---|---|
set ip next-hop A.B.C.D [A.B.C.D ...] |
No. Used before the RIB lookup. | Force a path. The first listed next hop that is reachable is used. |
set ip next-hop recursive A.B.C.D |
No, but the next hop itself may be remote; it is resolved through the RIB | Steer to a router that is not directly connected |
set ip next-hop verify-availability A.B.C.D SEQ track N |
No, but only while track object N is up | Force a path with health checking |
set interface TYPE NUM |
No | Send out an interface, mostly point-to-point or Null0 to drop |
set ip default next-hop A.B.C.D |
Yes. Used only if the RIB has no explicit route. | Gateway of last resort for matched traffic only |
set default interface TYPE NUM |
Yes. Used only if the RIB has no explicit route. | Same, by interface |
When several are configured in one sequence, IOS evaluates them in this order: set ip next-hop, then set interface, then set ip default next-hop, then set default interface. The first usable one wins. If none is usable, the packet is routed normally.
Exam trap
set ip default next-hop does not override a default route. A default route (0.0.0.0/0) in the routing table does not count as an explicit route, so the PBR default next hop is used for any destination that only matches 0.0.0.0/0. If the router has a specific route (for example a /16 learned from OSPF) for the destination, the PBR default next hop is ignored. A question that says "the router has a default route to ISP1, and traffic still goes to ISP1 despite PBR" usually has a specific route in the RIB.
What "reachable" means for set ip next-hop¶
A plain set ip next-hop address must be on a directly connected subnet with a resolved adjacency. If the interface toward that next hop goes down, the next hop is skipped and, if there is no other usable set clause, the packet falls back to normal routing. That fallback is by design, but it only reacts to the local interface going down. If a switch sits between the routers, or the failure is further upstream, the interface stays up and PBR keeps sending packets into a black hole.
The fix is verify-availability with object tracking:
ip sla 10
icmp-echo 10.1.3.2 source-interface GigabitEthernet0/2
frequency 5
ip sla schedule 10 life forever start-time now
!
track 10 ip sla 10 reachability
!
route-map GUEST-PBR permit 10
match ip address GUEST-SRC
set ip next-hop verify-availability 10.1.3.2 10 track 10
The 10 before track is a sequence number for this next hop. You can list several next hops, each with its own sequence and track object, and the lowest sequence whose track is up is used. When every tracked next hop is down, the packet is routed normally.
set ip next-hop verify-availability with no arguments is an older form that checks the next hop through CDP neighbour information. Because CDP is often disabled on WAN links, prefer the IP SLA form.
Exam trap
An IP SLA probe does nothing until it is scheduled. If show track reports the object as down while the next hop answers pings from the CLI, check for a missing ip sla schedule line. A track that is permanently down silently turns the PBR policy off, so all traffic follows the routing table.
Where to apply the policy¶
| Command | Where | What it catches |
|---|---|---|
ip policy route-map NAME |
Interface (or subinterface, SVI, tunnel) | Packets received on that interface and forwarded through the router |
ip local policy route-map NAME |
Global configuration | Packets generated by the router itself (pings, traceroute, Telnet/SSH sessions it originates, syslog, SNMP traps) |
ipv6 policy route-map NAME |
Interface | IPv6 packets received on that interface |
PBR is ingress only. There is no outbound ip policy. Apply it on the interface facing the users whose traffic you want to steer, never on the WAN interface the traffic leaves through.
Exam trap
Testing PBR with a ping from the router that runs PBR proves nothing. Router-generated packets do not arrive on an interface, so the interface policy never sees them. Either test from a host or downstream router behind the ingress interface, or configure ip local policy route-map if the router's own traffic must follow the policy. The reverse is also tested: ip local policy has no effect on transit traffic.
Configuration example¶
Verification¶
| Command | What it proves |
|---|---|
show ip policy |
Which interfaces have a policy and which route map. A missing line means the policy is not applied. Local policy shows as local. |
show route-map NAME |
The match and set clauses as IOS parsed them, the track state, and Policy routing matches counters per sequence |
show access-lists NAME |
ACL hit counters. Combine with the route-map counter to see whether packets match. |
show track N and show ip sla statistics N |
Whether a tracked next hop is considered up |
traceroute DEST source SRC from a downstream host or router |
The actual path, which is the final proof |
debug ip policy |
Per-packet decision: matched and routed, or rejected and routed normally. Use with an ACL-filtered debug ip packet only in the lab. |
R1# show ip policy
Interface Route map
Gi0/0 GUEST-PBR
R1# show route-map GUEST-PBR
route-map GUEST-PBR, permit, sequence 10
Match clauses:
ip address (access-lists): GUEST-SRC
Set clauses:
ip next-hop verify-availability 10.1.3.2 10 track 10 [up]
Policy routing matches: 215 packets, 21500 bytes
The [up] tag reflects the track object. The counter shows packets that matched the sequence and were policy routed. If the counter stays at zero while users send traffic, the packets are either arriving on another interface or not matching the ACL.
debug ip policy output looks like this (exact wording varies by release):
IP: s=10.4.20.1 (GigabitEthernet0/0), d=10.255.255.5, len 100, FIB policy match
IP: s=10.4.20.1 (GigabitEthernet0/0), d=10.255.255.5, g=10.1.3.2, len 100, FIB policy routed
IP: s=10.4.10.1 (GigabitEthernet0/0), d=10.255.255.5, len 100, FIB policy rejected(no match) - normal forwarding
"Policy match" plus "policy routed" with a g= gateway means PBR forwarded the packet. "Policy rejected" means the packet was routed normally, either because it matched nothing or because the next hop was unusable.
Troubleshooting PBR¶
| Symptom | Likely cause | Check |
|---|---|---|
| Counter stays at 0, traffic uses normal path | Policy on the wrong interface (egress, or a different ingress) | show ip policy, where the traffic actually arrives |
| Counter stays at 0, policy on the right interface | ACL matches the wrong field (destination instead of source), wrong wildcard, wrong protocol | show access-lists, compare with real flows |
| Counter increases but path is unchanged | Next hop not directly connected, track down, or set ip default next-hop with a specific route in the RIB |
show route-map (look for [down]), show track, show ip route DEST |
| Policy works for hosts, not for router pings | Testing with router-generated traffic | Test from a host, or add ip local policy |
| Traffic black-holed after an upstream failure | Plain set ip next-hop, interface stays up |
Add verify-availability with IP SLA tracking |
| Return traffic takes a different path | PBR is one-way; the remote side routes back normally | Traceroute from both ends; asymmetric paths may break stateful firewalls |
| Some matched traffic dropped on purpose by design but other traffic affected | Overly broad ACL with set interface Null0 |
ACL hit counts |
Exam trap
Route-map name typos are silent. ip policy route-map GUEST_PBR referencing a route map that does not exist (the real one is GUEST-PBR) is accepted, and every packet is routed normally. Compare the name in show ip policy with the names in show route-map.
PBR also affects only the router where it is configured. If R1 policy-routes guest traffic to R3, but R3's own routing table sends that destination back to R1, you get a loop between them. Always confirm that the PBR next hop has a sensible route onward to the destination.
Lab: guest traffic over the backup carrier¶
Topology: five IOSv routers. R4 simulates the LAN with two loopbacks: staff 10.4.10.0/24 and guests 10.4.20.0/24. R1 is the edge. R2 is the primary carrier and R3 the backup carrier, both connecting to R5, which simulates the Internet with Loopback0 10.255.255.5. OSPF area 0 runs everywhere, and R1's Gi0/2 cost is raised so normal routing prefers R2.
graph LR
R4["R4 LAN<br/>Lo10 10.4.10.1/24 staff<br/>Lo20 10.4.20.1/24 guest"] -- "Gi0/0 .2 10.1.4.0/30 .1 Gi0/0" --- R1["R1 edge<br/>PBR on Gi0/0"]
R1 -- "Gi0/1 .1 10.1.2.0/30 .2 Gi0/1" --- R2["R2 primary"]
R1 -- "Gi0/2 .1 10.1.3.0/30 .2 Gi0/1<br/>OSPF cost 100" --- R3["R3 backup"]
R2 -- "Gi0/2 .1 10.2.5.0/30 .2 Gi0/1" --- R5["R5 Internet<br/>Lo0 10.255.255.5"]
R3 -- "Gi0/2 .1 10.3.5.0/30 .2 Gi0/2" --- R5
Requirement: guest traffic (source 10.4.20.0/24) must use R3. Staff traffic follows normal routing through R2. If R3 stops answering, guest traffic must fall back to normal routing.
Build¶
- Address all links as shown and run
router ospf 1withnetwork 10.0.0.0 0.255.255.255 area 0on every router. Setip ospf cost 100on R1 Gi0/2. - Verify that
show ip route 10.255.255.5on R1 points to 10.1.2.2 only. - Configure the IP SLA, track, ACL and route map from the configuration example above on R1, and apply
ip policy route-map GUEST-PBRon R1 Gi0/0. - Save the working configuration:
copy running-config flash:pbr-good.cfg.
Verify the baseline¶
R4# traceroute 10.255.255.5 source Loopback20 numeric
Type escape sequence to abort.
Tracing the route to 10.255.255.5
VRF info: (vrf in name/id, vrf out name/id)
1 10.1.4.1 1 msec 1 msec 1 msec
2 10.1.3.2 2 msec 1 msec 1 msec
3 10.3.5.2 2 msec * 2 msec
R4# traceroute 10.255.255.5 source Loopback10 numeric
Type escape sequence to abort.
Tracing the route to 10.255.255.5
VRF info: (vrf in name/id, vrf out name/id)
1 10.1.4.1 1 msec 1 msec 1 msec
2 10.1.2.2 1 msec 1 msec 1 msec
3 10.2.5.2 2 msec * 2 msec
Guest traffic takes R3 and staff traffic takes R2. show route-map GUEST-PBR shows the counter increasing and the track [up].
Break and fix¶
Have a lab partner apply one fault at a time, or apply it yourself and wait a minute before looking. Restore the baseline between faults with configure replace flash:pbr-good.cfg force.
- Fault: on R1,
interface GigabitEthernet0/0,no ip policy route-map GUEST-PBR, theninterface GigabitEthernet0/2,ip policy route-map GUEST-PBR.- Symptom: the guest traceroute now goes through 10.1.2.2. The route-map counter stops increasing.
- Diagnosis:
show ip policylists Gi0/2. Guest packets arrive on Gi0/0, so the policy never sees them. - Fix: move the policy back to Gi0/0.
- Fault: on R1,
ip sla 10,icmp-echo 10.1.3.20 source-interface GigabitEthernet0/2(re-create the operation with a wrong target and reschedule it).- Symptom: guest traffic uses R2 even though R3 is healthy.
- Diagnosis:
show route-map GUEST-PBRshows[down]next to the next hop, andshow track 10shows "Reachability is Down".show ip sla statistics 10reports timeouts. PBR is behaving correctly for a down track: it falls back to normal routing. - Fix: correct the probe target to 10.1.3.2.
- Fault: on R1, replace the ACL line with
permit ip any 10.4.20.0 0.0.0.255.- Symptom: guest traffic uses R2. The route-map counter is frozen, but the track is up.
- Diagnosis:
show access-lists GUEST-SRCshows zero hits. The ACL matches the guest subnet as a destination, but packets arriving on Gi0/0 have it as their source. - Fix:
permit ip 10.4.20.0 0.0.0.255 any.
- Failover test: with the baseline restored, simulate a carrier fault that keeps R1's link up. On R3, create
ip access-list extended CARRIER-DOWNwithdeny ip any anyand apply it withip access-group CARRIER-DOWN inon Gi0/1.- With tracking: after the next probe times out (5 to 10 seconds with a 5-second frequency)
show track 10goes down, the route map shows[down], and the guest traceroute moves to R2. - Now restore the baseline, change the set clause to a plain
set ip next-hop 10.1.3.2, and repeat. R1 Gi0/2 stays up/up, so PBR keeps sending guest packets to R3 and they are dropped. The OSPF adjacency to R3 dies after the 40-second dead interval, but that does not matter: PBR does not consult OSPF, only the connected interface state. - Remove the ACL on R3 and restore the baseline.
- With tracking: after the next probe times out (5 to 10 seconds with a 5-second frequency)
Lesson from step 4
A plain set ip next-hop only reacts to the local interface going down. Tracking reacts to the next hop failing to answer. It still only proves the first hop is alive, so in production you track something that represents the whole path, and force the probe out the tracked link.
Quick check¶
A route map used for PBR has one sequence, route-map PBR deny 10 with match ip address 101. A packet matches ACL 101. What happens to it?
It is routed normally using the destination lookup. In PBR, a deny sequence means "do not policy route", not "drop". To drop traffic with PBR you need a permit sequence with set interface Null0.
Why does show route-map show a non-zero match counter while traceroute proves the traffic still follows the routing table?
The packets match the sequence, but the set clause is not usable. Typical causes are a tracked next hop in [down] state, a set ip next-hop address that is not directly connected, or set ip default next-hop when the RIB has a specific route for the destination.
Which command makes the router's own syslog messages follow a PBR policy?
ip local policy route-map NAME in global configuration. The interface ip policy command only acts on packets received on that interface.
References¶
- Cisco IOS XE IP Routing configuration guide, "Policy-Based Routing" and "PBR Support for Multiple Tracking Options" chapters: search on cisco.com
- Cisco IOS XE IP SLAs configuration guide: search "IP SLAs ICMP Echo Operation" on cisco.com
- Cisco Live On-Demand Library: search "policy based routing" and "ENARSI"
- Related practice: PBR next-hop decision diagram, Sim 08 fault 2
Unlock the full question banks and cram sheets
A free account opens every question bank, the timed practice exams, the printable cram sheets, all the simulations and the lab files. Without one you see a 5-question sample of each.
No card needed. Study tips by email are optional and off unless you tick the box. Your address is never sold or shared. Privacy policy ยท Terms
Signed in as . Your account
You're on the free account, so lessons after the first module, question banks, exams and cram sheets show a sample. See Track Pass and All-Access
Also from NetManager Systems: NetManager, network monitoring for multi-vendor networks. Try the NetManager, NetDiag, PCAP Analyzer and OpsDash demos: every new account gets a free 7-day read-only login to each.