RouterOS v7 路由过滤器学习笔记

RouterOS v7 路由过滤器学习笔记

发表于 2026/03/08 3185 字 12 分钟
AI 摘要 由 AI 自动生成

|

RouterOS v7 中 routing filter(路由过滤器) 的工作方式、语法结构、匹配属性、可执行动作、社区匹配、AS-PATH 正则、RPKI 与选择规则与 RouterOS v6 中存在较大的差异,本文整理通过 ChatGPT 5.4 Thinking 模型对这部分内容进行了整理。[1][2]

注意:该内容由人工智能(ChatGPT 5.4 Thinking 模型)进行生成。


RouterOS v7 的路由过滤器已经从 v6 那种偏“参数式”的风格,演进成一套更接近策略脚本语言的模型。其基本形式为:

if ( [matchers] ) { [actions] } else { [actions] }

过滤器规则不再只是简单的“匹配一个条件然后设置一个值”,而是支持布尔表达式、属性修改、跳转子链、返回父链、追加或删除 communities 等完整流程控制。[2]

对实际使用来说,最重要的理解是:

  1. 先匹配,再执行动作
  2. 并不是所有属性都能修改,有些属性只能用于匹配;
  3. 过滤链默认动作为 reject,没有显式 accept 的路由最终会被拒绝;
  4. 社区、扩展社区、大社区在 v7 中都有统一的匹配与修改机制;
  5. AS-PATH 正则在 v7 中语义已经变化,不能直接照搬 v6/Cisco 写法。[1][2]

v6 到 v7 的核心变化

协议配置结构变化

在 BGP 方面,ROS v7 不再沿用 ROS v6 的 instance / peer 模型,而是重构为 connectiontemplatesession 三部分。官方说明,这样做是为了将“连接相关参数”和“BGP 协议本身参数”明确分离,使配置结构更清晰。[1]

同时,v7 中很多原本分散的路由策略控制,也被统一到新的 /routing filter 框架里。BGP 会通过 input.filter-chainoutput.filter-chain 等方式将策略链挂接到会话输入与输出过程上。[1]

routing filter 的职责增强

在 OSPF 示例中,官方明确说明虽然 redistribution knob 在后续版本中回来了,但如果需要进一步控制哪些路由能被引入、以及修改 metric/type 等属性,仍然要使用 routing filter。[1]

这意味着在 ROS v7 中,协议负责挂载过滤器,过滤器负责做细粒度策略决策。[1]

v7 过滤器的执行模型

规则是脚本字符串

官方示例展示,v7 的过滤器规则是通过 rule="..." 的形式编写在字符串中的,例如:

/routing filter rule
add chain=myChain \
rule="if (dst in 192.168.1.0/24 && dst-len>24) {set distance +1; accept} else {set distance -1; accept}"

也就是说,规则本身是一段脚本,内部包含:

  • 条件表达式
  • 动作块
  • 可选的 else
  • 若干以分号结尾的语句。[2]

链默认拒绝

官方在 v6→v7 迁移文档中明确强调:routing filter chain 的默认动作是 reject。[1]

这点非常关键。实际效果是:如果一条路由走完整条链都没有遇到 accept,那么即使没有显式写 reject,它最终也不会被接受。[1][2]

accept / reject / jump / return

官方文档列出的主要控制动作包括:

  • accept
  • reject
  • jump
  • return

它们分别用于:

  • accept:接受当前路由并停止当前链处理;
  • reject:拒绝当前路由;
  • jump:跳到其他过滤链继续处理;
  • return:从被跳转的子链返回父链。[2]

因此,复杂策略推荐拆成“主链 + 子链”的结构,而不是写成一条很长的 if 语句。[2]

属性分类:只读与可读写

官方明确将路由过滤属性分为两类:[2]

只读属性

只能用于匹配,不允许修改。常见如:

  • dst-len
  • bgp-path-len
  • bgp-input-remote-as
  • bgp-output-remote-as
  • active
  • afi
  • protocol
  • ospf-dn

这些属性适合出现在 if (...) 里作为判断条件。[2]

可读写属性

既能匹配,也能通过 setappendunset 等动作修改。常见如:

  • distance
  • bgp-weight
  • bgp-local-pref
  • bgp-med
  • bgp-out-med
  • bgp-igp-metric
  • bgp-path-prepend
  • bgp-path-peer-prepend
  • gw
  • gw-ll
  • bgp-communities
  • bgp-ext-communities
  • bgp-large-communities

这类属性通常用于 BGP 策略控制、出口打社区、调整本地优先级、修改下一跳等场景。[2]

常用匹配语法

基本判断

官方示例表明,v7 支持布尔表达式与比较操作,例如:

if ( protocol connected ) { accept }
if ( bgp-med < 30 ) { accept }
if ( ospf-dn ) { reject }

这说明:

  • 某些 flag/布尔属性可以直接判断;
  • 数值属性可以用 <>== 等比较;
  • 多条件可以用 &&|| 组合。[2]

前缀匹配与 in

在前缀过滤中,dst in 192.168.1.0/24 表示当前路由前缀是否属于该网络范围。[2]

这对于常见的“允许某个聚合块及其子前缀输出”非常有用,例如:

if (dst in 2a05:dfc1:7100::/40 && dst-len <= 48) { accept; }

address-list 的坑

官方特别提醒:如果使用 dst in list_name,而该 list_name 是 address-list,那么其匹配逻辑源于 host-address 设计,可能会把 /32 也纳入命中范围。官方建议必要时同时加入 dst-len 约束,例如:

if (dst in list_name && dst-len < 32) { ... }

这对于做白名单输出控制或黑名单过滤时尤其重要。[2]

常用动作语法

set / unset

set 用于设置可写属性,例如:

set bgp-local-pref 200;
set distance +1;

官方也支持在原值基础上增减,例如 +1-1,甚至从其他数值属性读取值参与计算。[2]

unset 用于清空属性,官方文档中提到可用于如 pref-srcbgp-medbgp-out-medbgp-local-pref 等属性。[2]

append

append 用于向可追加属性中增加内容,典型场景就是 communities:

append bgp-communities 65000:100;
append bgp-large-communities 64999:1100:6939;

这也是 large community 正确的使用方法之一。[2]

delete / filter

官方说明:

  • delete:删除指定内容;
  • filter:删除“除指定值之外”的内容,相当于反向过滤。[2]

这些动作可以应用于:

  • 普通 communities
  • 扩展 communities
  • large communities
  • comment 等属性。[2]

BGP 场景最重要的几个属性

bgp-local-pref

用于 iBGP 内部优先级控制,是最常见的入口策略属性之一。例如按上游 ASN 给某个入口更高本地优先级:

if (bgp-input-remote-as == 6939) {
    set bgp-local-pref 200;
    accept;
}

该用法基于官方列出的 bgp-input-remote-as(只读)和 bgp-local-pref(可写)属性。[2]

bgp-path-prepend

官方说明,bgp-path-prepend 用于在 BGP output 时为本地 ASN 执行 prepend。也就是说,这是“我方向外发时,额外重复自己的 ASN 次数”的控制方式。[2]

bgp-path-peer-prepend

这个属性和上一个很容易混淆。官方说明它主要关联从对端收到的 prepend 信息,可以用于 input 中匹配“对方 prepend 过多”的路由,也可在某些场景下覆盖收到的 peer prepend 值。[2]

因此:

  • 我要对外 prepend 自己的 ASN:用 bgp-path-prepend
  • 我要检查对端 prepend 是否异常:看 bgp-path-peer-prepend。[2]

gw / gw-ll

官方说明,gwgw-ll 用于修改网关/下一跳,但在 BGP output 中并不是任何场景都能自由修改。尤其在 output 阶段,是否允许修改 next-hop,取决于会话属性、是否是 route reflector、是否启用了 nexthop-choice=propagate、是否为非 eBGP 且无 force-self 等上下文条件。[2]

因此,语法能写不等于一定能生效,这一点需要在实际出站策略中重点验证。[2]

Communities / Large Communities 的匹配与处理

社区匹配操作符

官方列出了多种社区匹配方式,包括:[2]

  • equal
  • equal-list
  • any
  • any-list
  • includes
  • includes-list
  • subset
  • subset-list
  • any-regexp

在工程实践中常见理解如下:

  • any:只要包含其中任意一个社区即可命中;
  • includes:必须包含指定的全部社区;
  • equal:当前社区集合必须与指定值完全一致;
  • subset:当前社区集合是给定集合的子集关系判断。[2]

使用社区列表

官方支持预定义:

  • /routing/filter/community-list
  • /routing/filter/community-ext-list
  • /routing/filter/community-large-list

这些列表可以被用于:

  • 匹配
  • 追加
  • 设置。[2]

对复杂网络策略来说,推荐把经常复用的上游控制社区、blackhole 社区、large communities 定义为 list,再在规则里调用,而不是每条规则都手写常量。[2]

大社区的正确写法

在 ROS v7 中,大社区属于 bgp-large-communities 这个属性。要给路由加 large community,应写成:

if (dst == 2a05:dfc1:710e::/48) {
    append bgp-large-communities 64999:1100:6939;
    accept;
}

而不能把 64999:1100:6939 直接裸写成“动作”。因为官方动作体系中并不存在“把一个 large community 常量直接当 action 执行”的语法,必须通过 setappend 作用到 bgp-large-communities 属性上。[2]

删除和清洗 communities

官方单独说明了 delete 对不同社区类型的支持范围:[2]

普通 communities

可删除:

  • wk
  • other
  • regexp 匹配项
  • 指定的 community-list。[2]

扩展 communities

可删除:

  • rt
  • soo
  • other
  • regexp 匹配项
  • 指定 ext-community list。[2]

Large communities

可删除:

  • all
  • regexp 匹配项
  • 指定 large-community list。[2]

这在出口策略中非常有用,例如:

  • 删除内部标记后再对外发布;
  • 对客户前缀清洗不应透传的内部社区;
  • 保留必要 RT / SoO,删除其它无关社区。[2]

AS-PATH 正则:v7 与 v6 不兼容

这是迁移时非常关键的一点。官方明确警告:不能把 ROS v6 或 Cisco 的 AS-PATH 正则直接复制到 ROS v7 中使用,因为 v7 的 AS-PATH 正则语义已经改变。[2]

官方举例说明:

  • 在旧语义中,1234[5-9] 可能被理解为字符串片段匹配;
  • 在 v7 中,它表达的是基于 ASN token 的匹配关系,即 1234 后面跟一个范围在 5-9 的 ASN。[2]

官方还指出:

  • 只有在 AS-PATH 存在时,正则才会匹配;
  • 不能用 ^$ 去匹配空 AS-PATH;
  • 如果要匹配“空路径”,应该使用 bgp-path-len。[2]

官方还提供了 /routing/filter/test-as-path-regexp 工具用于测试正则表达式。[2]

RPKI 与 select-rule

RPKI

官方在可执行动作中列出了 rpki-verify rpki_group_name,说明在过滤链中可以直接启用指定 RPKI 组进行验证。[2]

这意味着 RPKI 校验可以直接融入输入过滤链逻辑中,与 accept/reject、社区处理、标签标记等策略联动。[2]

select-rule

官方还介绍了 /routing/filter/select-rule,它并不是普通的 input/output filter,而是用于从候选路由集中挑选出符合条件的项。官方示例中甚至可以通过单独的 chain 去表达“只选 active 路由”的逻辑。[2]

这一机制对于高级选路与输出控制场景有较强扩展性,但日常 BGP 邻居入站/出站策略中用得相对少一些。[2]

filter wizard 辅助生成过滤规则

官方文档提到,从 v7.20 开始提供 /routing/filter/filter-wizard,用于帮助用户生成过滤规则。这从侧面说明 v7 的过滤器虽然功能更强,但语法和心智负担也明显高于 v6。[2]

因此在生产环境中,推荐:

  • 通过子链进行模块化设计;
  • 通过 community list / large-community list 进行对象复用;
  • 避免在 CLI 中临时手写非常长的 rule="..." 字符串;
  • 在变更前先验证语法与逻辑路径。[2]

面向 BGP 实战的推荐写法

按 AFI 分流

官方支持 afi 作为匹配属性,可识别 ipv4ipv6l2vpnvpnv4vpnv6 等地址族。[2]

因此,在双栈 BGP 策略中,建议先在主链按 AFI 分流,再分别跳转到 IPv4 / IPv6 子链中处理:

/routing/filter/rule
add chain=bgp_in rule="if (afi ipv4) { jump v4_in; } else { jump v6_in; }"

先匹配,再修改,再 accept

推荐统一采用下列风格:

if (条件) {
    set/append/delete ...;
    accept;
}

这样最符合 v7 的执行模型,也最不容易出现“语法看起来像对,实际上动作块不成立”的问题。[2]

next-hop 改写前先确认条件

由于官方明确说明 gw / gw-ll 的生效受 output 上下文约束,因此在设计 set gw ...set gw-ll ... 时,需要同时检查:

  • 邻居是 eBGP 还是 iBGP;
  • 是否 reflector;
  • nexthop-choice 是什么;
  • 是否 force-self;
  • 是否在 output 阶段改写。[2]

实战示例

按 IPv6 前缀打 large community

/routing/filter/rule
add chain=bgp_out rule="if (dst == 2a05:dfc1:710e::/48) { append bgp-large-communities 64999:1100:6939; accept; }"

说明:对指定 IPv6 前缀增加 large community,再接受输出。[2]

限制对端过度 prepend

/routing/filter/rule
add chain=bgp_in rule="if (bgp-path-peer-prepend > 4) { reject; }"

说明:对方 prepend 过多时直接拒绝,适用于清理异常路径。[2]

按来源 ASN 提高本地优先级

/routing/filter/rule
add chain=bgp_in rule="if (bgp-input-remote-as == 6939) { set bgp-local-pref 200; accept; }"
add chain=bgp_in rule="accept"

说明:来自 AS6939 的路由提高 local-pref,其余默认接受。[2]

限制可发布的前缀块与掩码长度

/routing/filter/rule
add chain=bgp_out rule="if (dst in 2a05:dfc1:7100::/40 && dst-len <= 48) { accept; }"
add chain=bgp_out rule="reject"

说明:只允许指定聚合块内、且不超过 /48 的前缀输出。[2]

清洗不应对外发布的社区

/routing/filter/rule
add chain=bgp_out rule="delete bgp-communities wk,other; accept;"

说明:将普通 communities 中的 well-known 或 other 类项清洗后再输出。是否这样删,需要按实际策略决定。[2]

最容易踩的坑

忘写 accept

因为链默认是 reject,所以少写一个 accept 就可能导致整个策略链“看起来正常,实际上全丢”。[1][2]

把 large community 当动作写

正确写法是:

append bgp-large-communities 64999:1100:6939;

而不是裸写 64999:1100:6939。后者不符合 v7 的动作语法。[2]

直接照抄 v6/Cisco 的 AS-PATH 正则

官方明确不建议这么做,因为语义已变,可能造成严重误匹配。[2]

误以为 set gw 必然生效

官方已说明 BGP output 的 next-hop 改写受会话上下文限制,因此必须结合具体 BGP 角色与会话属性判断。[2]

address-list 误匹配 host route

使用 dst in list_name 时,应根据需要补充 dst-len 限定,避免匹配到不希望处理的 /32。[2]

结论

RouterOS v7 的 routing filter 已经不再只是一个“附加条件的小工具”,而是一套覆盖匹配、修改、流程控制、社区处理、RPKI 验证、路由选择的完整策略语言框架。[2]

对于生产环境,推荐采用以下实践:

  1. 主链负责分流,子链负责细分策略;
  2. 所有出口、入口策略都显式写 accept / reject
  3. 将 communities、large communities 做成 list 复用;
  4. 对 next-hop、prepend、local-pref 等属性的修改,严格区分 input 与 output 语义;
  5. 所有 AS-PATH 正则先用官方测试工具验证,再上线;
  6. 迁移 v6 配置时,不要机械照抄旧语法,要按 v7 逻辑重新审视。[1][2]

参考来源

[1] MikroTik. Moving from ROSv6 to v7 with examples. RouterOS Documentation. Last updated Feb 19, 2026. Available at: https://help.mikrotik.com/docs/spaces/ROS/pages/30474256/Moving+from+ROSv6+to+v7+with+examples

[2] MikroTik. Route Selection and Filters. RouterOS Documentation. Last updated Feb 09, 2026. Available at: https://help.mikrotik.com/docs/spaces/ROS/pages/74678285/Route+Selection+and+Filters

作者: 小谈谈
声明: 本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。