BGP.guru

BGP.guru

Nerd blog.

22 Jun 2025

RouterOS 7.x Filtering

Introduction

This is an example policy/config I’ve been working on for several years. It supports Transit (DFZ), IXP Peering, and giving transit to customers.

BGP Policy

This policy tries to follow all of the best practices.

Roles

  • customer 65551:0:2
  • transit 65551:0:6
  • peering 65551:0:8 + 65551:0:IXP_ID

Transit Policy Inbound

  1. Transit_Name_In
  2. Protect_In
  3. Size validation
  4. Reject

Customer Policy Inbound

  1. Customer_Name
  2. Protect_In
  3. CustomerActions_In
    1. 65551:1:550 -> localpref=550
    2. 65551:1:450 -> localpref=450
    3. 65551:1:50 -> localpref=50 (last resort)
    4. else -> localpref=500
  4. Blackhole
  5. PrefixCheck (list + size validation)
  6. Reject

Example Policy Config

We start off by defining some lists of BGP communities, both regular and large communities are supported. As I run a 32-bit system I mostly rely on the large communities.

I have replaced my own 32-bit ASN with one of the documentation range ASNs, 65551.

/routing filter community-large-list
add communities="65551:0:1,65551:0:2,65551:0:3,65551:0:4,65551:0:6,65551\
    :0:8,65551:5:1,65551:5:2,65551:5:3,65551:5:4,65551:6:10,65551:6:11\
    95089:8:703" disabled=no list=Informational
add disabled=no list=Info_regex regexp="65551:[05678]:.*"
add disabled=no list=Action_Regex regexp="65551:[1234]:.*"
add communities="65551:1:50,65551:1:450,65551:1:550,65551:301:0,65551:302\
    :0,65551:303:0" disabled=no list=Customers_Only
add communities="65551:1:50,65551:1:150,65551:1:450,65551:1:550,65551:2:0\
    ,65551:3:0,65551:4:0,65551:301:0,65551:302:0,65551:303:0" disabled=\
    no list=Actions
add communities=65551:1:50,65551:1:150,65551:1:450,65551:1:550 disabled=\
    no list=LocalPrefMod

Similar functionality exists for regular communities, although I haven’t built it out as much because I don’t use this functionality myself.

/routing filter community-list
add communities="65089:50,65089:150,65089:450,65089:550,65089:202,65089:203,65\
    089:204,65089:301,65089:302,65089:303,65535:0,65535:666" disabled=no \
    list=Actions
add communities=65089:50,65089:450,65089:550,65089:301,65089:302,65089:303 \
    disabled=no list=Customers_Only
add communities="65089:1,65089:2,65089:3,65089:4,65089:101,65089:102,65089:103\
    ,65089:104,65089:10,65089:11" disabled=no list=Informational
add communities=65000:13335,13335:10168,13335:19000 disabled=no list=\
    test_communities

Before we use them, we define a bunch of actions that we can jump to.

  • Outbound we advertise things that are in the BGP.Advertisements IPv4 and IPv6 Firewall address-lists, or things that have “self” or “customer” large communities.
  • We use Protect_Transit_In to apply default route rejection, bogon route rejection, clean up any communities that have functionality on links they shouldn’t be used on, and add support for graceful shutdown. This jump target has a return at the end which is important.
  • Customer routes are filtered for Informational communities, and also return at the end of the jump.
  • RPKI Valiation we have covered in the past
/routing filter rule
add chain=Advertise_Out_v6 disabled=no rule="if ( (dst in BGP.Advertisements &\
    & dst-len in 16-48) || bgp-large-communities includes 65551:0:1 || bgp-la\
    rge-communities includes 65551:0:2 ) {\r\
    \n  accept;\r\
    \n} else {\r\
    \n  reject;\r\
    \n}"
add chain=Advertise_Out_v4 disabled=no rule="if ( (dst in BGP.Advertisements &\
    & dst-len in 8-24) || bgp-large-communities includes 65551:0:1 || bgp-lar\
    ge-communities includes 65551:0:2 ) {\r\
    \n  accept;\r\
    \n} else {\r\
    \n  reject;\r\
    \n}"
add chain=Protect_Transit_In disabled=no rule="jump Self_Reject;\r\
    \njump Default_Reject;\r\
    \njump Bogon_Reject;\r\
    \njump CleanInfoCommunities_In;\r\
    \njump CleanActionCommunities_In;\r\
    \njump GracefulShutdown_In;"
add chain=Protect_Transit_In disabled=no rule="return;"
add chain=Protect_Customer_In disabled=no rule=\
    "jump CleanInfoCommunities_In;"
add chain=Protect_Customer_In disabled=no rule="return;"
add chain=RPKI_Validate disabled=no rule="rpki-verify HextetRPKI"
add chain=RPKI_Validate disabled=no rule="if (rpki invalid) {\r\
    \n  set bgp-large-communities 65551:7:4;\r\
    \n  reject;\r\
    \n}"
add chain=RPKI_Validate disabled=no rule=\
    "if (rpki valid) {\r\
    \n  append bgp-large-communities 65551:5:2;\r\
    \n}"
add chain=RPKI_Validate disabled=no rule="return;"
add chain=Self_Reject disabled=no rule="if (afi ipv4 && dst in 192.0.2.0/2\
    4 && dst-len <= 32) {\r\
    \n  set bgp-large-communities 65551:7:1; reject;\r\
    \n}"
add chain=Self_Reject disabled=no rule="if (afi ipv6 && dst in 2001:db8::\
    /40 && dst-len <= 128) {\r\
    \n  set bgp-large-communities 65551:7:1; reject;\r\
    \n}"
add chain=Self_Reject disabled=no rule="return;"
add chain=Default_Reject disabled=no rule="if (afi ipv4 && dst == 0.0.0.0/0 &&\
    \_dst-len == 0) {\r\
    \n  set bgp-large-communities 65551:7:5; reject;\r\
    \n}"
add chain=Default_Reject disabled=no rule="if (afi ipv6 && dst == ::/0 && dst-\
    len == 0) {\r\
    \n  set bgp-large-communities 65551:7:5; reject;\r\
    \n}"
add chain=Default_Reject disabled=no rule="return;"
add chain=Bogon_Reject disabled=no rule="if ((dst in BGP.Bogons) || (dst in BG\
    P.RFC1918)) {\r\
    \n  set bgp-large-communities 65551:7:3; reject;\r\
    \n}"
add chain=Bogon_Reject disabled=no rule="return;"
add chain=CleanInfoCommunities_In disabled=no rule="if (bgp-large-communities \
    any-list Informational) {\r\
    \n  delete bgp-large-communities Informational;\r\
    \n}"
add chain=CleanInfoCommunities_In disabled=no rule="return;"
add chain=CleanActionCommunities_In disabled=no rule="if (bgp-large-communitie\
    s any-list Action) {\r\
    \n  delete bgp-large-communities Action;\r\
    \n}"
add chain=CleanActionCommunities_In disabled=no rule="return;"
add chain=GracefulShutdown_In disabled=no rule="if (bgp-communities includes g\
    raceful-shutdown) {\r\
    \n  set bgp-local-pref 0;\r\
    \n}"
add chain=GracefulShutdown_In disabled=no rule="return;"
add chain=CustomerActionCommunities_In disabled=no rule="if (bgp-large-communi\
    ties includes 65551:1:550 || bgp-communities includes 65089:550) {\r\
    \n  set bgp-local-pref 550;\r\
    \n}"
add chain=CustomerActionCommunities_In disabled=no rule="if (bgp-large-communi\
    ties includes 65551:1:450 || bgp-communities includes 65089:450) {\r\
    \n  set bgp-local-pref 450;\r\
    \n}"
add chain=CustomerActionCommunities_In disabled=no rule="if (bgp-large-communi\
    ties includes 65551:1:50 || bgp-communities includes 65089:50) {\r\
    \n  set bgp-local-pref 50;\r\
    \n}"
add chain=CustomerActionCommunities_In disabled=no rule="if (bgp-large-communi\
    ties any-list LocalPrefMod) {\r\
    \n\r\
    \n} else {\r\
    \n  set bgp-local-pref 500;\r\
    \n}"
add chain=CustomerActionCommunities_In disabled=no rule="if (bgp-communities i\
    ncludes graceful-shutdown) {\r\
    \n  set bgp-local-pref 0;\r\
    \n}"
add chain=CustomerActionCommunities_In disabled=no rule="return;"

After defining all of this, we can actually apply it to various links.

add chain=CUST1_customertransit_in_v6 disabled=no rule=\
    "jump Protect_Customer_In;"
add chain=CUST1_customertransit_in_v6 disabled=no rule="if (dst in 2001:db8::\
    /48 && dst-len == 128 && bgp-communities includes blackhole) {\r\
    \n  set blackhole true;\r\
    \n  append bgp-large-communities 65551:0:2;\r\
    \n  accept;\r\
    \n}"
add chain=CUST1_customertransit_in_v6 disabled=no rule="if (dst in 2001:db8::\
    /48 && dst-len <= 48) {\r\
    \n  append bgp-large-communities 65551:0:2;\r\
    \n  set bgp-local-pref 300;\r\
    \n  accept;\r\
    \n}"
add chain=CUST1_customertransit_out_v6 disabled=no rule=\
    "if (dst in 2001::/3 && dst-len in 16-48) { accept; }"


add chain=CUST2_customertransit_in_v6 disabled=no rule=\
    "jump Protect_Customer_In;"
add chain=CUST2_customertransit_in_v6 disabled=no rule="if (dst in 2001:db8::\
    /36 && dst-len == 128 && bgp-communities includes blackhole) {\r\
    \n  set blackhole true;\r\
    \n  append bgp-large-communities 65551:0:2;\r\
    \n  accept;\r\
    \n}"
add chain=CUST2_customertransit_in_v6 disabled=no rule="if (dst in 2001:db8::\
    /36 && dst-len <= 48) {\r\
    \n  append bgp-large-communities 65551:0:2;\r\
    \n  set bgp-local-pref 300;\r\
    \n  accept;\r\
    \n}"
add chain=CUST2_customertransit_in_v4 disabled=no rule=\
    "jump Protect_Customer_In;"
add chain=CUST2_customertransit_in_v4 disabled=no rule="if (dst in BGP.Custome\
    r.CUST2 && dst-len == 32 && bgp-communities includes blackhole) {\r\
    \n  set blackhole true;\r\
    \n  append bgp-large-communities 65551:0:2;\r\
    \n  accept;\r\
    \n}"
add chain=CUST2_customertransit_in_v4 disabled=no rule="if (dst in BGP.Custome\
    r.CUST2 && dst-len <= 24) {\r\
    \n  append bgp-large-communities 65551:0:2;\r\
    \n  set bgp-local-pref 300;\r\
    \n  accept;\r\
    \n}"
add chain=CUST2_customertransit_out_v6 disabled=no rule=\
    "if (dst == ::/0 && dst-len == 0) { accept; }"
add chain=CUST2_customertransit_out_v6 disabled=no rule=\
    "if (bgp-large-communities includes 65551:0:1) { accept; }"
add chain=CUST2_customertransit_out_v6 disabled=no rule=\
    "if (bgp-large-communities includes 65551:0:2) { accept; }"
add chain=CUST2_customertransit_out_v4 disabled=no rule=\
    "if (dst == 0.0.0.0/0 && dst-len == 0) { accept; }"
add chain=CUST2_customertransit_out_v4 disabled=no rule=\
    "if (bgp-large-communities includes 65551:0:1) { accept; }"
add chain=CUST2_customertransit_out_v4 disabled=no rule=\
    "if (bgp-large-communities includes 65551:0:2) { accept; }"

Transit provider… as you can see outbound is extremely simple and SAFE.

add chain=TRANSIT1_transit_in_v4 disabled=no rule="jump Protect_Transit_In;"
add chain=TRANSIT1_transit_in_v4 disabled=no rule="jump RPKI_Validate;"
add chain=TRANSIT1_transit_in_v4 disabled=no rule="if (dst in 0.0.0.0/0 && dst-l\
    en in 8-24) {\r\
    \n  set bgp-local-pref 100;\r\
    \n  append bgp-large-communities 65551:6:10,65551:0:6;\r\
    \n  accept;\r\
    \n} else {\r\
    \n  set bgp-large-communities 65551:7:5;\r\
    \n  reject;\r\
    \n}"
add chain=TRANSIT1_transit_in_v6 disabled=no rule="jump Protect_Transit_In;"
add chain=TRANSIT1_transit_in_v6 disabled=no rule="jump RPKI_Validate;"
add chain=TRANSIT1_transit_in_v6 disabled=no rule="if (dst in 2001::/3 && dst-le\
    n in 16-48) {\r\
    \n  set bgp-local-pref 100;\r\
    \n  append bgp-large-communities 65551:6:10,65551:0:6;\r\
    \n  accept;\r\
    \n} else {\r\
    \n  set bgp-large-communities 65551:7:5;\r\
    \n  reject;\r\
    \n}"
add chain=TRANSIT1_transit_out_v4 disabled=no rule="jump Advertise_Out_v4;"
add chain=TRANSIT1_transit_out_v6 disabled=no rule="jump Advertise_Out_v6;"

Peering over an IXP. Again simple and safe.

add chain=PEERING1_peering_in_v4 disabled=no rule="jump Protect_Transit_In;"
add chain=PEERING1_peering_in_v4 disabled=no rule="jump RPKI_Validate"
add chain=PEERING1_peering_in_v4 disabled=no rule="if (dst in 0.0.0.0/0 && dst-len\
    \_in 8-24) {\r\
    \n  set bgp-local-pref 200;\r\
    \n  append bgp-large-communities 65551:8:703,65551:0:8;\r\
    \n  accept;\r\
    \n} else {\r\
    \n  set bgp-large-communities 65551:7:5;\r\
    \n  reject;\r\
    \n}"
add chain=PEERING1_peering_in_v6 disabled=no rule="jump Protect_Transit_In;"
add chain=PEERING1_peering_in_v6 disabled=no rule="jump RPKI_Validate;"
add chain=PEERING1_peering_in_v6 disabled=no rule="if (dst in 2001::/3 && dst-len \
    in 16-48) {\r\
    \n  set bgp-local-pref 200;\r\
    \n  append bgp-large-communities 65551:8:703,65551:0:8;\r\
    \n  accept;\r\
    \n} else {\r\
    \n  set bgp-large-communities 65551:7:5;\r\
    \n  reject;\r\
    \n}"
add chain=PEERING1_peering_out_v4 disabled=no rule="jump Advertise_Out_v4;"
add chain=PEERING1_peering_out_v6 disabled=no rule="jump Advertise_Out_v6;"