Skip to main content
RunBook Academy

VyOSXIII · Policy-Based RoutingPolicy-based routing

Route-maps — match clauses and set clauses for PBR

Advanced⏱ ~22 minset policy route-mapset policy prefix-listshow policy route-mapshow policy prefix-listip rule showip route show table allvyosvtysh

What you'll learn

  • Configure a route-map with match and set clauses for PBR in VyOS 1.5 LTS
  • Explain rule-evaluation order and the role of sequence numbering
  • Distinguish `permit` from `deny` and the empty-match implicit deny
  • Recognise the production failure modes that arise from incorrect route-map ordering

Prerequisites

Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling) · 2026-08-15

Not yet marked complete on this device.

Route-maps — match clauses and set clauses for PBR

A route-map is a named, ordered sequence of rules. Each rule has a sequence number, an action (permit or deny), a set of match clauses, and a set of set clauses. When FRR evaluates a route-map, it walks the rules in sequence-number order and applies the first match. If the action is permit, the route is accepted and the set clauses are applied; if the action is deny, the route is rejected and evaluation stops. The rule model is the same whether the route-map is used for BGP policy, OSPF redistribution, or PBR — only the match and set clauses differ.

VyOS 1.5 LTS exposes the route-map through the set policy route-map tree. The configuration renders to FRR’s route-map block, which zebra installs as ip rule entries when the route-map is bound to an interface. This lesson walks through the syntax, the match clauses the PBR operator uses most often, the set clauses the PBR operator uses most often, and the production failure modes that arise from incorrect rule ordering.

Route-map syntax — what a rule looks like

set policy route-map <NAME> rule <N> action <permit|deny>
set policy route-map <NAME> rule <N> match <criteria>
set policy route-map <NAME> rule <N> set <attribute>

A rule has three parts:

  1. Actionpermit accepts the packet/route and applies the set clauses. deny rejects the packet/route and stops evaluation.
  2. Match — the criteria that select which packets/routes this rule applies to. Multiple match clauses in the same rule are AND-ed (all must match for the rule to apply).
  3. Set — the attributes that are applied to the packet/route when the rule fires. Multiple set clauses in the same rule are all applied.

The sequence number <N> determines evaluation order. Rules are walked in ascending order; the first rule that matches wins. Lower numbers run first. The convention is to leave gaps (10, 20, 30) so future rules can be inserted without renumbering.

flowchart TD
  P[Packet or route] --> R1{Rule 10<br/>match?}
  R1 -->|yes| A1{Action}
  A1 -->|permit| S1[Apply set clauses]
  A1 -->|deny| REJ[Reject<br/>evaluation stops]
  R1 -->|no| R2{Rule 20<br/>match?}
  R2 -->|yes| A2{Action}
  A2 -->|permit| S2[Apply set clauses]
  A2 -->|deny| REJ
  R2 -->|no| R3{Rule 30<br/>match?}
  R3 -->|yes| A3{Action}
  A3 -->|permit| S3[Apply set clauses]
  A3 -->|deny| REJ
  R3 -->|no| END[Implicit deny<br/>no further action]

A canonical PBR route-map

The canonical example: route the voice subnet (10.10.0.0/24) out the voice provider (198.51.100.1), and let everything else fall through to the main table.

configure
set policy prefix-list PL-VOICE-SRC rule 10 action permit
set policy prefix-list PL-VOICE-SRC rule 10 prefix '10.10.0.0/24'
set policy route-map RM-VOICE-OUT rule 10 action permit
set policy route-map RM-VOICE-OUT rule 10 match ip source address prefix-list PL-VOICE-SRC
set policy route-map RM-VOICE-OUT rule 10 set ip next-hop '198.51.100.1'
commit
save

The PL-VOICE-SRC prefix-list matches the source subnet. The RM-VOICE-OUT route-map has one rule at sequence 10 that permits traffic matching the source prefix and sets the next-hop. The implicit deny at the end of the route-map rejects everything else; that traffic falls through to the main table because the route-map has no deny action that would change the behaviour of the implicit deny.

The VyOS render of this configuration in FRR:

ip prefix-list PL-VOICE-SRC seq 10 permit 10.10.0.0/24
route-map RM-VOICE-OUT permit 10
  match ip source-address prefix-list PL-VOICE-SRC
  set ip next-hop 198.51.100.1

Match clauses the PBR operator uses

The match clauses relevant to PBR in VyOS 1.5 LTS:

Match clauseWhat it matches
match ip address prefix-list PLDestination address is in prefix-list PL
match ip source address prefix-list PLSource address is in prefix-list PL
match ip destination prefix-list PLDestination address is in prefix-list PL (alias for match ip address)
match ip next-hop address A.B.C.DBGP next-hop equals A.B.C.D (BGP context only)
match interface IFNAMEPacket arrived on interface IFNAME
match metric 0-4294967295Route metric equals the value (BGP/OSPF context only)
match community COMMUNITYBGP community matches (BGP context only)
match ip address access-list ACLDestination address matches ACL

The match ip address and match ip source address clauses are the workhorses of PBR. The match interface clause lets the operator apply different policies to traffic arriving on different interfaces — a common multi-WAN pattern.

configure
set policy route-map RM-VOICE-OUT rule 10 action permit
set policy route-map RM-VOICE-OUT rule 10 match interface 'eth1'
set policy route-map RM-VOICE-OUT rule 10 match ip source address prefix-list PL-VOICE-SRC
set policy route-map RM-VOICE-OUT rule 10 set ip next-hop '198.51.100.1'
commit
save

The two match clauses are AND-ed: the rule applies only to traffic that arrives on eth1 and has a source in PL-VOICE-SRC. This is a tighter policy than the source-only match — traffic arriving on eth0 is not affected even if its source is in the voice subnet.

Set clauses the PBR operator uses

The set clauses relevant to PBR in VyOS 1.5 LTS:

Set clauseEffect
set ip next-hop A.B.C.DIPv4 next-hop for the route
set ipv6 next-hop X:X::XIPv6 next-hop for the route
set ip next-hop A.B.C.D (multiple)ECMP next-hops (load-sharing)
set metric 0-4294967295Route metric
set local-preference 0-4294967295BGP local-preference (BGP context only)
set community 65001:100BGP community (BGP context only)
set community additive 65001:100Append to existing community
set ip vrf VRFNAMESet the route’s VRF (route leaking)
set ip table NSet the routing table for the route
set src A.B.C.DSource address for the forwarded packet

The set ip next-hop is the workhorse of PBR. The set metric and set local-preference clauses affect the route in dynamic protocols; in a pure PBR context the route is in a static table and these have no effect unless the route is redistributed.

configure
set policy route-map RM-DUAL-WAN rule 10 action permit
set policy route-map RM-DUAL-WAN rule 10 match ip source address prefix-list PL-VOICE-SRC
set policy route-map RM-DUAL-WAN rule 10 set ip next-hop '198.51.100.1'
set policy route-map RM-DUAL-WAN rule 20 action permit
set policy route-map RM-DUAL-WAN rule 20 match ip source address prefix-list PL-DATA-SRC
set policy route-map RM-DUAL-WAN rule 20 set ip next-hop '203.0.113.1'
commit
save

Two rules, two source subnets, two next-hops. The route-map sends voice traffic out provider-A and data traffic out provider-B.

The sequence number is the production lever

The sequence number is the order in which rules are evaluated. Lower numbers run first. If two rules match the same packet, the lower-numbered rule wins.

configure
set policy route-map RM-OVERRIDE rule 10 action permit
set policy route-map RM-OVERRIDE rule 10 match ip source address prefix-list PL-MGMT
set policy route-map RM-OVERRIDE rule 10 set ip next-hop '10.99.0.1'
set policy route-map RM-OVERRIDE rule 20 action permit
set policy route-map RM-OVERRIDE rule 20 match ip source address prefix-list PL-DEFAULT
set policy route-map RM-OVERRIDE rule 20 set ip next-hop '203.0.113.1'
commit
save

The RM-OVERRIDE route-map has two rules. Rule 10 matches the management subnet first. If the source is in PL-MGMT, the route-map sets next-hop to 10.99.0.1 and stops. Rule 20 is only evaluated if rule 10 did not match.

The convention of leaving gaps (10, 20, 30) lets the operator insert a rule between two existing rules without renumbering. Inserting a new rule at sequence 15 places it between rule 10 and rule 20.

Permit vs deny

The action permit accepts and applies set clauses. The action deny rejects and stops evaluation. A route-map with no rule matching a packet is an implicit deny — the packet falls through to the main table (or the next feature in the chain).

For PBR, the typical pattern is:

  • One permit rule per traffic class, with the appropriate match and set clauses.
  • No deny rule — the implicit deny handles the fall-through.

A deny rule is appropriate when the operator wants to block a traffic class. In a PBR context, that usually means setting the next-hop to a blackhole route or to a discard interface.

configure
set policy route-map RM-WITH-BLOCK rule 10 action permit
set policy route-map RM-WITH-BLOCK rule 10 match ip source address prefix-list PL-ALLOW
set policy route-map RM-WITH-BLOCK rule 10 set ip next-hop '198.51.100.1'
set policy route-map RM-WITH-BLOCK rule 20 action deny
set policy route-map RM-WITH-BLOCK rule 20 match ip source address prefix-list PL-BLOCK
commit
save

Rule 10 allows traffic from PL-ALLOW. Rule 20 denies traffic from PL-BLOCK and stops evaluation — the traffic is not subjected to any further rule in this route-map. Traffic from sources not in either prefix-list falls through to the implicit deny and is treated as if the route-map did not exist.

Multi-rule ECMP via route-map

A route-map can set multiple next-hops in the same rule, creating an ECMP group:

configure
set policy route-map RM-LOAD-SHARE rule 10 action permit
set policy route-map RM-LOAD-SHARE rule 10 match ip source address prefix-list PL-DATA
set policy route-map RM-LOAD-SHARE rule 10 set ip next-hop '203.0.113.1'
set policy route-map RM-LOAD-SHARE rule 10 set ip next-hop '203.0.113.2'
commit
save

The two set ip next-hop clauses in the same rule create an ECMP group with two next-hops. The kernel load-balances traffic from PL-DATA across the two providers. This is the per-flow load share — the kernel hashes the 5-tuple and picks one next-hop per flow, so each flow takes a single path but different flows take different paths.

How the configuration is validated

The validation command set confirms the route-map is correct:

show policy route-map
show policy route-map RM-VOICE-OUT
show policy prefix-list
show policy prefix-list PL-VOICE-SRC

The show policy route-map lists all configured route-maps. The show policy route-map RM-VOICE-OUT shows the rules, matches, and sets for the specific route-map. The show policy prefix-list lists all prefix-lists; the show policy prefix-list PL-VOICE-SRC shows the rules for the specific prefix-list.

The FRR view:

vtysh -c 'show running-config'
vtysh -c 'show route-map RM-VOICE-OUT'
vtysh -c 'show ip prefix-list'

The FRR show route-map shows the route-map with the sequence numbers and the per-rule counters. The counters increment for every rule evaluation; the operator can compare them to the expected traffic volume to verify the rule is firing.

The data-plane view (after the route-map is bound to an interface):

ip rule show
ip route show table 100
ip route get 8.8.8.8 from 10.10.0.5

The ip rule show contains the rule installed by the route-map binding. The ip route show table 100 shows the PBR table populated by the route-map. The ip route get from the voice source returns the PBR next-hop.

How it fails

The production failure modes the engineer must recognise:

  • Wrong rule order. Rule 20 matches the management subnet, rule 10 matches the same subnet with a different next-hop. Rule 10 wins; the management traffic uses the wrong next-hop.
  • Permit/deny reversed. A rule intended to allow traffic is configured with action deny. The traffic is rejected; the set clauses never fire.
  • Empty match clause. A rule has no match clause, so it matches everything. The set clauses apply to all traffic. The route-map becomes a blanket policy.
  • Prefix-list typo. The prefix-list has a typo’d prefix. The traffic that should match does not match. The PBR rule never fires.
  • Sequence gap. The operator inserts a rule at sequence 5 when existing rules start at sequence 10. Rule 5 fires first even if it was intended to be a fallback.

Rollback

The recovery from a bad route-map:

  • Wrong rule order: delete policy route-map <name> rule <n>; set policy route-map <name> rule <new-n> ...; commit; save.
  • Permit/deny reversed: set policy route-map <name> rule <n> action <correct>; commit; save.
  • Prefix-list typo: set policy prefix-list <name> rule <n> prefix <correct>; commit; save.
  • Whole-tree rollback: rollback N; commit; save.

Production discipline

Cross-course references

The Linux course’s XIX-Linux-NetFoundations covers the kernel FIB and the rule selector that route-maps feed into. The VyOS lessons vyos-xiii-01-pbr-concept, vyos-xiii-03-pbr-rules, and vyos-xiii-05-pbr-troubleshoot cover the PBR use of route-maps. The lessons vyos-xxviii-01-prefix-list-concept, vyos-xxviii-02-prefix-list-config, vyos-xxviii-03-distribute-list, and vyos-xxviii-04-filter-list cover the BGP prefix-filtering use of route-maps. The lesson vyos-xxvi-01-local-preference covers the BGP attribute that the set local-preference clause manipulates.

Quiz

Knowledge check · 4 questions

  1. Q1. How are multiple match clauses in the same route-map rule combined?

  2. Q2. In a route-map, an `action deny` rule applies its `set` clauses to the packet or route before rejecting it.

  3. Q3. An operator configures a route-map with rule 10 (voice subnet -> provider-A) and rule 20 (data subnet -> provider-B). The voice traffic still goes out provider-B. What is the most likely cause?

    The route-map has two rules. Rule 10 matches the voice subnet and sets next-hop to provider-A. Rule 20 matches the data subnet and sets next-hop to provider-B. The voice traffic is going out provider-B, which means rule 20 is firing for the voice traffic. The most likely cause is a typo in the prefix-list — the voice traffic is matching the data prefix-list instead of the voice prefix-list.

  4. Q4. An operator wants two source subnets to share the same next-hop. The operator writes `match ip source address prefix-list PL-A` and `match ip source address prefix-list PL-B` in the same rule. The rule never fires. Why?

    The operator intended OR semantics — match either of two source subnets. The VyOS route-map treats multiple match clauses as AND. The rule fires only if the source is in BOTH PL-A and PL-B simultaneously, which is impossible. The rule never fires.

Passing score: 75%. Answers are checked in this browser.