Skip to main content
RunBook Academy

VyOSXXXIII · Route PolicyRoute-map composition

Route-map composition — match and set clauses, sequence ordering, implicit deny

Advanced⏱ ~28 minvyosvtyshset policy route-mapshow policy route-mapvtysh -c show route-mapvtysh -c show ip bgp route-map

What you'll learn

  • Configure a route-map with match and set clauses on VyOS 1.5 LTS
  • Predict the AND/OR semantics of multi-clause match statements
  • Use set clauses to manipulate BGP attributes (community, local-preference, metric, as-path prepend, next-hop)
  • Recognise the implicit-deny on no-match and design a route-map that is auditable

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.

The route-map is the policy primitive that does two things no other primitive can: it matches a route against multiple criteria, and it manipulates the route’s attributes. Every BGP neighbour policy, every redistribution filter, and every complex policy decision in production is implemented with a route-map.

On VyOS 1.5 LTS the route-map is composed of numbered rules; each rule has an action (permit or deny), one or more match clauses, and zero or more set clauses. The route-map evaluates rules top-to-bottom by sequence; the first rule that matches the route decides the disposition; later rules are not consulted.

This lesson covers the match and set semantics, the sequence ordering, and the implicit-deny behaviour that distinguishes route-maps from prefix-lists.

Anatomy of a route-map rule

A route-map rule has four parts:

  • sequence number — positive integer that orders the rule in the route-map. Lower numbers evaluate first.
  • actionpermit (apply set clauses, continue to next route) or deny (do not apply set clauses, route is filtered).
  • match clause — one or more criteria the route must satisfy for the rule to fire. The criteria combine with AND across types and OR within a type.
  • set clause — one or more attribute manipulations applied to the route when the rule fires. Set clauses are only applied if the rule’s action is permit.
set policy route-map OSPF-TO-BGP rule 10 action permit
set policy route-map OSPF-TO-BGP rule 10 match ip address prefix-list INTERNAL-NETWORKS
set policy route-map OSPF-TO-BGP rule 10 match community FROM-IGP
set policy route-map OSPF-TO-BGP rule 10 set metric 100
set policy route-map OSPF-TO-BGP rule 10 set community 64512:400 additive

This rule:

  • Has sequence 10, action permit.
  • Matches routes whose prefix is in the INTERNAL-NETWORKS prefix-list AND whose community is in the FROM-IGP community-list.
  • On a match, sets the metric to 100 and adds the community 64512:400 to the route’s community-set (additive).
flowchart TB
  R["Route\nprefix, AS_PATH, community, ..."]
  L1{"Sequence 10\nmatches?"}
  L2{"Sequence 20\nmatches?"}
  L3{"Sequence 30\nmatches?"}
  P10["Action permit\nApply set clauses\nRoute continues"]
  D10["Action deny\nRoute is filtered"]
  P20["Action permit\nApply set clauses\nRoute continues"]
  D20["Action deny\nRoute is filtered"]
  X["Implicit deny\n(no rule matched)\nRoute is filtered"]

  R --> L1
  L1 -->|"yes, action permit"| P10
  L1 -->|"yes, action deny"| D10
  L1 -->|"no"| L2
  L2 -->|"yes, action permit"| P20
  L2 -->|"yes, action deny"| D20
  L2 -->|"no"| L3
  L3 -->|"yes, action permit"| P30
  L3 -->|"yes, action deny"| D30
  L3 -->|"no"| X

The first matching rule wins. If no rule matches, the implicit-deny applies: the route is filtered.

Match semantics — AND across types, OR within type

A route-map rule with multiple match clauses combines them with AND across types and OR within a type:

  • AND across typesmatch ip address prefix-list FOO AND match community BAR means the route must satisfy both: the prefix must be in FOO AND the community must match BAR. If either fails, the rule does not fire.
  • OR within typematch ip address prefix-list FOO and match ip address prefix-list BAZ on the same rule (if supported by the configuration tree) mean the route’s prefix must be in FOO or BAZ. The VyOS configuration tree typically allows one match ip address per rule; the operator who needs OR uses two rules with different sequences.
flowchart TB
  R["Route\nprefix: 10.0.0.0/16\ncommunity: 64512:100 64512:200"]
  M1["match ip address prefix-list INTERNAL\nmatches: 10.0.0.0/16 (yes)"]
  M2["match community FROM-IGP\nmatches: 64512:100 (yes)\nor 64512:200 (yes)\n=> permit (any-community semantic)"]
  AND["AND across types:\nboth M1 AND M2\n=> rule fires"]
  P["Action permit\nset metric 100\nset community 64512:400 additive"]

  R --> M1
  R --> M2
  M1 --> AND
  M2 --> AND
  AND -->|"both true"| P

The OR-within-type applies to community-lists (any community on the route matches), as-path access-lists (the AS_PATH matches the regex), and prefix-lists with ge or le (the prefix is in the range).

Set clauses — what the rule does to the route

A set clause writes an attribute back to the route. The set clauses are only applied if the rule’s action is permit (a deny action does not apply set clauses; the route is filtered).

The common set clauses on VyOS 1.5 LTS:

# Metric (BGP MED)
set policy route-map ... set metric <value>

# Local preference (iBGP only)
set policy route-map ... set local-preference <value>

# AS path prepend (BGP)
set policy route-map ... set as-path prepend <AS> [<AS> ...]

# Community (additive: adds to existing community-set;
# non-additive: replaces the community-set)
set policy route-map ... set community <AA:NN> [additive]
set policy route-map ... set community none

# Next-hop (eBGP)
set policy route-map ... set ip next-hop <IP>
set policy route-map ... set ip next-hop peer-address

# Origin (BGP)
set policy route-map ... set origin igp
set policy route-map ... set origin incomplete
set policy route-map ... set origin egp

# Weight (Cisco-style, VyOS exposes it as a BGP-specific option)
set policy route-map ... set weight <value>

The additive keyword on set community is critical: it adds the community to the route’s existing community-set; without additive, the community-set is replaced. The operator who forgets additive strips every community the upstream peer added — including the well-known no-export that was protecting downstream peers.

Sequence ordering and the implicit deny

The route-map evaluates rules top-to-bottom by sequence number. The first rule that matches the route (the match clauses evaluate to true) decides the disposition:

  • If the rule’s action is permit, the set clauses are applied; the route is permitted; later rules are not consulted.
  • If the rule’s action is deny, the set clauses are NOT applied; the route is filtered; later rules are not consulted.

If no rule matches the route, the implicit deny applies: the route is filtered.

The implicit deny at the end of a route-map is the opposite of the implicit deny in a prefix-list. A prefix-list that falls off the end denies the route; a route-map that falls off the end also denies the route. But the semantics differ:

  • A prefix-list with no explicit permit denies everything (the implicit deny is the safety net).
  • A route-map with no explicit permit denies everything (the implicit deny is the default behaviour).

The difference shows up when the operator writes a route-map with a deny rule followed by an implicit deny. The deny rule matches explicitly; the implicit deny catches everything else. The behaviour is the same as a prefix-list with an explicit deny at the end.

# Production pattern: deny bad, permit good
set policy route-map FROM-PEER-A rule 10 action deny
set policy route-map FROM-PEER-A rule 10 match ip address prefix-list BLOCK-LIST

set policy route-map FROM-PEER-A rule 20 action permit
set policy route-map FROM-PEER-A rule 20 match ip address prefix-list ALLOW-LIST

# No rule 30 or higher — implicit deny catches everything else

The operator who writes only deny rules and expects the rest to be permitted is wrong. The route-map falls off the end and the implicit deny applies. The defensive idiom is to write a catch-all permit at the end (rule 100 or higher).

Operational commands

# The configured route-map
show policy route-map FROM-PEER-A

# The matching engine's view (FRR)
vtysh -c 'show route-map'
vtysh -c 'show route-map FROM-PEER-A'

# Routes that matched the route-map (and what was applied)
vtysh -c 'show ip bgp route-map FROM-PEER-A'

# Clear the hit counts
clear route-map

The show ip bgp route-map <name> command is the canonical validation: it shows every route that the route-map processed and the set clauses that were applied. The operator who has just written a new rule should run this command to confirm the rule is firing on the intended routes and not firing on unintended routes.

Failure modes

Multi-clause match with one clause failing

The operator writes a rule with two match clauses. The route matches the first clause but not the second. The AND across types means the rule does not fire. The route falls through to the next rule (or the implicit deny).

Diagnostic:

  • vtysh -c 'show route-map <name>' shows the hit count for the rule is zero (or lower than expected).
  • show ip bgp route-map <name> does not include the expected routes.

Fix: simplify the match (one clause), or add another rule that matches the second clause alone.

set community without additive strips communities

The operator writes set community 64512:400 without additive. The community-set is replaced with 64512:400. The receiving peer loses the original communities.

Diagnostic:

  • show ip bgp <prefix> shows the community-set is just 64512:400. The original communities are gone.

Fix: change to set community 64512:400 additive.

Catch-all permit missing; route-map filters everything

The operator writes a route-map with permit rules but no catch-all permit. The implicit deny at the end filters every route that does not match a permit rule. The redistribution becomes a blackhole.

Diagnostic:

  • show ip bgp shows no routes (or only the ones that matched a permit rule).
  • show ip route shows the routes are not in the RIB.

Fix: add a catch-all permit at the end of the route-map.

Sequence reordering breaks the rule

The operator writes rule 10 permitting INTERNAL-NETWORKS and rule 20 denying EXCEPTIONS. The operator later inserts rule 15 permitting NEW-INTERNAL. The matching engine walks 10 → 15 → 20. The new rule 15 fires before the deny. Routes that were supposed to be denied by rule 20 are permitted by rule 15.

Diagnostic:

  • Routes that should be denied are permitted.
  • show policy route-map shows the new rule 15 is more general than rule 20’s match.

Fix: reorder so the deny fires before the permit, or make rule 15’s match more specific.

Rollback

A route-map change is reversible through the standard VyOS mechanisms:

  • rollback N and commit to revert to a previous configuration revision.
  • delete policy route-map <name> and commit to remove the route-map. The referencing BGP neighbour or redistribution is left dangling; the commit validator catches this.
  • delete policy route-map <name> rule <seq> and commit to remove a single rule.
  • set policy route-map <name> rule <seq> action permit (override the deny) to permit everything during a debugging window — restore after.

The VyOS commit validator rejects a BGP neighbour or redistribution that references a missing route-map.

Production discipline

Cross-course references

  • XIII-VyOS-PBR (vyos-xiii-02-route-maps) covers route-maps in the policy-based-routing context. The match and set semantics are the same.
  • XXV-VyOS-BGPAdvertise (vyos-xxv-03-bgp-redistribute-static, vyos-xxv-04-bgp-redistribute-ospf) shows route-maps in the BGP redistribution context.
  • XXVI-VyOS-BGPAttributes covers the BGP attributes that route-maps manipulate: community, local-preference, as-path prepend.

Quiz

Knowledge check · 4 questions

  1. Q1. A route-map rule has `match ip address prefix-list FOO` and `match community BAR`. A route matches FOO but does not match BAR. What is the disposition?

  2. Q2. A `set community 64512:400` clause without `additive` adds the community to the route's existing community-set.

  3. Q3. An operator writes a route-map with rule 10 denying routes in prefix-list BLOCK-LIST and rule 20 permitting routes in prefix-list ALLOW-LIST. They apply it to inbound from a peer. The peer sends 100 routes; 50 are in ALLOW-LIST, 5 are in BLOCK-LIST, and 45 are in neither. After the commit, 5 routes are in the BGP table. What happened?

    The route-map is: rule 10 deny BLOCK-LIST, rule 20 permit ALLOW-LIST. The peer sends 100 routes. The 45 routes that are in neither list do not match any rule.

  4. Q4. An operator writes a route-map rule with `set community 64512:400` (no `additive`) intending to tag routes from the IGP. The upstream peer stamps the routes with `no-export` to prevent leakage. After the commit, `show ip bgp` shows the routes are advertised to the downstream peer (no longer protected by `no-export`). Why?

    The route-map is applied inbound from the IGP redistribution. The set clause is `set community 64512:400` (no additive). The routes had `no-export` from the upstream peer.

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