VyOSXIII · Policy-Based RoutingPolicy-based routing
Route-maps — match clauses and set clauses for PBR
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
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:
- Action —
permitaccepts the packet/route and applies the set clauses.denyrejects the packet/route and stops evaluation. - 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).
- 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 clause | What it matches |
|---|---|
match ip address prefix-list PL | Destination address is in prefix-list PL |
match ip source address prefix-list PL | Source address is in prefix-list PL |
match ip destination prefix-list PL | Destination address is in prefix-list PL (alias for match ip address) |
match ip next-hop address A.B.C.D | BGP next-hop equals A.B.C.D (BGP context only) |
match interface IFNAME | Packet arrived on interface IFNAME |
match metric 0-4294967295 | Route metric equals the value (BGP/OSPF context only) |
match community COMMUNITY | BGP community matches (BGP context only) |
match ip address access-list ACL | Destination 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 clause | Effect |
|---|---|
set ip next-hop A.B.C.D | IPv4 next-hop for the route |
set ipv6 next-hop X:X::X | IPv6 next-hop for the route |
set ip next-hop A.B.C.D (multiple) | ECMP next-hops (load-sharing) |
set metric 0-4294967295 | Route metric |
set local-preference 0-4294967295 | BGP local-preference (BGP context only) |
set community 65001:100 | BGP community (BGP context only) |
set community additive 65001:100 | Append to existing community |
set ip vrf VRFNAME | Set the route’s VRF (route leaking) |
set ip table N | Set the routing table for the route |
set src A.B.C.D | Source 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
permitrule per traffic class, with the appropriate match and set clauses. - No
denyrule — 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
Q1. How are multiple match clauses in the same route-map rule combined?
Q2. In a route-map, an `action deny` rule applies its `set` clauses to the packet or route before rejecting it.
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.
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.