Skip to content
MikroTik RouterOS Docs

Routing Filters in RouterOS: A Complete Guide

RouterOS Version: 7.x+ (v7 syntax required) Difficulty: Advanced Estimated Time: 45 minutes

Routing Filters control route acceptance, rejection, and attribute modification for dynamic routing protocols (BGP, OSPF, RIP). They provide policy control over which routes enter your routing table and what attributes they carry.

Key concepts:

  • Filters use script-like if-then-else syntax
  • Default action is REJECT - unmatched routes are discarded
  • Rules are processed top-to-bottom; first match wins
  • v7 syntax is completely different from v6

Critical: RouterOS v7 introduced major syntax changes. Filters from v6 or Cisco configurations are NOT compatible and must be rewritten.

MenuPurpose
/routing/filter/ruleFilter rules for accept/reject/modify
/routing/filter/select-ruleSelection rules for route candidates
/routing/filter/num-listAS number lists for path matching
/routing/filter/community-listStandard BGP community lists
/routing/filter/community-ext-listExtended BGP community lists
/routing/filter/community-large-listLarge BGP community lists
"if ( [matchers] ) { [actions] } else { [actions] }"

Or simple unconditional:

"accept;"
"reject;"
ActionDescription
acceptAccept route (stop processing)
rejectReject route (stop processing)
returnExit to parent chain
jump [chain]Branch to another chain
set [property] [value]Modify property
unset [property]Clear property
OperatorDescription
&&AND
||OR
notNegation
==, !=, >, <, >=, <=Comparison
inRange or subnet match

Accept specific prefixes, reject everything else:

# Rule 1: Accept your customer prefixes
/routing/filter/rule add chain=bgp-in \
rule="if (dst in 192.168.0.0/16 && dst-len in 16-24) { accept; }"
# Rule 2: Accept default route
/routing/filter/rule add chain=bgp-in \
rule="if (dst == 0.0.0.0/0) { accept; }"
# Rule 3: Reject everything else (explicit for clarity)
/routing/filter/rule add chain=bgp-in \
rule="reject;"
# Apply to BGP connection
/routing/bgp/connection set [find name=upstream] input.filter=bgp-in

Advertise prefixes with prepending:

# Prepend AS 3 times for backup link
/routing/filter/rule add chain=bgp-out-backup \
rule="if (dst in 10.0.0.0/8) { set bgp-path-prepend 3; accept; }"
# Reject all other advertisements
/routing/filter/rule add chain=bgp-out-backup \
rule="reject;"
# Apply to BGP connection
/routing/bgp/connection set [find name=backup-peer] output.filter-chain=bgp-out-backup

Prefer routes from primary upstream:

# Primary peer - higher local-pref
/routing/filter/rule add chain=bgp-in-primary \
rule="set bgp-local-pref 200; accept;"
# Backup peer - lower local-pref
/routing/filter/rule add chain=bgp-in-backup \
rule="set bgp-local-pref 100; accept;"
# Apply to connections
/routing/bgp/connection set [find name=primary] input.filter=bgp-in-primary
/routing/bgp/connection set [find name=backup] input.filter=bgp-in-backup

Block routes containing specific AS numbers:

# Create num-list for blocked ASNs
/routing/filter/num-list add list=blocked-as range=64496-64511
/routing/filter/num-list add list=blocked-as range=65535
# Filter using AS path regex
/routing/filter/rule add chain=bgp-in \
rule="if (bgp-as-path .[[:blocked-as:]].) { reject; }"
# Accept everything else
/routing/filter/rule add chain=bgp-in \
rule="accept;"

Handle blackhole communities:

# Create community list
/routing/filter/community-list add name=blackhole communities=65535:666
# Check for blackhole community and set route to blackhole
/routing/filter/rule add chain=bgp-in \
rule="if (bgp-communities any-list blackhole) { set blackhole yes; accept; }"
# Accept other routes normally
/routing/filter/rule add chain=bgp-in \
rule="accept;"

Tag routes with communities:

# Add community to customer routes
/routing/filter/rule add chain=bgp-out \
rule="if (dst in 192.168.0.0/16) { append bgp-communities 65000:100; accept; }"
# Accept other routes without modification
/routing/filter/rule add chain=bgp-out \
rule="accept;"

Control which routes are redistributed into OSPF:

# Allow connected routes from specific subnets
/routing/filter/rule add chain=ospf-out \
rule="if (protocol connected && dst in 192.168.0.0/16) { set ospf-ext-metric 10; set ospf-ext-type type1; accept; }"
# Allow static routes
/routing/filter/rule add chain=ospf-out \
rule="if (protocol static && dst in 10.0.0.0/8) { set ospf-ext-metric 20; set ospf-ext-type type2; accept; }"
# Reject everything else
/routing/filter/rule add chain=ospf-out \
rule="reject;"
# Apply to OSPF instance
/routing/ospf/instance set [find name=default] out-filter-chain=ospf-out

Organize complex filters:

# Bogon check sub-chain
/routing/filter/rule add chain=bogon-check \
rule="if (dst in 0.0.0.0/8) { reject; }"
/routing/filter/rule add chain=bogon-check \
rule="if (dst in 10.0.0.0/8) { reject; }"
/routing/filter/rule add chain=bogon-check \
rule="if (dst in 127.0.0.0/8) { reject; }"
/routing/filter/rule add chain=bogon-check \
rule="if (dst in 192.168.0.0/16) { reject; }"
/routing/filter/rule add chain=bogon-check \
rule="return;"
# Main filter - jump to bogon check first
/routing/filter/rule add chain=bgp-in \
rule="jump bogon-check;"
/routing/filter/rule add chain=bgp-in \
rule="accept;"

Generate rules using v6-like syntax:

# Generate filter rule
/routing/filter filter-wizard action=accept chain=mychain \
prefix=10.0.0.0/8 prefix-length=8-24 set-bgp-local-pref=200
# Result: "if (dst in 10.0.0.0/8 && dst-len in 8-24) { set bgp-local-pref 200; accept; }"

RouterOS v7 uses numeric per-ASN matching, different from v6/Cisco string-based patterns.

PatternDescription
^Path start (first AS)
$Path end (origin AS)
.Any single ASN
*Zero or more
+One or more
?Zero or one
|Alternative
[123 456]ASN set
[^123]Negated set
[[:numlist:]]Reference num-list
PatternMatches
^$Empty path (locally originated)
^1234$Single-hop from AS 1234 only
.1234.Any path containing AS 1234
^1234Path starting with AS 1234
1234$Path ending with AS 1234 (origin)
^1234+$Path with one or more AS 1234

Warning: Do NOT copy regex from v6 or Cisco - they use string-based matching!

MatcherDescription
dstDestination prefix
dst-lenPrefix length
afiAddress family (ipv4, ipv6)
MatcherValues
protocolbgp, ospf, rip, static, connected
ospf-typeext1, ext2, inter, intra, nssa1, nssa2
MatcherDescription
bgp-as-pathAS path regex
bgp-path-lenAS path length
bgp-communitiesCommunity matching
bgp-networkOriginated via network statement
PropertyDescription
bgp-local-prefLocal preference
bgp-medMulti-Exit Discriminator
bgp-path-prependAS prepend count
bgp-originOrigin (igp, egp, incomplete)
bgp-weightWeight
PropertyDescription
ospf-ext-metricExternal metric
ospf-ext-typeExternal type (type1, type2)
ospf-ext-tagExternal tag
PropertyDescription
distanceAdministrative distance
blackholeMake blackhole route
pref-srcPreferred source
gwGateway

Cause: Default action is reject; missing accept statement.

Solution: Always add explicit accept for wanted routes:

# Your conditional rules here...
# End with accept for remaining routes
/routing/filter/rule add chain=bgp-in rule="accept;"

Cause: Completely different syntax.

v6 syntax (doesn’t work):

/routing filter add action=accept chain=bgp-in prefix=10.0.0.0/8

v7 syntax (correct):

/routing/filter/rule add chain=bgp-in rule="if (dst in 10.0.0.0/8) { accept; }"

Cause: v7 uses numeric per-ASN matching, not string matching.

Wrong (string-based):

rule="if (bgp-as-path \"_1234_\") { reject; }"

Correct (numeric):

rule="if (bgp-as-path .1234.) { reject; }"

Cause: Filter chain not applied to protocol.

Solution:

# For BGP
/routing/bgp/connection set [find name=peer1] input.filter=bgp-in
# For OSPF
/routing/ospf/instance set [find] out-filter-chain=ospf-out

Cause: OSPF is link-state; filters only work on external routes.

Workaround:

  • Use area summarization on ABR
  • Convert area to NSSA with no-summary
  • Filter at redistribution point, not OSPF-to-OSPF

Problem: dst in 10.0.0.0/8 only matches that exact prefix.

Solution: Add prefix length condition:

# Match all prefixes within 10.0.0.0/8
rule="if (dst in 10.0.0.0/8 && dst-len >= 8) { accept; }"
# Match specific length range
rule="if (dst in 10.0.0.0/8 && dst-len in 16-24) { accept; }"
v6v7
prefix=10.0.0.0/8dst in 10.0.0.0/8
prefix-length=16-24dst-len in 16-24
action=acceptaccept;
action=discardreject;
set-bgp-prepend=3set bgp-path-prepend 3;
bgp-as-path=".1234."bgp-as-path .1234.
jump-target=chain2jump chain2;
# View all filter rules
/routing/filter/rule print
# View specific chain
/routing/filter/rule print where chain=bgp-in
# Check BGP connection filter assignment
/routing/bgp/connection print detail
# View filtered (rejected) routes
/routing/route print where filtered
# Check community lists
/routing/filter/community-list print
# Check num-lists
/routing/filter/num-list print
  • BGP (/routing/bgp) - Primary filter consumer
  • OSPF (/routing/ospf) - Uses filters for redistribution
  • RIP (/routing/rip) - Uses filters for route control
  • RPKI (/routing/rpki) - Integrates with filters for validation
  • Routing Tables (/routing/table) - Filters can reference tables

Routing Filters in RouterOS v7 use script-like syntax for route policy:

  1. Create filter rules with if-then-else syntax
  2. Apply to protocol via input.filter or output.filter-chain
  3. Always add explicit accept for wanted routes

Key points:

  • Default action is REJECT
  • v7 syntax is completely different from v6
  • AS-PATH uses numeric regex, not string-based
  • OSPF internal routes cannot be filtered
  • Use Filter Wizard (v7.20+) for easier migration