Skip to main content
RunBook Academy

VyOSXXXIII · Route PolicyPolicy validation

Policy validation — testing with vtysh, clearing route-maps, sequence numbering gotchas

Advanced⏱ ~20 minvyosvtyshshow policyshow ip prefix-listshow bgp community-listshow bgp as-path-access-listshow route-mapclear ip prefix-listclear bgp community-listclear bgp as-path-access-listclear route-map

What you'll learn

  • Run the vtysh show commands that validate each policy primitive
  • Use the clear commands to reset hit counts during testing
  • Recognise the sequence-numbering gotchas that cause silent policy bypass
  • Build a validation sequence that proves a policy change is correct before commit

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.

A policy change that passes validation but does not do what the operator intended is a silent failure. The routes are in the BGP table, the commit succeeded, the configuration is syntactically correct — but the prefix the operator wanted to block is being advertised, or the route the operator wanted to permit is being denied. The operator who validates the policy with the right commands catches these failures before they affect production traffic.

This lesson covers the validation sequence for each policy primitive, the clear commands that reset hit counts during testing, and the sequence-numbering gotchas that cause silent policy bypass.

The validation sequence

The canonical validation sequence after a policy change is:

# 1. The configuration is in the tree (VyOS)
show policy route-map
show policy prefix-list
show policy community-list
show policy as-path-list

# 2. The matching engine has loaded the policy (FRR)
vtysh -c 'show route-map'
vtysh -c 'show ip prefix-list'
vtysh -c 'show bgp community-list'
vtysh -c 'show bgp as-path-access-list'

# 3. The policy is doing what the operator intended
vtysh -c 'show ip bgp route-map <name>'
vtysh -c 'show ip bgp filter-list <name>'
vtysh -c 'show ip bgp community <value> exact-match'

# 4. The hit counts match expectations
vtysh -c 'show route-map <name>'   # per-rule hit count
vtysh -c 'show ip prefix-list <name>'   # per-rule hit count

# 5. The route-map and prefix-list agree on the same prefix
vtysh -c 'show ip prefix-list <name> <prefix>'
vtysh -c 'show route-map <name> <prefix>'   # if supported

If steps 1 and 2 disagree, the configuration has not been committed or the commit failed silently. If steps 2 and 3 disagree, the matching engine is not processing the policy correctly. If steps 3 and 4 disagree, the policy is doing something the operator did not expect.

Validating a prefix-list

# The configured list (VyOS)
show policy prefix-list INBOUND

# The matching engine's view (FRR)
vtysh -c 'show ip prefix-list'
vtysh -c 'show ip prefix-list INBOUND'

# The sequence and hit count per rule
vtysh -c 'show ip prefix-list INBOUND seq 10'

# Test a specific prefix against the list
vtysh -c 'show ip prefix-list INBOUND 192.168.1.0/24'

# Clear the hit counts
clear ip prefix-list

The show ip prefix-list <name> <prefix> command is the canonical validation. It returns permit or deny for the prefix against the list. The operator who has just written a new rule should run this command for every prefix the rule is supposed to match, and for at least one prefix the rule is supposed to reject.

The clear ip prefix-list command resets the hit counts. The operator who is testing a new rule should clear the counts before the test, run the test traffic, then read the counts to confirm the rule fired.

Validating a community-list

# The configured list (VyOS)
show policy community-list FROM-PEER-A

# The matching engine's view (FRR)
vtysh -c 'show bgp community-list'
vtysh -c 'show bgp community-list FROM-PEER-A'

# Routes carrying a specific community
vtysh -c 'show ip bgp community 64512:100'
vtysh -c 'show ip bgp community 64512:100 exact-match'

# Routes matching a regex
vtysh -c 'show ip bgp regexp "_64512:.*"'

# Clear the hit counts
clear bgp community-list

The show ip bgp community <value> command returns every route whose community-set contains <value>. The operator who has just stamped a new community should run this command to confirm the community is on the routes.

The clear bgp community-list command resets the hit counts for testing.

Validating an as-path access-list

# The configured list (VyOS)
show policy as-path-list MY-FILTER

# The matching engine's view (FRR)
vtysh -c 'show bgp as-path-access-list'
vtysh -c 'show bgp as-path-access-list MY-FILTER'

# Routes matching a regex
vtysh -c 'show ip bgp regexp _64513_'

# Routes filtered by the list
vtysh -c 'show ip bgp filter-list MY-FILTER'

# Clear the hit counts
clear bgp as-path-access-list

The show ip bgp filter-list <name> command is the canonical validation for an as-path access-list. It shows every route whose AS_PATH was processed by the list. The operator who has just written a new rule should run this command to confirm the filter is doing what it claims.

Validating a route-map

# The configured route-map (VyOS)
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 shows every route that the route-map processed and the set clauses that were applied. This is the most informative command for validating a complex route-map.

The clear route-map command resets the hit counts for testing.

Sequence-numbering gotchas

The most common production failure modes in policy are sequence-numbering errors. The matching engine walks rules top-to-bottom by sequence; the first matching rule wins; later rules are not consulted. The operator who writes a broad permit rule at a low sequence number catches every route that should have been denied by a specific rule at a higher sequence number.

Gotcha 1: rule 10 is too broad

# Intent: permit INTERNAL, deny EXCEPTIONS
set policy route-map ... rule 10 action permit
set policy route-map ... rule 10 match ip address prefix-list INTERNAL

set policy route-map ... rule 20 action deny
set policy route-map ... rule 20 match ip address prefix-list EXCEPTIONS

A route in EXCEPTIONS that is also in INTERNAL matches rule 10 first (because it is in INTERNAL). The route is permitted. Rule 20 is never consulted. The exception is silently bypassed.

Diagnostic:

  • show ip bgp route-map <name> shows routes in EXCEPTIONS that should be denied.
  • vtysh -c 'show route-map <name>' shows rule 10 has a hit count and rule 20 has zero hits (or low).

Fix: reorder the rules. Deny first, then permit.

Gotcha 2: the sequence is not what was intended

The operator writes rule 10 intending to permit and rule 20 intending to deny. After a set typo or a copy-paste error, the rule is at sequence 100 instead of 10. The matching engine walks 10, 20, 30, …, 100. The deny rule at 100 fires only after every permit rule has been evaluated. A route that matches a permit rule at sequence 10 is permitted, even if it should have been denied by the rule at sequence 100.

Diagnostic:

  • show policy route-map <name> shows the rule order.
  • vtysh -c 'show route-map <name>' shows the rule order.

Fix: delete the rule and re-create it at the correct sequence number. VyOS does not support set policy route-map <name> rule <seq> rule <new-seq> (no renumber); the operator must delete and re-set.

Gotcha 3: the rule’s match clause is not what was

intended

The operator writes match ip address prefix-list INTERNAL intending to match the prefix. The VyOS configuration tree parses this correctly. But the operator forgets that match ip address prefix-list matches the prefix AND the prefix length (a /24 in the prefix-list does not match a /16 route). The rule fires only for exact-length matches.

Diagnostic:

  • show ip bgp route-map <name> does not include the expected routes.
  • vtysh -c 'show ip prefix-list INTERNAL <prefix>' returns deny for the route.

Fix: adjust the prefix-list to match the intended prefix-length range, or use ge/le to broaden the match.

Gotcha 4: the rule is referenced but does nothing

The operator writes a route-map with match ip address prefix-list EMPTY-LIST (a prefix-list that has no rules). Every route falls through to the implicit deny. The route-map looks correct in the configuration; the operator who does not test the rule sees no error.

Diagnostic:

  • vtysh -c 'show ip prefix-list EMPTY-LIST' returns no rules.
  • show ip bgp shows routes that should be permitted are missing.

Fix: add rules to the prefix-list, or reference a different prefix-list.

The clear-route-map sequence

The clear-route-map sequence is the canonical test procedure:

# 1. Clear the hit counts
clear route-map
clear ip prefix-list
clear bgp community-list
clear bgp as-path-access-list

# 2. Trigger a soft reset of the BGP session (re-evaluate
#    inbound policy)
clear ip bgp <peer> soft in

# 3. Wait for the BGP session to re-evaluate (a few seconds)

# 4. Read the hit counts
vtysh -c 'show route-map'
vtysh -c 'show ip prefix-list'
vtysh -c 'show bgp community-list'
vtysh -c 'show bgp as-path-access-list'

# 5. Read the routes that were admitted or denied
vtysh -c 'show ip bgp neighbors <peer> routes'
vtysh -c 'show ip bgp filter-list <name>'
vtysh -c 'show ip bgp route-map <name>'

The soft reset triggers the BGP session to re-evaluate the inbound policy against the routes it has already received. This is faster than waiting for a new UPDATE; the routes are re-evaluated in place.

The clear ip bgp <peer> soft in command is non-destructive: it does not reset the TCP session; it triggers a route refresh. The peer must support route refresh (RFC 2918); all modern BGP implementations do.

Rollback

A policy validation failure is rolled back through the standard VyOS mechanisms:

  • rollback N and commit to revert to a previous configuration revision.
  • delete policy <primitive> <name> and commit to remove the policy.
  • delete policy <primitive> <name> rule <seq> and commit to remove a single rule.

The validation commands do not modify the configuration; they only display the matching engine’s state. The operator can run them as often as needed without affecting production.

Production discipline

Cross-course references

  • The previous lessons in this part (xxxiii-02-prefix-list, xxxiii-03-community-list, xxxiii-04-as-path-list, xxxiii-05-route-map-composition) cover the policy primitives that this lesson validates.
  • XXXIV-VyOS-Redistribution (lessons xxxiv-01 through xxxiv-06) uses these validation commands to verify redistribution route-maps.
  • The Linux course’s V-Linux-NetConfig covers the host-side perspective on policy (iptables, nftables).

Quiz

Knowledge check · 4 questions

  1. Q1. After a prefix-list change, which command tests a specific prefix against the list?

  2. Q2. The `clear route-map` command removes the route-map from the configuration.

  3. Q3. An operator writes a route-map with rule 10 denying prefix-list BLOCK-LIST and rule 20 permitting 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. The operator wants to verify the route-map. They run `clear route-map`, then `clear ip bgp <peer> soft in`, then `vtysh -c 'show route-map'`. The hit count for rule 10 is 5, for rule 20 is 50. The hit count for the implicit deny is 45. What does this confirm?

    The route-map is rule 10 deny BLOCK-LIST, rule 20 permit ALLOW-LIST. The peer sends 100 routes. After clear + soft reset, the hit counts are: rule 10 = 5, rule 20 = 50, implicit deny = 45.

  4. Q4. An operator writes a prefix-list with rule 10 permitting 10.0.0.0/8 le 16 and rule 20 permitting 10.5.0.0/16. They expect rule 20 to be more specific and 'win' for 10.5.0.0/16. They run `vtysh -c 'show ip prefix-list MYLIST 10.5.0.0/16'` and the output is `permit seq 10`. The operator is confused: rule 20 should have fired. What is wrong?

    The list is rule 10 (10.0.0.0/8 le 16 permit) and rule 20 (10.5.0.0/16 permit). The route is 10.5.0.0/16. The expected behaviour: rule 20 fires (more specific). The actual behaviour: rule 10 fires (permit seq 10).

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