BGP Route Filtering and Communities
BGP Route Filtering and Communities
Section titled “BGP Route Filtering and Communities”This guide covers RouterOS 7 BGP routing policy: writing routing filters to control which prefixes are accepted and advertised, manipulating BGP attributes (local-pref, MED, communities), and building practical policies for ISP and enterprise networks.
For BGP session setup, see BGP Peering: eBGP and iBGP Configuration. For the complete filter language reference, see Route Selection and Filters.
Filter Rule Fundamentals
Section titled “Filter Rule Fundamentals”if/then/else Syntax
Section titled “if/then/else Syntax”RouterOS 7 routing filters use a script-like if/then/else syntax. Each rule is a single rule= string attached to a named chain:
/routing filter ruleadd chain=bgp-in rule="if (dst in 192.0.2.0/24) { accept } else { reject }"Multiple conditions can appear in a single rule:
add chain=bgp-in rule="if (dst in 10.0.0.0/8 && dst-len <= 24) { set bgp-local-pref 200; accept }"The else branch is optional. Rules without an else clause that do not match fall through to the next rule in the chain. The chain’s default action is reject: any route that reaches the end without an explicit accept is dropped.
Chain Evaluation
Section titled “Chain Evaluation”A filter chain is a named, ordered list of rules evaluated top-to-bottom. When a rule accepts or rejects a route, evaluation stops. Chains can call other chains with jump and return with return:
# Jump to a shared sanitization chain, then continue in the calling chainadd chain=bgp-in-peer rule="jump bgp-sanitize"add chain=bgp-in-peer rule="if (dst-len <= 24) { set bgp-local-pref 150; accept }"add chain=bgp-in-peer rule="reject"Attaching Filters to BGP Connections
Section titled “Attaching Filters to BGP Connections”/routing bgp connectionset peer-name input.filter-chain=bgp-in output.filter-chain=bgp-outinput.filter-chain runs on routes received from the peer before they enter the routing table. output.filter-chain runs on routes being advertised to the peer.
Prefix Filtering
Section titled “Prefix Filtering”Exact Prefix Match
Section titled “Exact Prefix Match”Accept or reject a specific prefix:
/routing filter ruleadd chain=bgp-out rule="if (dst == 198.51.100.0/24) { accept }"add chain=bgp-out rule="reject"Prefix-Length Filtering
Section titled “Prefix-Length Filtering”The dst-len property matches the prefix length in bits. This is the primary tool for rejecting too-specific routes (host routes, long prefixes) or too-broad aggregates:
# Reject host routes and prefixes longer than /24 on inboundadd chain=bgp-in rule="if (dst-len > 24) { reject }"
# Reject default and prefixes shorter than /8add chain=bgp-in rule="if (dst-len < 8) { reject }"
# Accept only /8 through /24add chain=bgp-in rule="if (dst-len >= 8 && dst-len <= 24) { accept }"add chain=bgp-in rule="reject"Subnet Range Matching
Section titled “Subnet Range Matching”The in operator matches any prefix that falls within a supernet:
# Accept /24s within your allocated /22, reject more-specificsadd chain=bgp-out rule="if (dst in 203.0.113.0/22 && dst-len == 24) { accept }"add chain=bgp-out rule="reject"Combined subnet-and-length matching is the correct way to implement IRR or RPKI-style origination checks without a full validation infrastructure.
Using Address Lists as Prefix Lists
Section titled “Using Address Lists as Prefix Lists”For larger sets of prefixes, define an address list and reference it in the filter:
# Build a prefix list/ip firewall address-listadd list=customer-prefixes address=203.0.113.0/24add list=customer-prefixes address=198.51.100.0/24
# Use it in a filter/routing filter ruleadd chain=bgp-in-customer rule="if (dst in customer-prefixes) { accept }"add chain=bgp-in-customer rule="reject"Address lists used in routing filters match on exact prefix, not subnet containment. For subnet range matching, use the in operator with an explicit supernet.
BGP Attribute Manipulation
Section titled “BGP Attribute Manipulation”Local Preference
Section titled “Local Preference”Local Preference (bgp-local-pref) determines the preferred exit from your AS for a given prefix. Higher values are preferred. It is carried only in iBGP and is not sent to eBGP neighbors.
Set it on inbound eBGP filters to control internal path selection:
# Primary upstream: high preference/routing filter ruleadd chain=bgp-in-isp-primary rule="if (dst-len <= 24) { set bgp-local-pref 300; accept }"add chain=bgp-in-isp-primary rule="reject"
# Secondary upstream: lower preference (used only if primary does not have the route)add chain=bgp-in-isp-secondary rule="if (dst-len <= 24) { set bgp-local-pref 100; accept }"add chain=bgp-in-isp-secondary rule="reject"
/routing bgp connectionset to-isp-primary input.filter-chain=bgp-in-isp-primaryset to-isp-secondary input.filter-chain=bgp-in-isp-secondaryMED (Multi-Exit Discriminator)
Section titled “MED (Multi-Exit Discriminator)”MED (bgp-med) signals to neighboring ASes which of your entry points to prefer for a given prefix. Lower MED is preferred. MED is only compared between routes received from the same neighboring AS.
Set MED on outbound filters to influence inbound traffic from a single upstream:
# Advertise prefix via primary link with low MED (preferred entry)add chain=bgp-out-primary rule="if (dst == 198.51.100.0/24) { set bgp-med 10; accept }"add chain=bgp-out-primary rule="reject"
# Advertise same prefix via secondary link with high MED (backup entry)add chain=bgp-out-secondary rule="if (dst == 198.51.100.0/24) { set bgp-med 100; accept }"add chain=bgp-out-secondary rule="reject"To clear an inherited MED before sending:
add chain=bgp-out rule="if (dst in 198.51.100.0/24) { unset bgp-out-med; accept }"AS-Path Prepending
Section titled “AS-Path Prepending”Prepending your AS number makes a path appear longer and thus less preferred by external networks. Use it as an alternative to MED when your upstream compares routes from multiple ASes:
# Prepend local AS three times on secondary upstream — traffic prefers primaryadd chain=bgp-out-secondary rule="if (dst == 198.51.100.0/24) { set bgp-path-prepend 3; accept }"add chain=bgp-out-secondary rule="reject"BGP Community Operations
Section titled “BGP Community Operations”Community Types
Section titled “Community Types”| Type | Format | Size | Use |
|---|---|---|---|
| Standard | ASN:value (e.g., 65000:100) | 32-bit | General policy tagging |
| Extended | type:admin:value (e.g., rt:65000:1) | 64-bit | VPN route-target, SoO |
| Large | ASN:L-value:value (e.g., 65000:100:1) | 96-bit | 4-byte ASN policies |
Setting Communities
Section titled “Setting Communities”The set command replaces the entire community attribute. Use it when you want full control over what is attached:
# Set a standard community on all outbound routesadd chain=bgp-out rule="if (dst in 198.51.100.0/24) { set bgp-communities 65000:100; accept }"Appending Communities
Section titled “Appending Communities”The append command adds communities to the existing list without removing current values:
# Mark customer routes with a local tag before sending to transitadd chain=bgp-out-transit rule="if (dst in customer-prefixes) { append bgp-communities 65000:200; accept }"Matching on Communities
Section titled “Matching on Communities”RouterOS provides several community matching operators:
| Operator | Matches when… |
|---|---|
== value | Route has exactly these communities (no more, no less) |
any value | Route has at least one of the listed communities |
includes value | Route has all of the listed communities |
subset value | Route’s communities are a subset of the listed values |
# Accept routes tagged with a specific provider communityadd chain=bgp-in rule="if (bgp-communities includes 64500:500) { set bgp-local-pref 250; accept }"
# Match routes with any of several communitiesadd chain=bgp-in rule="if (bgp-communities any 64500:100,64500:200) { accept }"Deleting Communities
Section titled “Deleting Communities”Strip communities before advertising to prevent policy information from leaking:
# Remove all well-known communities (NO_EXPORT, NO_ADVERTISE, etc.)add chain=bgp-sanitize-out rule="if (!bgp-communities-empty) { delete bgp-communities wk; accept }"add chain=bgp-sanitize-out rule="accept"
# Remove all non-well-known communities (private policy tags)add chain=bgp-sanitize-out rule="if (!bgp-communities-empty) { delete bgp-communities other; accept }"add chain=bgp-sanitize-out rule="accept"
# Remove communities matching a regular expression (e.g., all from your own AS)add chain=bgp-sanitize-out rule="if (!bgp-communities-empty) { delete bgp-communities regexp \"65000:.*\"; accept }"add chain=bgp-sanitize-out rule="accept"Community Lists
Section titled “Community Lists”Named community lists simplify filters that reference the same set of communities in multiple rules:
# Define a community list/routing filter community-listadd list=upstream-blackhole communities=64500:666
# Use it in a filter/routing filter ruleadd chain=bgp-in rule="if (bgp-communities any-list upstream-blackhole) { set bgp-local-pref 1; accept }"Well-Known Communities
Section titled “Well-Known Communities”NO_EXPORT and NO_ADVERTISE
Section titled “NO_EXPORT and NO_ADVERTISE”RFC 1997 defines two well-known communities with mandatory behavior across all standards-compliant BGP implementations:
| Community | Numeric | Effect |
|---|---|---|
NO_EXPORT | 65535:65281 | Do not advertise to eBGP peers |
NO_ADVERTISE | 65535:65282 | Do not advertise to any peer (iBGP or eBGP) |
NO_EXPORT_SUBCONFED | 65535:65283 | Do not export to sub-confederation eBGP peers |
# Tag a more-specific with NO_EXPORT so it stays within your ASadd chain=bgp-out-ibgp rule="if (dst == 198.51.100.128/25) { append bgp-communities 65535:65281; accept }"
# Honor NO_ADVERTISE on inbound: reject before installing in RIBadd chain=bgp-in rule="if (bgp-communities includes 65535:65282) { reject }"Blackhole Community (RFC 7999)
Section titled “Blackhole Community (RFC 7999)”The IANA-assigned blackhole community (65535:666) signals upstream providers to null-route a specific destination. This is used for upstream DDoS mitigation — you advertise a /32 with this community and the upstream drops traffic to it at their edge.
# Advertise a /32 blackhole to upstream for DDoS mitigationadd chain=bgp-out-blackhole rule="if (dst-len == 32 && dst in 198.51.100.0/24) { \ set bgp-communities 65535:666; accept }"add chain=bgp-out-blackhole rule="reject"
/routing bgp connectionset to-isp output.filter-chain=bgp-out-blackholeMany providers require a provider-specific community in addition to or instead of 65535:666. Check your provider’s looking glass or NOC documentation for their exact community values.
AS-Path Filtering
Section titled “AS-Path Filtering”RouterOS 7 AS-PATH regular expressions operate on whole AS numbers (not character strings). This differs from RouterOS 6 and Cisco behavior.
# Reject routes that transited AS 64496 (route leak prevention)add chain=bgp-in rule="if (bgp-as-path .64496.) { reject }"
# Accept routes originated only by AS 64500 (no transit)add chain=bgp-in rule="if (bgp-as-path ^64500\$) { accept }"
# Reject routes with AS-PATH longer than 5 hopsadd chain=bgp-in rule="if (bgp-path-len > 5) { reject }"
# Match routes originated by either AS 64500 or AS 64501add chain=bgp-in rule="if (bgp-as-path ^(64500|64501)\$) { accept }"Test AS-PATH regular expressions before applying them to production:
/routing filter test-as-path-regexp regexp="^64500\$" as-path="64500"Peer Groups via BGP Templates
Section titled “Peer Groups via BGP Templates”RouterOS 7 replaces the v6 concept of peer groups with BGP templates. A template is a named object that holds session parameters and filter assignments; peers inherit from it. This allows a single filter chain to be applied to many peers without repeating configuration.
Defining a Base Template
Section titled “Defining a Base Template”/routing bgp templateadd name=ebgp-base as=65000 router-id=198.51.100.1 \ address-families=ip hold-time=1m keepalive-time=20sRole-Specific Templates
Section titled “Role-Specific Templates”Create role-level templates that extend the base and attach filter chains. Peers inherit both the session parameters and the filters:
# Transit upstream: strict inbound, advertise only your prefixes outbound/routing bgp templateadd name=transit template=ebgp-base \ input.filter-chain=bgp-in-transit \ output.filter-chain=bgp-out-own-prefixes
# Customer: accept only their registered prefixes, send default routeadd name=customer template=ebgp-base \ input.filter-chain=bgp-in-customer \ output.filter-chain=bgp-out-default-only
# IXP peer: accept /8–/24, AS-path length ≤ 3add name=ixp-peer template=ebgp-base \ input.filter-chain=bgp-in-ixp \ output.filter-chain=bgp-out-own-prefixesPer-Peer Override
Section titled “Per-Peer Override”A peer can override any single field while inheriting everything else from the template. This is the correct place for per-peer customization such as a different max-prefix limit or a peer-specific inbound chain:
/routing bgp templateadd name=customer-65100 template=customer \ input.filter-chain=bgp-in-customer-65100
/routing bgp connectionadd name=to-65100 remote.address=203.0.113.1 .as=65100 template=customer-65100Applying the Template to Connections
Section titled “Applying the Template to Connections”Connections reference a template. All filter and session settings are resolved from the template hierarchy at the time of connection establishment:
/routing bgp connectionadd name=to-transit1 remote.address=192.0.2.1 .as=64501 template=transitadd name=to-transit2 remote.address=192.0.2.2 .as=64502 template=transitadd name=to-customer-a remote.address=203.0.113.5 .as=65100 template=customeradd name=to-ixp-peer1 remote.address=198.51.100.10 .as=64600 template=ixp-peerBoth transit connections share bgp-in-transit and bgp-out-own-prefixes. Changing either chain updates policy for all peers in that template at once.
iBGP Templates
Section titled “iBGP Templates”The same pattern applies to iBGP. Define an iBGP base template and derive route-reflector-client or full-mesh variants from it:
/routing bgp templateadd name=ibgp-base as=65000 router-id=198.51.100.1 address-families=ip
add name=rr-client template=ibgp-base \ route-reflect=yes \ input.filter-chain=bgp-in-ibgp \ output.filter-chain=bgp-out-ibgp
/routing bgp connectionadd name=to-rr-client-1 remote.address=10.0.0.1 .as=65000 template=rr-clientadd name=to-rr-client-2 remote.address=10.0.0.2 .as=65000 template=rr-clientPractical Examples
Section titled “Practical Examples”ISP: Customer Route Filter
Section titled “ISP: Customer Route Filter”A customer at AS 65100 has been allocated 203.0.113.0/24. Accept only that prefix and its subnets down to /28; reject everything else. Set local-pref to identify customer-learned routes for internal policy:
/routing filter ruleadd chain=bgp-in-customer-65100 rule="if (dst in 203.0.113.0/24 && dst-len <= 28) { \ set bgp-local-pref 200; accept }"add chain=bgp-in-customer-65100 rule="reject"
/routing bgp connectionset customer-65100 input.filter-chain=bgp-in-customer-65100Outbound to customer: send only a default route (or a partial table if agreed):
/routing filter ruleadd chain=bgp-out-customer-65100 rule="if (dst == 0.0.0.0/0) { accept }"add chain=bgp-out-customer-65100 rule="reject"
/routing bgp connectionset customer-65100 output.filter-chain=bgp-out-customer-65100ISP: Peer Route Filter
Section titled “ISP: Peer Route Filter”A peer at AS 64500 should only send routes it originates or its customers originate. Reject transit routes (AS-PATH length > 2). Accept /8–/24 only:
/routing filter ruleadd chain=bgp-in-peer-64500 rule="if (dst-len < 8 || dst-len > 24) { reject }"add chain=bgp-in-peer-64500 rule="if (bgp-path-len > 2) { reject }"add chain=bgp-in-peer-64500 rule="if (bgp-as-path ^64500.*\$) { \ set bgp-local-pref 150; accept }"add chain=bgp-in-peer-64500 rule="reject"Outbound to peer: send only your own prefixes, strip internal communities:
/routing filter ruleadd chain=bgp-out-peer-64500 rule="if (dst in 198.51.100.0/22 && dst-len >= 22 && dst-len <= 24) { \ delete bgp-communities other; accept }"add chain=bgp-out-peer-64500 rule="reject"ISP: Transit Route Filter
Section titled “ISP: Transit Route Filter”Inbound from a transit provider: accept full table but reject bogons and too-specific prefixes. Set local-pref lower than peers (transit is last-resort):
/routing filter rule
# Reject RFC 1918 and other bogonsadd chain=bgp-in-transit rule="if (dst in 10.0.0.0/8) { reject }"add chain=bgp-in-transit rule="if (dst in 172.16.0.0/12) { reject }"add chain=bgp-in-transit rule="if (dst in 192.168.0.0/16) { reject }"add chain=bgp-in-transit rule="if (dst in 0.0.0.0/8) { reject }"add chain=bgp-in-transit rule="if (dst in 169.254.0.0/16) { reject }"add chain=bgp-in-transit rule="if (dst in 240.0.0.0/4) { reject }"add chain=bgp-in-transit rule="if (dst == 0.0.0.0/0) { reject }"
# Reject too-specific (host routes from global table) and too-broadadd chain=bgp-in-transit rule="if (dst-len < 8 || dst-len > 24) { reject }"
# Accept remainder with transit local-prefadd chain=bgp-in-transit rule="if (dst-len >= 8 && dst-len <= 24) { \ set bgp-local-pref 100; accept }"add chain=bgp-in-transit rule="reject"Enterprise: Dual-Homed with Community-Based Failover
Section titled “Enterprise: Dual-Homed with Community-Based Failover”An enterprise with two ISPs uses communities to control routing. ISP-A’s blackhole community is 64500:666. Mark internal prefixes to influence inbound traffic:
# Inbound from ISP-A: default route only, high preference/routing filter ruleadd chain=bgp-in-ispa rule="if (dst == 0.0.0.0/0) { set bgp-local-pref 200; accept }"add chain=bgp-in-ispa rule="reject"
# Inbound from ISP-B: default route only, low preferenceadd chain=bgp-in-ispb rule="if (dst == 0.0.0.0/0) { set bgp-local-pref 100; accept }"add chain=bgp-in-ispb rule="reject"
# Outbound to ISP-A: advertise prefix, prefer inbound via A (low MED)add chain=bgp-out-ispa rule="if (dst == 198.51.100.0/24) { set bgp-med 10; accept }"add chain=bgp-out-ispa rule="reject"
# Outbound to ISP-B: advertise prefix, deprioritize inbound via B (high MED + prepend)add chain=bgp-out-ispb rule="if (dst == 198.51.100.0/24) { \ set bgp-med 100; set bgp-path-prepend 2; accept }"add chain=bgp-out-ispb rule="reject"
# Trigger upstream blackhole for a /32 under attackadd chain=bgp-out-blackhole rule="if (dst-len == 32 && dst in 198.51.100.0/24) { \ append bgp-communities 64500:666; accept }"add chain=bgp-out-blackhole rule="reject"Stripping Communities at Administrative Boundaries
Section titled “Stripping Communities at Administrative Boundaries”When a route crosses from your AS to a customer or peer, strip internal policy communities to prevent information leakage:
/routing filter rule
# Remove all internal communities before sending to any eBGP neighboradd chain=bgp-out-strip rule="if (!bgp-communities-empty) { \ delete bgp-communities regexp \"65000:.*\"; accept }"add chain=bgp-out-strip rule="accept"
/routing bgp connection# Apply strip chain for all external connectionsset to-customer output.filter-chain=bgp-out-stripset to-peer output.filter-chain=bgp-out-stripCommon Mistakes
Section titled “Common Mistakes”Omitting a final reject rule. The chain default is reject, but an explicit final reject documents intent and makes audits easier.
Modifying and accepting in the wrong order. Actions in a rule’s block execute left-to-right. set bgp-local-pref 200; accept is correct. accept; set bgp-local-pref 200 applies the accept immediately and the set is unreachable.
Using v6-style AS-path regexp. In RouterOS 7, bgp-as-path .1234. matches ASN 1234 as a whole token, not the substring “1234” in the path string. Patterns copied from v6 or Cisco configs may produce unexpected matches.
Setting local-pref on outbound. Local Preference is only meaningful on inbound routes. Setting it in an output filter has no effect on path selection at the receiving peer.
MED comparison across ASes. MED is only compared by the receiving router between routes from the same neighboring AS. Setting MED to influence traffic from two different ASes requires AS-path prepending instead.
Troubleshooting
Section titled “Troubleshooting”Verify Applied Filter Rules
Section titled “Verify Applied Filter Rules”/routing filter rule print where chain=bgp-inCheck What a Peer Is Sending vs What Was Accepted
Section titled “Check What a Peer Is Sending vs What Was Accepted”# Routes received (pre-filter)/routing bgp advertisements print where session=peer-name
# Routes installed from BGP/ip route print where bgp
# BGP RIB with filter state/routing route print where bgp && !activeInactive BGP routes in the RIB (flag b but not A) were received and parsed but not installed as best path. This is normal when a better path exists. Routes rejected by input filters do not appear in the RIB at all.
Test a Filter Chain Without Applying It
Section titled “Test a Filter Chain Without Applying It”Temporarily assign the chain to a connection and monitor prefix counts:
/routing bgp connection set peer-name input.filter-chain=test-chain/routing bgp session print detail where name=peer-name# Check input-prefixesRemove when done:
/routing bgp connection set peer-name input.filter-chain=bgp-inSee Also
Section titled “See Also”- BGP Peering: eBGP and iBGP Configuration — Session setup, iBGP full-mesh and route reflectors
- Route Selection and Filters — Complete filter language reference: all readable/writable properties, operators, and community/num-list primitives
- OSPF Configuration — Redistributing OSPF into BGP and vice versa