Skip to main content
RunBook Academy

VyOSXXXIII · Route PolicyCommunity-list

Community-list — standard, expanded, and regular-expression matching

Advanced⏱ ~22 minvyosvtyshset policy community-listshow policy community-listvtysh -c show bgp community-listvtysh -c show ip bgp communityvtysh -c show ip bgp regexp

What you'll learn

  • Configure a community-list in standard and expanded forms on VyOS 1.5 LTS
  • Distinguish exact-match (standard) from regex (expanded) community matching
  • Write community regular expressions that match the intended community set
  • Diagnose a community-list that returns no-match for a community that should match

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 BGP community-list is the policy primitive that filters routes by their communities. Communities are 32-bit tags attached to a BGP route by the originator or by intermediate ASes; the recipient uses them to make policy decisions without inspecting the prefix or the AS-path.

On VyOS 1.5 LTS the community-list comes in two forms: standard (exact-match) and expanded (regular expression). The form the operator chooses determines the matching engine; the operator who confuses the two forms writes a list that matches nothing or matches too much.

This lesson covers the configuration, the matching engine semantics, and the production failure modes.

Standard vs expanded — the two matching engines

A community-list has a type that selects the matching engine:

  • standard (set policy community-list <name> rule <seq> action permit community <AA:NN>) — matches the exact community value AA:NN. 64512:100 matches only 64512:100; it does not match 64512:10 or 64512:1000.
  • expanded (set policy community-list <name> rule <seq> action permit regex <pattern>) — matches a POSIX regular expression against the string form of the community. ^64512:100$ matches only 64512:100; ^64512:[0-9]+$ matches every community in AS 64512.
flowchart TB
  R["Route with communities\n64512:100 64512:200 64513:50"]
  L1{"List type?"}
  STD["Standard matching:\neach rule's community\nmatched exactly\nagainst route's\ncommunities"]
  EXP["Expanded matching:\neach rule's regex\nmatched against\neach community string"]
  P["Permit: at least one\ncommunity matched"]
  X["Deny: no community\nmatched any rule"]

  R --> L1
  L1 -->|standard| STD
  L1 -->|expanded| EXP
  STD -->|"at least one community\nmatches a permit rule"| P
  STD -->|"no community matches\nany permit rule"| X
  EXP -->|"at least one community\nmatches a permit regex"| P
  EXP -->|"no community matches\nany permit regex"| X

The two engines differ in one key property: a community-list returns permit if any community on the route matches a permit rule. It is not “the route’s community-set must match the list”. It is “the list looks at each community on the route and asks ‘does any of them match?’”.

The operator who forgets this writes a community-list that permits routes they thought were denied, because the route carries multiple communities and one of them happens to match.

The configuration

Standard form

# Exact-match for 64512:100
set policy community-list FROM-PEER-A rule 10 action permit
set policy community-list FROM-PEER-A rule 10 community 64512:100

# Exact-match for 64512:200
set policy community-list FROM-PEER-A rule 20 action permit
set policy community-list FROM-PEER-A rule 20 community 64512:200

# Catch-all deny
set policy community-list FROM-PEER-A rule 1000 action deny

The list evaluates top-to-bottom. The first rule that matches any community on the route decides. A route with communities 64512:100 64512:200 is permitted (either rule 10 or rule 20 will fire). A route with community 64513:50 falls through to rule 1000 (deny).

Expanded form

# Regex: any community in AS 64512
set policy community-list FROM-ANY-64512 rule 10 action permit
set policy community-list FROM-ANY-64512 rule 10 regex '^64512:'

# Regex: exact match for 64512:100 only (equivalent to standard)
set policy community-list EXACT-100 rule 10 action permit
set policy community-list EXACT-100 rule 10 regex '^64512:100$'

# Catch-all deny
set policy community-list FROM-ANY-64512 rule 1000 action deny

The expanded form uses POSIX extended regular expressions. The anchor characters ^ (start of string) and $ (end of string) are essential for exact-match. Without them, 64512:100 matches 64512:1000, 64512:1005, and every other community in 64512:1xx, 64512:10xx, etc.

flowchart LR
  PAT["Regex pattern"]
  A1["^64512: (anchored start)\nmatches: 64512:100 64512:200 64512:1 64512:99999"]
  A2["64512: (no anchor)\nmatches: 164512: 64512:100 64512:1000 64512:99999\nalso matches: '164512:5' (contains '64512:')"]
  A3["^64512:100$ (anchored both)\nmatches: 64512:100 ONLY"]
  A4["^64512:100 (anchored start only)\nmatches: 64512:100 64512:1000 64512:1005 64512:10000"]

  PAT --> A1
  PAT --> A2
  PAT --> A3
  PAT --> A4

The unanchored 64512: matches 164512:5 (the substring 64512: appears in 164512:5). The operator who writes an unanchored regex and expects exact-match is surprised when the list permits unintended communities.

Sequence semantics

Community-lists are ordered and sequential, like prefix-lists. Two rules in the same list cannot both fire; the first match by sequence wins. The implicit deny at the end of the list applies for any community-set that matches no permit rule.

The operator can mix standard and expanded rules in the same list; each rule’s action permit community or action permit regex selects the matching engine for that rule. The list type is per-rule, not per-list.

Operational commands

# The configured list
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 whose community matches a regex
vtysh -c 'show ip bgp regexp "_64512:.*"'

# Clear the hit counts
clear bgp community-list

The show ip bgp community <value> returns all routes in the BGP table whose community-set contains <value>. The exact-match keyword restricts to routes whose only community is <value>. The show ip bgp regexp returns routes whose community-set matches the regex (FRR uses an internal regex that looks similar to expanded community regex but is distinct).

Failure modes

Standard list with too many communities

The operator writes a standard list with 50 permit rules, one per customer community. The configuration is correct but unmaintainable. A customer adds a 51st community; the operator forgets to update the list. The route is denied by the implicit catch-all.

Diagnostic:

  • show ip bgp community returns empty for the new community.
  • show policy community-list shows the old list.
  • vtysh -c 'show bgp community-list <name>' shows no hit count for the new community.

Fix: replace the 50 permit rules with a single expanded regex. ^64512:(100|200|...|500)$ matches all 50.

Expanded regex without anchors

The operator writes set policy community-list FOO rule 10 action permit regex '64512:100' (no ^ and no $). The intent was exact-match. The actual matching is: any community string that contains 64512:100 as a substring. 64512:1000 matches. 164512:1005 matches. 64512:100 matches. The list permits too much.

Diagnostic:

  • vtysh -c 'show bgp community-list FOO' returns hit counts for communities the operator did not intend to match.
  • show ip bgp community 64512:1000 returns routes that should have been denied.

Fix: anchor the regex. ^64512:100$.

Community-list with the wrong type

The operator writes set policy community-list FOO rule 10 action permit community 64512:100 intending an exact-match. The rule is a standard rule. The matching engine compares the community value 64512:100 exactly. A route with community 64512:1000 does not match. A route with community 64512:100 64512:200 is permitted (the 64512:100 community matches).

If the operator wanted the regex semantics, they should have used set policy community-list FOO rule 10 action permit regex '^64512:100$'. If they wanted exact-match for multiple communities, the standard form is correct; they need multiple rules.

Diagnostic:

  • The list returns permit for routes that should be denied.
  • show policy community-list shows the rule as a standard rule (no regex keyword in the output).

Fix: switch the rule to expanded if regex semantics are needed; otherwise add more standard rules for each community.

Rollback

A community-list change is reversible through the standard VyOS mechanisms:

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

The VyOS commit validator rejects a route-map that references a missing community-list.

Production discipline

Cross-course references

  • XXVI-VyOS-BGPAttributes (lesson vyos-xxvi-05-community) covers the BGP community attribute at depth: the four well-known communities, the format, and the path of a community through a route.
  • XXIX-VyOS-BGPCommunities covers community-based outbound policy: how to stamp a community and let downstream peers use it.
  • XXXIII-VyOS-RoutePolicy (next lesson, route-map) shows how a community-list is matched against a route in the route-map’s match clause.

Quiz

Knowledge check · 4 questions

  1. Q1. A standard community-list has rule 10 permitting community 64512:100 and rule 20 permitting community 64512:200. A route arrives with communities 64512:100 64513:50. What is the disposition?

  2. Q2. An expanded community-list with rule 10 regex '64512:100' matches only community 64512:100.

  3. Q3. An operator wants to filter inbound routes from a peer to those carrying the customer's specific community 64512:500. They write `set policy community-list FROM-CUSTOMER rule 10 action permit community 64512:500`. A route arrives with communities 64512:500 64512:600. What happens and what is the fix?

    The list is a standard community-list with rule 10 permitting 64512:500. The route carries two communities: 64512:500 and 64512:600. The intent was to filter to only the customer community.

  4. Q4. An operator writes an expanded community-list `set policy community-list FOO rule 10 action permit regex '^64512:'` and applies it via route-map to inbound from a peer. The peer sends 100 routes, all with community 64512:100. The operator expects 100 routes permitted. After the commit, 100 routes are denied. What is wrong?

    The regex is `^64512:` (anchored start). The peer sends 100 routes with community 64512:100. The list is referenced from a route-map on the inbound side. The operator expected permit; observed deny.

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