资讯详情

资讯详情

FRRouting Route Maps 路由策略实战:从原理到BGP选路控制

1. 路由策略的底层逻辑为什么需要 Route Maps很多刚接触 FRRouting 的朋友会有一个疑问我明明已经把 OSPF、BGP 都配通了路由表里该有的条目也都有了为什么还要折腾 Route Maps 这个东西这个问题问得好因为它恰恰触及了路由策略的核心价值。先说一个最朴素的场景。假设你手上有两台边界路由器同时跑着 BGP从两个不同的上游各收到了一份默认路由。你希望主链路正常的时候走 A 上游A 挂了再切到 B 上游。如果你只是简单地让 BGP 把两条默认路由都装进路由表那选路就完全交给了协议本身的优先级规则你没有任何主动权。而 Route Maps 就是让你重新拿回主动权的工具——它允许你基于路由的各种属性下一跳、Community、AS Path、Metric 等来做匹配然后对匹配到的路由执行放行、丢弃、修改属性等操作。从 FRRouting 的实现角度看Route Maps 并不是一个独立运行的进程它是一套嵌入在 BGP、OSPF、 RIP 等协议内部的策略引擎。当你在一台 FRR 路由器上定义了一条 Route Map它本身不会产生任何效果必须被某个协议显式调用才会生效。这一点非常关键很多新手配了 Route Map 发现没起作用十有八九是忘了在协议里引用它。Route Maps 的本质可以用一句话概括它是一条或多条“匹配条件 执行动作”规则的有序集合。每条规则有一个序号sequence numberFRR 会按照序号从小到大依次检查一旦某条规则匹配成功就执行对应的动作permit 或 deny并且默认不再继续往下检查。这个“匹配即停止”的行为模式和防火墙的 ACL 非常像但 Route Maps 比 ACL 强大得多因为它不仅能控制“放不放行”还能在放行的同时修改路由属性。还有一个容易被忽略的点Route Maps 的默认行为。如果你定义了一条 Route Map 但里面只写了 match 条件没写动作或者调用时引用了不存在的 Route Map不同协议的处理方式可能不一样。在 BGP 中如果引用的 Route Map 不存在默认行为是 permit 所有路由但如果 Route Map 存在且所有条目都没匹配上默认行为是 deny。这个隐式 deny 规则坑过不少人后面我会专门展开讲。理解了这些你就知道 Route Maps 不是可有可无的装饰品而是路由控制的中枢神经。接下来我们逐层拆解它的语法结构、匹配机制和实战用法。2. Route Maps 的语法骨架与匹配引擎拆解2.1 一条 Route Map 条目的完整结构在 FRR 的配置体系里一条 Route Map 条目的标准写法是这样的route-map NAME permit|deny SEQUENCE-NUMBER match 条件类型 参数 set 动作类型 参数拆开来看NAME是这条 Route Map 的标识符同一个名字下可以有多条条目靠SEQUENCE-NUMBER区分顺序。permit和deny是这条条目的动作——匹配成功后是放行还是拒绝。match语句定义匹配条件set语句定义匹配成功后要执行的属性修改。这里有一个设计上的细节值得注意permit和deny是写在条目级别上的而不是写在 match 或 set 里面的。这意味着一条条目要么是 permit 要么是 deny不能在同一条条目里既放行又拒绝。如果你需要“匹配条件 A 的路由放行并改属性匹配条件 B 的路由拒绝”那就需要写两条不同序号的条目。序号的选择也有讲究。FRR 默认的序号步长是 5有些版本是 10也就是说你写route-map RM permit 10下一条自动就是 20。这个步长设计是为了方便你后续在中间插入新条目。比如你原来有 10 和 20 两条后来发现需要在它们之间加一条直接写route-map RM permit 15就行不用重新编号。我个人的习惯是步长用 10给自己留足够的插入空间。2.2 match 语句的匹配维度match 是 Route Maps 的“眼睛”它决定了哪些路由会被这条条目捕获。FRR 支持的 match 类型非常多常用的包括以下几类match 类型作用对象典型用途match ip address前缀列表或 ACL按目标网段匹配match ip next-hop前缀列表或 ACL按下一跳地址匹配match as-pathAS Path 列表按 AS 路径匹配BGPmatch communityCommunity 列表按团体属性匹配BGPmatch metric数值按度量值匹配match interface接口名按出接口匹配match tag数值按路由标记匹配match route-type路由类型按内部/外部路由匹配这里要特别说明一个容易混淆的地方match ip address后面跟的可以是标准 ACL、扩展 ACL也可以是前缀列表。但它们的匹配逻辑不同——ACL 匹配的是网络地址部分前缀列表匹配的是“前缀 掩码长度”。举个例子10.0.0.0/8这个前缀用 ACLpermit 10.0.0.0 0.255.255.255能匹配到用前缀列表ip prefix-list PL permit 10.0.0.0/8也能匹配到。但如果你想精确匹配10.1.0.0/16而不匹配10.1.1.0/24就必须用前缀列表因为 ACL 只看地址不看掩码长度。另一个关键点是 match 语句之间的逻辑关系。同一条条目内的多个 match 语句是“与”关系也就是说所有 match 条件都满足才算匹配成功。如果你需要“或”关系比如“匹配网段 A 或者匹配 Community B”那就必须拆成两条不同序号的条目。这个设计逻辑和很多人的直觉相反我第一次用的时候也踩过这个坑。2.3 set 语句能改哪些属性set 是 Route Maps 的“手”它决定了匹配成功后要对路由做什么修改。常用的 set 操作包括set ip next-hop 地址修改下一跳set local-preference 数值修改 BGP 本地优先级set metric 数值修改度量值set weight 数值修改 BGP 权重仅本地有效set community 数值设置或追加 Communityset as-path prepend AS号列表在 AS Path 前面追加 AS 号set tag 数值设置路由标记这些 set 操作里set local-preference和set weight是 BGP 选路中最常用的两个。它们的区别在于weight 是本地有效的不会传递给邻居local-preference 会在 IBGP 邻居之间传递但不会传出 AS。理解这个区别对于设计选路策略至关重要。set as-path prepend是一个“看起来简单但很容易用错”的操作。它的作用是在路由的 AS Path 前面插入指定的 AS 号从而让这条路由在邻居看来“路径变长了”降低被选中的概率。但要注意prepend 的 AS 号列表越长影响越大而且有些上游会对过长的 AS Path 做过滤。我一般建议 prepend 不超过 3 个否则可能触发对端的最大 AS Path 长度限制。2.4 隐式 deny 与空 Route Map 的陷阱这是 Route Maps 里最经典的坑没有之一。当你定义了一条 Route Map 并且被协议引用后如果一条路由没有匹配上任何一条条目FRR 的默认行为是deny。也就是说Route Map 末尾隐含了一条deny any。这个行为导致的最常见问题是你只想用 Route Map 修改某几条路由的属性其他路由原样放行结果配完之后发现其他路由全没了。原因就是你只写了匹配特定路由的 permit 条目没写兜底的 permit 条目。正确的做法是在 Route Map 末尾显式加一条route-map RM permit 9999不带任何 match 条件。这条条目会匹配所有剩余路由并放行。序号用一个大数比如 9999是为了确保它排在最后。还有一个相关的陷阱如果你引用了一个不存在的 Route Map不同协议的行为不一致。在 BGP 的neighbor x.x.x.x route-map RM in中如果 RM 不存在FRR 会报错并拒绝配置。但在某些其他场景下不存在的 Route Map 可能被当作“permit all”处理。所以我的建议是永远先定义 Route Map再在协议里引用不要依赖默认行为。3. 在 BGP 中落地 Route Maps 的完整实操3.1 入方向策略过滤与属性标记BGP 的 Route Map 应用分为入方向in和出方向out。入方向策略作用于从邻居收到的路由在写入 BGP 表之前生效。这是最常用的场景因为你无法控制邻居发什么但可以控制自己收什么。假设有一个场景你从某个上游收到了大量路由其中包含一些你不想要的私有网段比如 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16你希望把这些过滤掉同时对其他路由设置一个较低的 local-preference。第一步定义前缀列表来匹配私有网段ip prefix-list PRIVATE-NETS seq 10 permit 10.0.0.0/8 le 32 ip prefix-list PRIVATE-NETS seq 20 permit 172.16.0.0/12 le 32 ip prefix-list PRIVATE-NETS seq 30 permit 192.168.0.0/16 le 32注意这里的le 32它表示匹配掩码长度从 /8 到 /32 的所有子网。如果不写le 32就只精确匹配 /8 这一个前缀10.1.0.0/16 就匹配不到了。第二步定义 Route Maproute-map FROM-UPSTREAM deny 10 match ip address prefix-list PRIVATE-NETS route-map FROM-UPSTREAM permit 20 set local-preference 80 route-map FROM-UPSTREAM permit 9999这里第一条 deny 掉了私有网段第二条给剩余路由设置 local-preference 为 80第三条兜底放行。注意第二条和第三条的区别第二条会修改属性第三条不会。为什么需要第三条因为如果只有前两条那些既不是私有网段、又没有被第二条匹配到的路由实际上第二条没有 match 条件会匹配所有路由其实第二条已经能匹配所有剩余路由了。但为了逻辑清晰和防止未来修改时出错加一条纯 permit 的兜底条目是好习惯。第三步在 BGP 邻居上引用router bgp 65001 neighbor 203.0.113.1 route-map FROM-UPSTREAM in这里有一个实操中很容易忽略的细节入方向 Route Map 的修改是在路由进入本地 BGP 表之前生效的。也就是说如果你在入方向设置了 local-preference这个值会随路由一起进入 BGP 表并参与选路。但如果你在入方向设置了 as-path prepend这个修改只影响本地不会传递给其他邻居。3.2 出方向策略影响对端选路出方向策略作用于发送给邻居的路由在路由离开本地 BGP 表之后生效。出方向策略的典型用途是你希望某个邻居优先走某条路径或者你希望隐藏某些路由不让邻居看到。一个常见的出方向场景是多宿主环境下的流量引导。假设你有两条上行链路分别连到两个不同的上游你希望所有出站流量默认走上游 A只有在上游 A 不可用时才走上游 B。你可以在向上游 B 发送路由时给所有路由追加 AS Path prependroute-map TO-UPSTREAM-B permit 10 set as-path prepend 65001 65001 65001 route-map TO-UPSTREAM-B permit 9999然后在邻居上引用router bgp 65001 neighbor 203.0.113.2 route-map TO-UPSTREAM-B out这样上游 B 收到的路由 AS Path 会变成65001 65001 65001 65001原来的 65001 加上 prepend 的三个而上游 A 收到的是正常的65001。在 BGP 选路中AS Path 越短越优先所以上游 B 会觉得走你这里“绕了远路”从而降低优先级。这里有一个经验之谈prepend 的 AS 号必须是自己的 AS 号。如果你 prepend 了别人的 AS 号不仅不符合规范还可能被对端的 AS Path 过滤规则丢弃。另外prepend 的效果是累加的如果你在出方向对多个邻居都做了 prepend要小心 AS Path 长度超过对端的限制。3.3 用 Route Maps 实现 BGP 选路的精细控制BGP 的选路规则有十几条按优先级从高到低依次比较。Route Maps 可以在多个环节介入最常用的是通过修改 weight、local-preference、metric 和 AS Path 来影响选路结果。假设你有两条到同一目的网段的路径分别来自两个不同的 IBGP 邻居。你希望优先走邻居 A邻居 A 挂了再走邻居 B。最直接的做法是在入方向给邻居 A 的路由设置更高的 local-preferenceroute-map FROM-A permit 10 set local-preference 200 route-map FROM-B permit 10 set local-preference 100然后在两个邻居上分别引用。这样邻居 A 的路由 local-preference 是 200邻居 B 的是 100BGP 选路时会优先选 local-preference 高的。但这里有一个坑local-preference 只在 IBGP 邻居之间传递不会传出 AS。如果你是从 EBGP 邻居收到的路由设置 local-preference 是有效的因为这个值会在你的 AS 内部传递。但如果你想把 local-preference 传递给 EBGP 邻居那是不行的EBGP 邻居收到后会忽略这个属性。另一个常用的选路控制手段是set weight。weight 是 Cisco 私有的属性FRR 也支持。它的特点是只在本地有效不会传递给任何邻居包括 IBGP 邻居。所以 weight 适合做“本路由器独有”的选路决策不适合做全网统一的策略。3.4 调试 Route Maps 的实用命令配完 Route Map 之后怎么确认它真的生效了这是实操中最关键的一步。FRR 提供了几个非常有用的调试命令show route-map show route-map NAME show ip bgp 前缀 show ip bgp neighbors 邻居IP routesshow route-map会列出所有已定义的 Route Map 及其引用计数。引用计数这个信息很有用——如果你发现某个 Route Map 的引用计数是 0说明它没有被任何协议引用自然也不会生效。show ip bgp 前缀会显示这条路由的详细信息包括 local-preference、weight、AS Path、Community 等属性。你可以通过对比配置前后的输出确认 Route Map 是否按预期修改了属性。还有一个高级技巧在 Route Map 条目里加set tag或set community作为标记然后用show ip bgp community 值来验证哪些路由被这条条目匹配到了。这个方法在调试复杂的多条目 Route Map 时特别有效因为你可以直观地看到每条条目到底匹配了哪些路由。注意在生产环境调试 Route Map 时建议先在测试环境验证或者使用clear ip bgp 邻居 soft in做软重置避免硬重置导致 BGP 会话中断。软重置只会重新应用入方向策略不会断开邻居关系。4. 那些年我踩过的 Route Maps 坑与排查链路4.1 序号顺序导致的“策略不生效”有一次我帮朋友排查一个问题他配了一条 Route Map想把某个特定前缀的 local-preference 改成 200其他路由保持默认。配置大概是这样的route-map RM permit 10 match ip address prefix-list SPECIFIC set local-preference 200 route-map RM permit 20看起来没问题对吧但他发现特定前缀的 local-preference 确实是 200 了可其他路由的 local-preference 变成了空值默认 100而不是他期望的“保持原来的值”。原因在于第二条permit 20虽然没有 match 条件但它会匹配所有剩余路由并且由于没有 set 语句不会修改任何属性。这本身没问题问题出在他原来的路由是从 EBGP 学来的local-preference 默认就是 100所以看起来“没变”。但如果原来的路由是从 IBGP 学来的local-preference 可能是 200经过这条 Route Map 后反而被“重置”了。这个案例的教训是Route Map 的 set 操作是“覆盖”而不是“合并”。如果你不显式设置某个属性它不会被修改但如果你在一条条目里设置了某个属性它会覆盖原来的值。对于没有 set 语句的条目属性保持不变。4.2 前缀列表的 le/ge 参数写错导致匹配范围异常前缀列表的le和ge参数是另一个高频踩坑点。le表示“掩码长度小于等于”ge表示“掩码长度大于等于”。如果不写这两个参数就只精确匹配指定的前缀长度。我见过一个配置ip prefix-list PL permit 10.0.0.0/8 le 24配置者的本意是“匹配 10.0.0.0/8 及其所有子网”但实际上le 24表示掩码长度在 8 到 24 之间。也就是说10.1.0.0/16 能匹配到但 10.1.1.0/24 也能匹配到而 10.1.1.128/25 就匹配不到了。如果他想匹配所有子网应该写le 32。更隐蔽的一个问题是ge和le的组合。ge 16 le 24表示掩码长度在 16 到 24 之间不包括 /8 本身。这个语义和很多人的直觉不同——ge是“大于等于”所以 /8 不满足ge 16的条件。4.3 Route Map 引用顺序与协议默认行为的冲突在 OSPF 中引用 Route Map 做路由重分发时有一个容易忽略的细节OSPF 的 redistribute 命令默认只重分发主类网络边界。如果你从 BGP 重分发到 OSPF不加subnets关键字只有那些恰好落在主类网络边界上的路由会被重分发。这个行为和 Route Map 无关但经常和 Route Map 一起使用时产生混淆。排查这类问题的链路应该是先确认协议本身的重分发行为是否符合预期再检查 Route Map 的匹配条件是否正确最后验证 Route Map 的引用位置是否正确。我一般的排查顺序是show route-map NAME确认 Route Map 存在且引用计数不为 0show ip bgp 前缀或show ip route 前缀确认路由的属性是否被修改如果属性没变检查 match 条件是否真的匹配到了这条路由如果 match 条件看起来没问题检查序号顺序和隐式 deny 规则4.4 软重置与硬重置的选择修改入方向 Route Map 后需要重置 BGP 会话才能让新策略生效。FRR 支持两种方式clear ip bgp 邻居 soft in软重置只重新应用入方向策略不断开邻居关系clear ip bgp 邻居硬重置断开并重建邻居关系软重置的优点是不断邻居缺点是只对支持 Route Refresh 能力的邻居有效。如果邻居不支持 Route Refresh软重置会失败只能硬重置。硬重置的缺点是会导致短暂的流量中断在生产环境要谨慎使用。我的经验是在修改入方向策略前先确认邻居是否支持 Route Refresh。可以用show ip bgp neighbors IP查看 “Route Refresh Capability” 字段。如果支持放心用软重置如果不支持尽量在维护窗口操作。5. Route Maps 与其他策略工具的配合与边界5.1 Route Maps 与 Distribute List 的分工Distribute List 是另一个常用的路由过滤工具它的功能比 Route Map 简单——只能做过滤不能修改属性。那什么时候用 Distribute List什么时候用 Route Map我的原则是如果只需要过滤不需要修改属性优先用 Distribute List。因为 Distribute List 的配置更简洁性能开销也更小。Route Map 虽然也能做纯过滤但它的匹配引擎更复杂在大规模路由表下会有额外的 CPU 开销。但 Distribute List 有一个限制它只能引用 ACL 或前缀列表不能引用 AS Path、Community 等 BGP 特有的属性。所以如果你需要基于 AS Path 或 Community 做过滤就必须用 Route Map。5.2 Route Maps 与 Filter List 的优先级关系在 BGP 中Filter List 和 Route Map 可以同时作用于同一个邻居。它们的执行顺序是Filter List 先执行Route Map 后执行。也就是说如果一条路由被 Filter List 拒绝了它根本不会进入 Route Map 的处理流程。这个顺序在实际配置中很重要。如果你同时配了 Filter List 和 Route Map发现某些路由没有按预期被 Route Map 修改首先要检查是不是被 Filter List 提前过滤掉了。5.3 性能考量大规模路由表下的 Route Map 优化在承载完整互联网路由表的路由器上大约 90 万条 IPv4 路由Route Map 的性能是一个不可忽视的问题。每一条路由都要逐条检查 Route Map 的每个条目如果 Route Map 有几十条条目累积的开销会非常可观。几个优化建议把最可能匹配的条目放在前面。Route Map 是按序号顺序匹配的匹配到就停止。所以把命中率高的条目放在前面可以减少平均匹配次数。尽量用前缀列表而不是 ACL。前缀列表的匹配效率通常比 ACL 高尤其是在大规模路由表下。避免在 Route Map 里做复杂的正则匹配。AS Path 的正则匹配开销很大如果可以用简单的字符串匹配就不要用正则。定期清理不再使用的 Route Map。未引用的 Route Map 虽然不生效但会占用内存也会让配置变得混乱。5.4 Route Maps 在 OSPF 和 RIP 中的差异虽然 Route Maps 的语法在 FRR 的各协议之间基本一致但不同协议对 Route Map 的支持程度不同。BGP 对 Route Map 的支持最完整几乎所有的 match 和 set 操作都可用。OSPF 主要用 Route Map 来做路由重分发时的过滤和属性设置支持的 match 类型较少。RIP 的支持更有限主要也是用于重分发场景。一个具体的差异是在 OSPF 中set metric设置的是 OSPF 的度量值而在 BGP 中set metric设置的是 MEDMulti-Exit Discriminator。这两个值的语义和取值范围完全不同配置时要注意区分。还有一个差异是set tag的行为。在 OSPF 中tag 是一个 32 位的值可以随路由一起传播。在 BGP 中没有原生的 tag 概念set tag实际上是设置了一个 Community 或者扩展 Community。这个差异在跨协议重分发时特别容易出问题因为 tag 的格式和传递方式都不一样。6. 从零构建一套可复用的 Route Maps 模板6.1 入方向标准模板基于我多年的实操经验一套标准的入方向 Route Map 模板应该包含以下几个部分! 第一步定义前缀列表 ip prefix-list BOGON seq 10 permit 0.0.0.0/8 le 32 ip prefix-list BOGON seq 20 permit 127.0.0.0/8 le 32 ip prefix-list BOGON seq 30 permit 169.254.0.0/16 le 32 ip prefix-list BOGON seq 40 permit 192.0.2.0/24 le 32 ! 第二步定义 Route Map route-map RM-IN permit 10 match ip address prefix-list BOGON set community 65001:666 set local-preference 50 route-map RM-IN permit 20 set local-preference 100 route-map RM-IN permit 9999 ! 第三步在邻居上引用 router bgp 65001 neighbor 203.0.113.1 route-map RM-IN in这个模板的逻辑是先给“坏”路由打上 Community 标记并降低 local-preference然后给正常路由设置默认的 local-preference最后兜底放行。打 Community 标记的好处是后续可以用show ip bgp community 65001:666快速定位这些路由。6.2 出方向标准模板出方向模板的核心目标是控制对端看到的 AS Path 和 Communityroute-map RM-OUT permit 10 match ip address prefix-list OUR-PREFIXES set community 65001:100 route-map RM-OUT permit 20 set as-path prepend 65001 route-map RM-OUT permit 9999这个模板给自有前缀打上特定的 Community给其他路由追加 AS Path prepend。注意set community默认是覆盖操作如果你想追加而不是覆盖需要加additive关键字set community 65001:100 additive6.3 模板的版本管理与变更记录Route Map 的配置一旦多了很容易变得混乱。我的做法是给每个 Route Map 加注释记录它的用途、创建日期和最后修改日期。FRR 的配置文件支持!开头的注释行虽然这些注释不会出现在show running-config的输出里但在原始配置文件中是可读的。另外我建议把 Route Map 的变更纳入版本管理。每次修改前先备份当前配置修改后对比差异确认无误再提交。这个习惯在多人协作的环境下尤其重要因为 Route Map 的修改往往会影响整个网络的流量走向。6.4 验证清单上线前必须检查的几件事在把 Route Map 应用到生产环境之前我通常会过一遍这个清单检查项检查方法预期结果Route Map 是否被引用show route-map引用计数大于 0序号顺序是否正确show route-map NAME序号从小到大排列是否有兜底 permit查看最后一条条目存在无 match 的 permit前缀列表是否匹配预期show ip prefix-list NAME条目和预期一致软重置是否生效clear ip bgp 邻居 soft in无报错路由属性已更新是否影响现有流量对比修改前后的路由表关键路由未被误过滤这套清单看起来简单但能挡住 90% 的低级错误。我见过太多因为忘了写兜底 permit 导致整个 BGP 会话路由全丢的案例其实只要上线前多看一眼就能避免。6.5 一个真实场景的完整配置复盘最后分享一个我实际处理过的场景。某网络环境有两条上行链路主链路带宽大但价格高备链路带宽小但便宜。需求是正常情况走主链路主链路故障时自动切到备链路切换时间控制在 30 秒以内。我的方案是在备链路的入方向设置较高的 local-preference但通过 Community 匹配只对特定路由生效。具体配置如下ip community-list standard BACKUP permit 65001:200 route-map RM-BACKUP permit 10 match community BACKUP set local-preference 200 route-map RM-BACKUP permit 20 set local-preference 80 route-map RM-BACKUP permit 9999然后在主链路和备链路的邻居上分别引用不同的 Route Map。主链路的路由 local-preference 是 100备链路中带 Community 65001:200 的路由是 200其他是 80。这样正常情况下主链路优先主链路故障后备链路中带标记的路由接管。这个方案的关键在于 Community 的标记是在上游设置的我们通过匹配 Community 来识别哪些路由应该走备链路。这种“上游标记、本地匹配”的模式在多宿主环境中非常常见也是 Route Maps 最核心的价值体现。整个切换过程依赖 BGP 的收敛速度实测下来在 15 到 25 秒之间满足 30 秒的要求。如果对切换时间有更严格的要求可以考虑结合 BFD 做快速故障检测但那又是另一个话题了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →