ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RIP与OSPF双向重发布实战解析:从路由环路到种子度量排错

RIP与OSPF双向重发布实战解析:从路由环路到种子度量排错

作为一名常年跟多协议网络打交道的工程师,我对"重发布"这三个字其实是有点敬畏的。早几年做实验时,我在一台路由器上敲下 redistribute 命令,以为从此 RIP 和 OSPF 就能互通有无,结果路由表里瞬间出现一堆奇怪的路由,数据包绕了大半个网络又回到了起点,差点把一台核心设备搞到 CPU 满载。那次事故让我明白,重发布实验不是"把 A 协议抄进 B 协议"这么简单,它背后牵扯到种子度量、路由回灌、环路抑制、管理距离等一系列连锁反应。

这篇博客就把我当时做过的重发布实验完整复盘一遍。我会先讲清楚重发布到底要解决什么问题,再给出可复现的拓扑配置,然后重点拆解双向重发布时最容易踩的环路坑和种子度量坑,最后用验证手段说明数据平面到底走了哪条路径。无论你是刚学动态路由的网工新人,还是在准备认证的实验党,这篇内容应该都能让你少走几个弯路。

1. 重发布到底在解决什么问题

1.1 两个独立协议域的数据孤岛

很多企业网络并不会只用一种动态路由协议。合并进来的子公司可能还在跑 RIP,新建设的骨干网清一色 OSPF,甚至某些边缘设备为了对接运营商还会接上 BGP。协议不同,天然语言不通:OSPF 用链路状态计算最短路径树,RIP 靠跳数逐跳传递整张路由表。两个协议域内部都能自洽,但到了边界路由上,两边的路由表就像隔了一堵墙,彼此根本不知道对方那边有什么网段。

没有重发布的时候,边界路由器上只能靠手写静态路由把关键网段指过去。小规模没事,一旦路由条目超过几十条,静态路由就会变成维护噩梦。某个新网段上线,你得同时改好几台设备;某条链路断了,静态路由不会自己收敛。所以实验的第一目的,就是模拟这种真实场景:左边是 RIP 域,右边是 OSPF 域,中间用一台边界路由器连接,通过重发布让两边自动交换路由信息。

1.2 重发布的本质:在两套路由表之间建立桥梁

从实现原理看,重发布就是把路由表里来自协议 A 的路由条目,以协议 B 的路由格式重新注入到协议 B 的路由进程里。边界路由器在这个过程中充当翻译官。每个协议对路由优劣的判定标准不一样,OSPF 看 cost,RIP 看 hop count,所以翻译的时候必须给路由加上一个"初始开销",这个初始值就是种子度量(seed metric)。

如果种子度量设置不当,比如把 OSPF 路由重发布进 RIP 时不指定度量,RIP 默认会认为这条路由的跳数是无穷大,直接拒绝放进路由表。实验中很大一部分时间其实不是花在敲命令上,而是花在理解这种"翻译规则"上。理解了这一点,后续配置才有依据。

2. 拓扑搭建和基础配置:先把几个协议老老实实跑起来

2.1 实验拓扑与地址规划

我用三台路由器做了最简拓扑:R1 跑 RIP,R2 同时跑 RIP 和 OSPF,R3 跑 OSPF。R2 就是边界路由器,承担重发布任务。地址规划如下(环回口模拟业务网段):

设备接口网段协议
R1Loopback010.0.1.1/24RIP(模拟 R1 侧局域网)
R1G0/0192.168.12.1/24连接 R2
R2G0/0192.168.12.2/24连接 R1
R2G0/1192.168.23.2/24连接 R3
R2Loopback02.2.2.2/32管理地址
R3G0/0192.168.23.3/24连接 R2
R3Loopback010.0.3.3/24OSPF(模拟 R3 侧局域网)

所有设备用模拟器起就行,物理设备也可以,关键是两台边界设备之间不要跑任何额外策略,先把干净环境跑通,再逐步加重发布规则,这样排错时变量最少。

2.2 基础配置命令与验证

R1 的 RIP 配置很简单,宣告直连网段即可:

R1(config)# router rip R1(config-router)# version 2 R1(config-router)# no auto-summary R1(config-router)# network 10.0.0.0 R1(config-router)# network 192.168.12.0

R3 的 OSPF 配置:

R3(config)# router ospf 1 R3(config-router)# router-id 3.3.3.3 R3(config-router)# network 192.168.23.0 0.0.0.255 area 0 R3(config-router)# network 10.0.3.0 0.0.0.255 area 0

R2 先同时配置两种协议,但不做重发布:

R2(config)# router rip R2(config-router)# version 2 R2(config-router)# no auto-summary R2(config-router)# network 192.168.12.0 R2(config)# router ospf 1 R2(config-router)# router-id 2.2.2.2 R2(config-router)# network 192.168.23.0 0.0.0.255 area 0 R2(config-router)# network 2.2.2.2 0.0.0.0 area 0

此时验证一下:在 R1 上应该只能看到 10.0.1.0 和 192.168.12.0 这两条 RIP 路由,根本看不到 10.0.3.0 和 192.168.23.0。在 R3 上则看不到 RIP 域的路由。这正是"两个协议域互不相通"的初始状态,也是重发布要做出的改变。

3. 双向重发布的第一个教训:路由回灌导致的环路

3.1 双向重发布到底该怎么配置

要让两边互通,最简单的做法是在 R2 上做双向重发布:把 OSPF 学到的东西喂给 RIP,也把 RIP 学到的东西喂给 OSPF。命令如下:

R2(config)# router rip R2(config-router)# redistribute ospf 1 metric 3 R2(config)# router ospf 1 R2(config-router)# redistribute rip subnets metric 20

第一行表示 OSPF 路由注入到 RIP 时,初始跳数设为 3;第二行表示 RIP 路由注入 OSPF 时,cost 设为 20。我当时天真地以为这样配置完就万事大吉,结果一查看 R2 路由表,差点笑不出来。

3.2 为什么回灌会带来路由环路:距离矢量协议都这样

双向重发布跑起来后,R2 会把从 OSPF 学到的 10.0.3.0/24 重发布进 RIP,R1 能收到这条路由。同时,R1 原本就有一条直连路由 10.0.1.0/24,它通过 RIP 通告给 R2,R2 再把 10.0.1.0/24 重发布进 OSPF,R3 也能收到。表面上一切正常,但问题出在 R1 身上。

R1 可能通过 RIP 听到一条"从 OSPF 重发布进 RIP"的路由,这条路由的目的地其实是某个 OSPF 网段,而 R1 本身对这个网段一无所知,只能把数据交给下一跳 R2。这是正常行为。但如果 OSPF 域里也出现了 RIP 域内部的某个网段,而 RIP 域内部该网段的真实来源设备收到这条回灌路由,它可能认为"还有一个远端路径可以到达这个网段",于是把原本应该直接转发的流量绕到边界路由器上。

更典型的环出现在单向重发布漏配过滤时:R3 通过 OSPF 学到 10.0.1.0/24(这条路由来自 RIP 域重发布),如果 OSPF 域内部又把 10.0.3.0/24 通过重发布回灌到 RIP 域,RIP 域内的 R1 就会看到一条去往 10.0.3.0/24 的路径,而这条路径的下一跳还是 R2,R2 又回过头在 OSPF 域内找 10.0.3.0/24 的源头。数据包在 R1 和 R2 之间来回送,TTL 不断递减,直到丢包。

RIP 这种距离矢量协议更新路由时只关心跳数,不会做拓扑图的全局判断,所以非常容易把这种"回灌路由"当成一条有效路径。OSPF 属于链路状态协议,本身自带防环机制,但重发布进来的外部路由是"外部注入"的,OSPF 无法自动判断它是否应该存在。于是无论哪种协议做双向重发布,回灌都是头号隐患。

3.3 控制回灌的两种常用手段

我试过两种有效手段,都推荐写进实验笔记。

第一种是在重发布时用 distribute-list 过滤回灌路由。以 R2 为例,我不想让 RIP 域内的直连网段 10.0.1.0/24 跑进 OSPF 后再被 OSPF 学回来,也不想让 OSPF 域内的网段被 RIP 学回来后又被重发布回 OSPF。可以配置前缀列表,把需要保护的路由挡在重发布的入口外:

R2(config)# ip prefix-list BLOCK_LOOP seq 5 deny 10.0.1.0/24 R2(config)# ip prefix-list BLOCK_LOOP seq 10 permit 0.0.0.0/0 le 32 R2(config)# router ospf 1 R2(config-router)# distribute-list prefix BLOCK_LOOP in

但 distribute-list in 只能过滤进入 OSPF 进程的路由,对于 R2 内部的回灌判断还不够精确。更好用的是路由打标记(route tagging)方案:重发布进 OSPF 的 RIP 路由打上 tag 100,重发布进 RIP 的 OSPF 路由打上 tag 200,然后再写 route-map 拒绝掉 tag 匹配的外部路由。这种方式生产环境里维护起来最清晰,也方便排错。

当时我用了更直接的办法:单向重发布,只在 R2 上把 RIP 重发布进 OSPF,同时在边界方向用静态路由指回 RIP 域。这种方案可以避免双向回灌,但要维护的静态路由也不少,实验时评估一下工作量,根据实际情况选择。

4. 种子度量是个坑:为什么重发布后的路由老是不通

4.1 种子度量的默认值和惨案现场

我第一次做重发布时,第一版配置里漏掉了 metric 和 subnets 关键字,结果 R3 上死活学不到 RIP 域的路由。查了半天,发现 OSPF 对重发布进协议的路由如果没有特殊处理,默认不接收外部路由,必须加上 subnets 参数才会通告子网路由。

RIP 更讲究。把 OSPF 路由重发布进 RIP,如果不显式指定 metric,RIP 默认把这条路由的跳数设为 16,而 16 在 RIP 语义里就是不可达。R1 收到这条路由之后只会把它当垃圾丢弃,控制层面看路由表根本没有 10.0.3.0/24。所以我当时补上metric 3,R1 的路由表才出现跳数为 3 的外部路由。

如果重发布进 OSPF 不指定 metric,OSPF 默认会给外部路由一个 cost 20(OE2 类型)。20 意味着什么?如果 OSPF 域内部有路径到达同一网段,且内部 cost 小于 20,OSPF 会优先选择内部路径;只有内部路径不存在,或者内部 cost 大于 20,外部路由才会被选中。很多时候这会导致流量明明应该走重发布的出口,结果却绕道很远,问题不太好排查。

4.2 用 route-map 精确控制重发布行为

单纯的redistribute rip metric 20只能对所有 RIP 路由统一设置一个种子度量,没办法针对不同网段区别对待。我后来养成了用 route-map 包裹重发布的习惯,一套配置既能控制度量,又能顺手做过滤和打 tag。示例配置:

R2(config)# route-map REDIS_TO_OSPF permit 10 R2(config-route-map)# match ip address prefix-list RIP_LOOP R2(config-route-map)# set metric 50 R2(config-route-map)# set tag 100 R2(config)# router ospf 1 R2(config-router)# redistribute rip route-map REDIS_TO_OSPF subnets

上面这段命令的意思是:只有匹配 RIP_LOOP 前缀列表的 RIP 路由才允许进入 OSPF,并且 cost 强制改成 50,打上 tag 100。实验中 R3 收到 10.0.1.0/24 时看到的外部度量就是 50,可以完整验证重发布策略是否生效。

我在实测中发现,把外部路由类型从 OE2 改成 OE1(使用metric-type 1关键字)在很多场景下更符合直觉。OE2 只看外部种子度量,OSPF 内部路径的 cost 不累加;OE1 则会累加从边界路由器到目标的开销,路径选择更接近真实链路质量。实验时如果发现流量总是不走预期出口,我会先检查是不是 OE2 的默认特性导致选路偏差。

5. 实验现象验证与数据平面排查

5.1 控制平面验证命令组合

配置只完成一半,剩下的一半是验证。先看 R2 上重发布的结果:

R2# show ip route

关注外部路由标志,RIP 重发布进 OSPF 后,路由表里会出现O E2前缀的路由,那就是外部学习到的条目。在 R1 上则能看到 RIP 路由出现 OSPF 域网段的条目。此时再检查各设备的路由表是否完整。

用show ip protocols可以自查各协议的 filter 和 redistribute 列表是否生效,如果配置了 route-map,这里会显示具体关联关系。生产环境里这是首选排查命令,比反复敲 show run 快得多。

5.2 数据平面抓包分析

控制平面通,不代表数据平面顺畅。我实验时模拟了 R1 要 ping 通 R3 的 10.0.3.3 的场景。在 R2 与 R1 相连的接口上做抓包,观察 ICMP 报文是否还在反复被转发到其他接口。一旦出现 TTL exceeded,基本就是环路已经发生了。

检查数据平面时还要注意源目地址的往返路径是否一致。重发布后的网络中,去程走 RIP→OSPF,回程可能走 OSPF→RIP,如果其中一段被过滤或者路由表缺失,就会出现单向丢包。我在实验里遇到过去程能通、回程却不通的情况,最后发现是 OSPF 域内某台设备上有一条静态路由指向了错误下一跳,重发布本身没有任何问题。这个教训说明:出现故障时不要第一时间怀疑重发布,先把两端路由表对比一下,再做抓包判断。

5.3 真实模拟中的断连排障演示

为了演示完整排障思路,我特意把 R2 上的 route-map 临时改成拒绝 RIP 环回路由:

R2(config)# ip prefix-list DENY_RIP_LOOP seq 5 deny 10.0.1.0/24 R2(config)# ip prefix-list DENY_RIP_LOOP seq 10 permit 0.0.0.0/0 le 32 R2(config)# route-map REDIS_TO_OSPF permit 10 R2(config-route-map)# match ip address prefix-list DENY_RIP_LOOP R2(config-route-map)# set metric 50

这个时候从 R3 ping 10.0.1.1 应该失败,因为 10.0.1.0/24 根本没有进入 OSPF。我在 R2 上show ip route ospf确认外部路由消失,再查 R3 路由表也确实没有 10.0.1.0/24。这种一步步缩小范围的方法,比一上来就折腾链路要好用得多。实验里培养这种结构化的排查习惯,到了生产环境能省下大量故障时间。

6. 生产环境里我反复强调的几条红线

6.1 过滤一切你不想暴露的路由

很多人在实验里追求全网互通,把边界路由器的所有直连和环回全都不加选择地重发布出去。生产环境千万别这么干。管理地址、内部保留网段、终端接入网段,这些暴露出去只会增加路由攻击面。

我的经验是:明确列出允许重发布的网段清单,用前缀列表做白名单,不在白名单里的统统拒绝。这样即使边界设备之后新增了网段,也不会因为忘了配置而把敏感路由传播出去。

6.2 管理距离的非常规调整

重发布之外还有一个分支问题值得单独说:当同一台路由器从两种不同协议学到同一个网段,并且都出现在路由表时,路由优先级由管理距离决定。OSPF 内部路由管理距离是 110,RIP 是 120。默认情况下 OSPF 的路由会胜出。我遇到过一种情况,两个协议域之间确实有几个网段完全重叠,而我希望 RIP 域的路由优先(因为它在物理链路上时延更低),这时候单纯调整种子度量没用,必须调整管理距离才能实现预期。

实验时千万不要养成乱调管理距离的习惯,尤其不要为了应付考试把所有协议距离全部改成一样。管理距离一旦搞错,可能让整张路由表的行为变得诡异,而且这种问题非常难排查。

6.3 从实验走向现实的补充建议

最后给想把这个实验往生产环境迁移的读者几点建议。第一,重发布配置一定要做好回滚预案,建议在边界设备上提前保存重发布前的配置文件。第二,上线前先在隔离环境里仿真一遍,模拟真实的流量负载,看边界路由器的 CPU 是否扛得住。第三,监控上要配置路由抖动告警,重发布出的路由一旦出现频繁撤销和重新注入,往往比链路故障更先暴露问题。

我在实际项目里见过不少因为重发布细节没处理好而引发的生产事故,其中最常见的就是双向重发布时漏配过滤。这篇实验里的每个坑,基本都是从那种真实事故里反过来推出来的。希望你能把实验做透,把坑提前踩一遍,而不是在生产网络里重温这些教训。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进