
前一阵子帮朋友处理一个网络故障现象特别典型单位内网其他业务都正常唯独财务系统访问服务器时通时不通延迟从 1ms 一路飙到几百上千毫秒核心路由器 CPU 冲到 90% 以上。登录设备一看路由表同一个网段一会儿指向下一跳 A一会儿又指向下一跳 B来回横跳。懂行的人应该已经猜到了——这就是典型的“路由环路”。这个主题在计算机网络里几乎是所有教材的必考内容《计算机网络谢希仁版》动态路由章节、408 统考里都反复出现但真正的问题在于书里只讲了几行字的“环路”实际网络里却是从“间歇性丢包”到“全网瘫痪”的一连串故障。这篇文章我就把路由环路这件事彻底讲透包括它怎么形成、不同协议下有什么特征、现场怎么快速定位和止血以及你在模拟器里可以怎么亲手复现一次。不管你是被此类故障折磨过的运维新人还是准备期末考试的学生这篇文章都能给你一套能直接用的方法论。1. 路由环路是怎么形成的1.1 先看一个最简单的逻辑模型理解路由环路先从最简单的两台路由器开始。假设路由器 R1 和 R2 之间存在一条链路R1 有一条去往网段 X 的直连路由R2 从 R1 学到“去 X 走 R1”。这很正常流量 R2 交给 R1R1 直连送达 X。但如果 R1 与网段 X 之间的链路突然断了而 R1 还没来得及把这个变化告诉 R2问题就来了。R2 的路由表里仍然写着“去 X 走 R1”于是它把发往 X 的报文交给 R1R1 呢自己到 X 已经不通了但它的路由表里可能还残留着一条从 R2 学来的、经由 R2 去 X 的旧路由。于是 R1 又把报文原路退回给 R2。R2 再投给 R1R1 再退给 R2——数据包就在两台设备之间来回踢皮球。这有点像你让一个快递员送包裹去某个地址地址已经搬迁了他问隔壁邻居邻居说“你问前面那个人”前面那个人又说“你问后面那个人”最后包裹只能在一个小圈子里来回转永远送不到收件人手里。好在 IP 报文头里有一个 TTLTime To Live字段每经过一台路由器就减 1减到 0 时报文被丢弃并回送一个 ICMP 超时消息。所以环路不会让数据包无限循环下去但在 TTL 归零之前这个报文会在环路里反复消耗链路带宽、占用设备 CPU这才是环路最恶心的地方。1.2 动态路由协议为什么会“自己骗自己”看到这里你可能有个疑问动态路由协议不是会定时交换路由信息吗为什么链路断了R2 还不知道答案是路由收敛需要时间而在收敛完成之前网络中不同设备各自掌握的信息是不一致的。正是这种“信息不一致”制造了环路。以 RIP 为例这是最容易理解也最容易踩坑的协议。RIP 的度量值是跳数最大 15 跳16 跳代表不可达。假设拓扑是 R1—R2—R3网段 A 在 R1 后面。初始状态R2 从 R1 学到“去 A 跳数 1”R3 从 R2 学到“去 A 跳数 2”。一切正常。现在 R1 与 R2 之间的链路断了。R2 不会立刻删除去 A 的路由而是要等老化计时器超时。在这期间R3 还在周期性地向 R2 通告“我去 A 是 2 跳”——注意R3 的这条路由本来就是从 R2 学来的但 R2 此刻并不知道自己已经失去了 A。接下来就进入经典的“计数到无穷”过程R2 暂时没有更优的路径等到旧路由超时删除后它会接受 R3 通告的“去 A 经 R32 跳”。然后 R2 再把这个路由通告给 R3跳数变成 3R3 发现自己原来的 2 跳“更好”按理说不应该更新但如果 R3 的旧路由也已经老化它就会接受这个 3 跳的路径再通告回 R2 变 4 跳……如此往复跳数一路涨到 16协议才判定这条路由彻底不可达。RIP 为了防环其实做了不少设计。我把常用机制整理成一个表大家复习时可以对照着看防环机制原理能防住什么不能防住什么最大跳数15 跳内有效16 跳不可达兜底阻止报文无限转发报文仍会在 TTL 内反复空转业务已经断了水平分割从接口 A 学到的路由不再从接口 A 通告回去防止两台直连路由器互指三台以上设备组成的环防不住毒性逆转把不可达路由的跳数设为 16 再通告出去比水平分割更激进主动告诉邻居“这条路没了”同样不能覆盖多跳环路场景触发更新路由变化时立即发送更新不等 30 秒周期缩短故障发现时间更新报文丢失或顺序错乱时依然产生窗口抑制计时器收到路由变差的更新后进入保持状态暂时不接受更差路由抑制跳数快速增长让收敛变慢老路由在别的节点反而保留更久这里最重要的结论是RIP 的防环机制是“尽力而为”不是“绝对无环”。真正网络里多个计时器错位、更新顺序颠倒、配置错误叠加在一起环路照样会出现只是表现形式不同。2. 不同协议下的环路特征2.1 RIP 环境15 跳的“死亡倒计时”RIP 网络里的环路有一个非常鲜明的特征你看路由表时会发现某个网段的跳数在持续变大。比如上一秒看到[120/2]过三十秒变成[120/3]再过三十秒变成[120/4]直到涨到 16 然后整条路由消失。RIP 的设计本身就很“原始”周期更新默认 30 秒用 UDP 520 端口发广播或组播跳数就是唯一的度量标准。它根本不知道网络拓扑长什么样只知道“我听邻居说的邻居说远不远”。因此一旦发生故障所有路由器都只能靠“听说”来更新自己的认知而这种认知链条一断裂环路就容易钻空子。实际运维踩坑最多的地方是两类一是接口上有人手动关了水平分割以为能加速路由收敛结果把最重要的防环屏障拆了二是错误地宣告了 network 网段导致设备把不该通告的路由发给了邻居比如把内网管理网段通告进了生产网段两台设备同时掌握一条“次优路径”环路就在包里打转。记住一句话RIP 网络的任何一处配置变更都要确认“这条路由最终会不会被通告回来源方向”。2.2 OSPF 和 EIGRP看似无环环都藏在策略里很多人觉得 OSPF 和 EIGRP 算法先进不会产生环路这个想法平时没事但一到重分发和区域边界就能把人坑到哭。OSPF 在同一个区域内是严格无环的因为每台路由器都拥有完全一致的链路状态数据库SPF 算法算出来的是一棵无环的最短路径树。但区域之间依赖 ABR 生成和通告路由一旦区域间汇总错误、虚链路配置不当或者两台 ABR 对同一网段的通告逻辑不一致就可能出现流量在两个 ABR 之间来回绕行的“次优路径”本质上和环路的表现一模一样。还有一类常见配置多条默认路由从两个边界设备同时下发到骨干区域下发的路由被另一台边界设备学回去形成默认路由互指。EIGRP 的 DUAL 算法通过可行后继机制保证无环但前提是拓扑表里有合法的可行后继。当所有路径都失效时路由进入 active 状态设备会向邻居发起查询如果查询报文的响应顺序和内容有问题收敛期间照样会出现暂时性环路。不过说实话EIGRP 网络里真正的环路绝大多数还是重分发造成的。尤其是“双向重分发”这个操作把 RIP 的路由引到 OSPF再把 OSPF 的路由引回 RIP两边边界设备同时操作不加任何过滤和标记路由就可能在两个协议之间来回倒腾。我见过一个真实的案例核心交换机上跑 OSPF下面接的设备跑 RIP双点双向重分发后一台接入交换机的默认路由一会儿指向核心 A一会儿指向核心 B每次切换都伴随大面积丢包。表面看是“路由振荡”本质上就是重分发制造的“策略环”。3. 定位路由环路的标准排查流程3.1 从现象反推故障类型路由环路在现象层面并不难认难的是你要在第一眼判断出“这是环路”而不是误当成链路质量问题或设备性能问题。我习惯先看三个指标丢包形态、设备 CPU、路由表稳定性。现象环路嫌疑其他可能原因丢包不是连续丢而是时通时断延迟忽高忽低高链路拥塞、光模块劣化路由器/交换机 CPU 持续偏高接口流量不大却占用高高广播风暴、网卡故障、环路二层环路同一目的地址 traceroute 的路径在少数设备之间反复横跳极高路由策略错误、等价负载不均路由表中同一前缀的下一跳和 metric 频繁变化高邻居设备反复震荡、BFD/Hello 超时业务系统偶发超时个别用户访问内部服务器时好时坏中DNS 解析、服务器负载、防火墙策略重点说一下延迟忽高忽低这个特征。环路里的数据包每次经过一台路由器TTL 就减 1数据包在环路里兜的圈子越大时延就越大。而且这个过程不是均匀增加的——同一台 PC 发出的报文第一个包可能兜了 5 跳第二个包可能兜了 13 跳延迟完全不可预测用户体感就是“卡得要死但偶尔又能通”。3.2 三板斧traceroute、路由表、抓包确认环路靠三个工具基本就够我按排查顺序给你捋一遍。第一板斧是 traceroute。Windows 下用tracert -dLinux 下建议用traceroute -I -n因为很多设备不响应 UDP 高位端口用 ICMP 更可靠。当输出里连续几跳的 IP 地址在两三台设备之间反复出现比如“R2、R3、R2、R3、R2、R3”最后以* * *超时结束基本可以断定这就是环路。TTL 是逐跳递减的所以你能看到它兜了一圈又一圈直到耗尽。第二板斧是路由表。以思科设备为例重点看show ip route、show ip protocols、show ip rip database。环路出现时你会看到同一个前缀在不同时间点从不同接口学到metric 数值变化异常。比如 RIP 路由的 metric 从 2 跳到 3、跳到 4这说明设备正在“计数到无穷”。华为设备对应看display ip routing-table、display rip 1 route。这里有个细节如果路由表中的 AD管理距离相同、metric 却在持续变大几乎可以锁定是动态协议环路如果 AD 不同则可能是静态与动态策略互相覆盖造成的“策略环”。第三板斧是抓包。Wireshark 在链路两端的端口上做镜像抓包重点看两类报文业务数据流和路由协议报文。业务数据流要看 IP 头里的 TTL 字段如果同一源地址的报文反复出现、TTL 逐包递减说明它在环路里不断打转路由协议报文更直接RIP 报文里同一个网段的 metric 在一次又一次更新中不断变大这就是环路形成过程的实锤。顺带说一句二层的交换环路看 STP 状态和端口计数器三层路由环路就看 TTL 和路由协议报文两者不要搞混。3.3 抓包的两个关键位置和一个关键字段很多同学第一次抓环路抓不到不是因为抓包姿势不对而是抓错了地方。环路是动态路由设备之间的事情数据帧在环内的两台或多台设备之间打转你在终端侧、接入交换机侧去抓大概率什么都看不到因为那些“回转”的流量根本没有到达你的抓包点。第一个关键位置是环内两台设备之间的链路上。比如你怀疑 R2 和 R3 之间在互指就把抓包端口镜像在 R2—R3 这条链路上这样才能看到同一个报文反复穿梭。第二个关键位置是环内设备的入接口和出接口分别抓一遍对照看同一报文的到达顺序很快就能判断流量在哪两个设备之间来回。关键字段则是 IP 头里的 TTL。正常转发路径上TTL 每一跳只减 1一路平稳递减。当你在抓包里看到同一个源地址、同一个目的地址的报文TTL 从 255 快速降到 240、230甚至出现多个 TTL 值交替出现那就别犹豫了这是在环路里消耗生命。4. 动手复现模拟器里制造一次路由环路4.1 实验拓扑与基础配置纸上谈兵再多不如亲手复现一次。这个实验用 GNS3 或 EVE-NG 做最合适没有真机环境的话 Packet Tracer 也可以只不过 RIP 的实现细节有差异但看现象足够了。拓扑很简单三台路由器 R1、R2、R3 串联R1 和 R3 后面分别接一台 PC模拟两个业务网段。地址规划如下R1—R2 互联192.168.12.0/24R1 为 .1R2 为 .2R2—R3 互联192.168.23.0/24R2 为 .2R3 为 .3R1 连接 PC1 网段192.168.1.0/24R3 连接 PC3 网段192.168.3.0/24三台设备都启用 RIPv2关闭自动汇总。以思科 IOS 为例R1 的关键配置interface GigabitEthernet0/0 ip address 192.168.12.1 255.255.255.0 no shutdown ! interface GigabitEthernet0/1 ip address 192.168.1.1 255.255.255.0 no shutdown ! router rip version 2 no auto-summary network 192.168.1.0 network 192.168.12.0R2interface GigabitEthernet0/0 ip address 192.168.12.2 255.255.255.0 no shutdown ! interface GigabitEthernet0/1 ip address 192.168.23.2 255.255.255.0 no shutdown ! router rip version 2 no auto-summary network 192.168.12.0 network 192.168.23.0R3 同理宣告 192.168.23.0 和 192.168.3.0。配置完成后PC1 去 ping PC3 应该能通R1 的路由表里能看到192.168.3.0/24 [120/2] via 192.168.12.2说明流量路径是 R1—R2—R3跳数 2。4.2 制造故障亲眼看到环路这里我给你两条路线一条快速见效一条看协议的本质。快速路线直接模拟“默认路由互指”。在 R2 上加一条默认路由指向 R3在 R3 上加一条默认路由指向 R2R2(config)# ip route 0.0.0.0 0.0.0.0 192.168.23.3 R3(config)# ip route 0.0.0.0 0.0.0.0 192.168.23.2此时从 PC1 去 ping 一个不在路由表里的公网地址比如 8.8.8.8你把 traceroute 跑起来会看到什么路径会变成 R1 → R2 → R3 → R2 → R3 → R2……在 R2 和 R3 之间反复横跳直到 TTL 耗尽。这种默认路由互指在生产环境特别常见尤其是两个出口设备各自下发默认路由又通过动态协议互相学习时稍不注意就是一个环。协议本质路线做 RIP 计数到无穷。操作步骤是先把 R2 和 R3 之间的水平分割关掉然后断开 R1 与 R2 之间的链路或者在 R2 上触发路由刷新。关水平分割的命令interface GigabitEthernet0/1 no ip split-horizon然后在 R2 上开启 debugR2# debug ip rip之后你会在终端里看到类似这样的输出RIP: received v2 update from 192.168.23.3 on GigabitEthernet0/1 192.168.1.0/24 - 2 hops RIP: sending v2 update to 224.0.0.9 via GigabitEthernet0/1 192.168.1.0/24 - 3 hops RIP: received v2 update from 192.168.23.3 on GigabitEthernet0/1 192.168.1.0/24 - 4 hops看到这个输出你是不是对“计数到无穷”有了画面同一个网段的跳数在 R2 和 R3 之间一次比一次大1→2→3→4……直到变成 16路由被标记为不可达。这就是 RIP 环路从产生到终结的全过程。实验做完记得恢复配置把静态默认路由删掉把水平分割恢复别把环路留到明天。4.3 关于“16 跳”的底层逻辑很多人第一次看到 RIP 路由 metric 变成 16第一反应是“设备坏了”。其实 16 跳是 RIP 协议的一种“主动死亡宣告”任何路由只要跳数达到 16就代表这台设备认为该网段不可达。为什么是 15 和 16因为 RIP 的设计者很清楚在一个小型网络中超过 15 跳的路由大概率已经不可用了。他们把 16 作为“无穷大”的数字让环路在协议层面有一个自我终止的机制。这个设计和 IP 报文头的 TTL 一样都是给网络的混乱状态兜底的。理解了这一点再看 RIP 环路就不会慌环路不会永远持续下去它会在跳数涨到 16 的那次更新后终止。但问题是这个“计数到无穷”的过程需要多个更新周期每个周期 30 秒从 2 跳到 16 可能要好几轮而且这期间业务已经完全中断了。所以千万不要指望协议兜底你要做的是在它兜底之前主动干预。5. 故障处置先止血再治根5.1 快速恢复业务的几种手段真在现场遇到路由环路第一目标永远是“先把业务保下来”而不是坐下来慢慢查根因。我按操作速度和破坏性从小到大给你排个序。第一种用静态路由覆盖动态路由。RIP 的管理距离是 120一条普通静态路由的管理距离是 1优先级远高于动态路由。假如环路出现在去往 192.168.3.0/24 的方向直接加一条静态ip route 192.168.3.0 255.255.255.0 192.168.23.3这条更优的静态路由会立刻被路由表采用动态协议的坏路由就算还在协议层来回通告也不影响实际转发。华为设备对应ip route-static 192.168.3.0 24 192.168.23.3这招速度最快、副作用最小但它是治标等故障排查完记得把静态路由删掉。第二种用路由过滤阻断错误通告。如果你能快速判断出是哪个方向的通告在制造环路可以在接收方向加 distribute-list 或前缀列表把错误的前缀直接拒掉。思科命令示例access-list 1 deny 192.168.3.0 0.0.0.255 access-list 1 permit any router rip distribute-list 1 in GigabitEthernet0/1但这招要求你准确定位环路的源头在完全混乱的故障现场需要一定的冷静和判断力。第三种直接断开环路链路。如果上述办法都不好使观察路由表发现某台设备正在把错误路由通告给邻居直接在通告方向的接口上 shutdown 或者配置 passive-interface让环路从物理上断掉。代价是这条链路原有的正常业务也会受影响所以必须有心理准备这叫“壮士断腕”。5.2 根因修复配置审查与变更规范业务恢复之后不要以为事就完了。路由环路是一场故障的“果”前面一定有一个“因”。如果不去除因下一次故障早晚复现。最常见的一个因是 network 语句宣告了不该宣告的网段。有些同学在 Cisco 设备上配置 RIP 时习惯性地network 0.0.0.0把直连、环回、业务网段一股脑全宣告出去。本来直连网段宣告给邻居没问题但如果设备本身有冗余链路或备份路由就会把“本不该互相通告的路由”也搅进协议里。另一个常见因是重分发方向没有控制。前面说过双点双向重分发最容易制造策略环正确做法是在重分发时用 route-map 控制方向用 tag 给路由打标记并在另一个重分发点拒绝带特定 tag 的路由再进入。这就像快递单上写清楚“此单不要退回到发货地”每个中转站都在源头过滤一遍环自然无处可藏。最后一条可能很多人会忽略任何网络变更都要有验证和回退方案。我自己的习惯是变更前先show ip route存一份完整截图改完等 5 分钟再看一次路由表同时盯一段时间的日志。如果发现路由在震荡立刻执行回退脚本不要试图在深夜的故障现场“现场调优”那只会扩大故障面。5.3 一次凌晨割接的教训说一个我亲身踩过的坑。当时给一家单位的两个机房做出口设备替换新设备同时启用了 OSPF 和 RIP两边的边界设备都有重分发策略。我原本以为所有配置都是按标准模板做的结果割接完成之后核心交换机的路由表开始出现“灵异现象”某个办公网段的下一跳一会儿指向出口 A一会儿指向出口 B而且间隔不到五秒就切换一次。一开始我以为是 OSPF 邻居震荡看了邻居表稳定得很。后来发现是 RIP 侧的问题——新一代设备把 OSPF 学到的路由重分发进了 RIP老设备再把 RIP 路由导回 OSPF同一段路由在两个协议之间来回“倒手”。因为两边管理距离不同路由表里表现为 AD 和下一跳不断变化。最终解决是靠 tag在从 OSPF 导入 RIP 的路由上打上 tag 100然后在另一个边界设备的 RIP 导入 OSPF 方向加过滤拒绝携带 tag 100 的路由。那次割接之后我总结了一条铁律任何跨协议重分发必须双向过滤必须打 tag缺一不可。你不是在“优化网络”你是在给未来的自己埋雷。6. 常见问题排查速查表与避坑清单6.1 故障场景速查表我把实际工作中最常遇到的路由环路相关场景整理成一张速查表遇到问题时直接对照查。现象可能原因快速判断手段处理方向同一网段路由 metric 持续增大直到 16RIP 计数到无穷show ip rip database/ debug ip rip静态路由覆盖或过滤错误通告默认路由在 R2、R3 之间反复横跳边界设备默认路由互指traceroute 看路径反复删除错误的静态默认路由重分发加过滤OSPF 区域内路由频繁删除又恢复链路震荡 / 接口 flapshow ip ospf neighbor/ 查看日志排查物理链路和光模块检查 Hello/Dead 计时器重分发后路由表下一跳在 A、B 间不定期切换双向重分发无 tag 无过滤show ip route观察 AD 和 next-hop加 tag双向过滤规范重分发策略路由表正常但业务访问超时CPU 高二层环路或三层环路并存抓包看 TTL / 查端口计数器断环、查 STP、逐跳排查这里特别说一下“路由表正常但业务超时”这种情况。有些环路并不会让路由表立刻变成“反复横跳”因为设备可能通过等价路径或者策略路由把报文送进了环路而路由表本身看起来没什么异常。此时抓包看 TTL 是唯一可靠的判断方式不要因为“路由表看起来正常”就排除环路。6.2 关于网站“异常流量”提示的一个提醒写这篇文章之前正好看到有人搜索“我们的系统检测到您的计算机网络中存在异常流量。请稍后重新发送请求”这类提示说句实在话如果你只是访问某个网站时看到这个提示绝大多数情况下是网站侧的安全风控策略触发了比如出口 IP 被频繁请求、浏览器指纹异常、代理链路被共享等等跟你自己局域网里的路由环路没有直接关系。只有当你们网络内部真的有大范围广播风暴或环路导致出口流量特征明显异常才可能触发边界安全设备产生类似的告警。但这是“网络先坏了、安全设备报警”的顺序而不是“安全设备报警导致网络坏”。所以遇到这类提示先确认本地网络是否真的有异常流量表现再看是不是出口 IP 被风控别把锅甩给路由环路。6.3 独家避坑清单这几条是我从多次故障里换回来的经验专门写给在一线排查的人。第一生产环境慎用 debug。debug ip rip或debug ip routing在故障定位时确实直观但 debug 会大幅消耗设备 CPU在已经因为环路而满载的路由器上debug 可能直接把设备拖死。我的习惯是先用 show 命令和抓包缩小范围最后才考虑 debug而且 debug 时间不超过 30 秒看完立刻undebug all。第二traceroute 的输出要会看。很多情况下你 traceroute 出来某个节点* * *不代表这里就是环路。防火墙、设备限速策略、ICMP 过滤都会导致节点无响应。你要找的是“同一个 IP 反复出现”的模式而不是单纯看星号。第三抓包之前想清楚抓哪里。抓对位置比抓多久更重要。环路流量只在环内传播你抓错了链路抓一整天都看不到异常。第四区分“真环”和“次优路径”。次优路径只是绕路报文不会反复打转TTL 只会正常递减而真环路会让 TTL 快速递减甚至出现 ICMP Time Exceeded 的反馈风暴。TTL 是判断真环和次优路径的金标准不要看到路径绕路就喊环路。最后说点实在的。我自己第一次认真研究路由环路是刚入行时在一个老厂区的网络里当时一台接入交换机把一条默认路由通告到了核心核心又把它传给了另一台接入结果全网一半终端访问互联网都卡成幻灯片。那时候什么都不懂只会重启设备重启一次好一阵过一阵又犯。后来才明白网络故障从来不是“重启能解决”的而是“你要能讲清楚数据包到底在哪里打转”。所以我的建议很直接每个做网络的人都应该在模拟器里亲手复现一次路由环路。你在 GNS3 里把默认路由互指配出来看着 traceroute 在 R2 和 R3 之间来回横跳的那几分钟比你翻十遍教材都管用。那种“ping 不通但路径图清清楚楚”的顿悟感才是干这行真正值钱的经验。