搞网络的人,对BGP的第一印象通常是“稳定”“能扛事”。但真实网络里,BGP最让人头疼的恰恰不是它不够稳,而是它太“稳”了——即便拓扑已经出了严重问题,它也能把流量稳稳地送进环路,或者稳稳地走进一条次优路径,让你排查半天都摸不着头脑。
环路和次优路径是BGP绕不开的两个经典问题。环路属于“显性故障”,一旦发生,流量要么打转要么丢包,现象非常扎眼;次优路径则属于“隐性故障”,网络能通、延迟能忍,但带宽利用率、路由收敛速度统统不达标。这篇文章就把这两个问题掰开揉碎:为什么会发生、怎么判断、怎么处理,以及我在实际网络里踩过的一些坑。
适合谁看?网络工程师、运维、刚学BGP没多久但对“为什么明明有两条链路却只走一条”充满疑惑的人。基础概念不会讲太多,但涉及命令和配置的部分,我会按主流厂商的命令行习惯来写,思路是通用的。
1. BGP环路问题的原理与误解:AS_PATH到底防住了什么
1.1 为什么有了AS_PATH还会有环路:拆解防环机制的边界
BGP是路径矢量协议,防环的核心机制是AS_PATH。原理很简单:自己AS号已经在某条路由的AS_PATH里了,就不再接收这条路由。这和“快递单上的中转记录”一个道理——如果你是第5个中转站,看到单子上已经有你了,说明这包裹在外面转了一圈又回来了,绝对不能收,收了就成死循环。
这个机制防住了什么?防住了跨AS的环路,而且是只在AS_PATH还“诚实”的情况下有效。
有人会误以为有了AS_PATH,BGP就绝对不会出现环路。这个理解有两个漏洞:
第一,AS_PATH防环依赖“AS号必须全局唯一”的前提。现实中私有AS号被不同企业重复使用、运营商拆分合并、旧AS号被重新分配的场景还挺常见。一旦两个不同机构用了同一个AS号,路由器可能把一条正常的新路由误判为环路而丢弃,也可能因为两边都往里添加同一个AS号导致环路检测失效。
第二,AS_PATH只在BGP域内有效。到了AS内部,IBGP的防环靠的是另一套规则——即“从IBGP对等体收到的路由不会传给另一个IBGP对等体”,但这条规则在引入路由反射器之后被打破了。BBGP的环路风险并没有消失,而是转移到了Cluster List和Originator ID的机制上,很多人配置路由反射器时把这些属性忽略掉,就会有隐患。
我做一个表格把“防环机制”和“对应弱点”对照起来:
| 防环机制 | 解决什么 | 失效条件或盲区 |
|---|---|---|
| AS_PATH(EBGP) | 跨AS转发环路 | AS号重复、私有AS号泄露、聚合路由丢失AS_PATH |
| IBGP水平分割 | AS内部IBGP转发环路 | 配了路由反射器后不再适用 |
| Cluster List(RR) | 反射器簇内环路 | 没有正确配置Cluster ID、RR互相嵌套 |
| Originator ID(RR) | 防止始发路由被反射回来 | 某些厂商不强制检查,多级反射时容易漏 |
1.2 真实网络中环路出现的三种场景
这里不说理论,直接说故障现场。
第一个场景:AS号配置错误。某公司网络用了一套私有AS号,比如AS 65001和AS 65002,本来一条从AS 65001到AS 65002的EBGP链路配得好好的。结果某天扩容时,在核心路由器上把本端AS号误配成了AS 65002。双方都以为对端是外部邻居,但更新报文里带的AS_PATH会逐渐包含本端AS号,路由被丢进黑洞,表现为部分网段能通、部分网段完全不通,而且时通时断。这种问题最坑的地方在于,BGP会话能建立,邻居关系是Up的,不细看配置根本发现不了AS号错了。
第二个场景:私有AS号泄露到公网。多个分支机构使用相同的私有AS号与总部建立EBGP,总部收到这些路由后,如果没做as-path替换或as-path过滤,这些私有AS号会原样出现在BGP路由表里。当分支之间需要互相访问时,一条路由可能被一个分支接受后,又被另一个分支学习到,而AS_PATH里已经有自己的私有AS号了,正常协议逻辑会丢弃——但如果你中间还有AS号转换或联盟配置,这套逻辑就会乱套,最终形成环路。
第三个场景:BGP路由反射器下配了“假邻居”。路由器反射器的设计里,客户端和RR之间可以形成多级反射。如果两个RR互为非客户端,同时又把对方设为客户端,就可能让路由被重复反射,Cluster List在部分厂商实现里默认不检查或者检查不严,环路就会从反射层面诞生。而且这种环路不像跨AS环路那样有AS_PATH可以看一眼就发现,排查起来特别费劲。
2. 次优路径问题:比环路更隐蔽的“慢性病”
2.1 次优路径的产生机制:选路规则与真实拓扑的错位
BGP的选路规则大家都背过:Weight、Local Preference、本地始发、AS Path长度、Origin类型、MED、EBGP优于IBGP、IGP metric……问题是这套规则是“顺序比较”,而不是“全局优化”。每条规则都只比较一个属性,一旦前面几步分出了胜负,后面的优劣就不看了。这导致一个常见现象:协议认为的最优路径,恰恰是你最不想让流量走的路径。
打个比方,BGP选路就像在餐厅点套餐。规则规定先比价格,再比分量、再比口味。结果隔壁套餐便宜一块钱但难吃得要命,你捏着鼻子也要选它,因为价格这一步已经赢了。网络里的“难吃”就是高延迟、高丢包、过拥塞链路,但在BGP看来这些都不算指标。
还有一个底层原因:BGP是距离矢量协议,对网络拓扑的认知来自邻居的“转述”。它不像OSPF那样自己掌握全网拓扑,因此无法判断哪条路径在物理上更优。IGP metric虽然是接口比较项之一,但它在整个选路顺序里排在MED之后,而且只影响IGP开销的计算,无法弥补前面几步的“错误选择”。
2.2 最典型的四个次优路径场景
场景一:IGP metric让流量绕路。假设AS内部有两个出口路由器R1和R2都连接上游运营商,从上游学到同一条前缀。BGP选路时,前面Weight、LP、AS Path这些都一样,最后通过比较到达Next Hop的IGP metric决定胜负。R1的环回口IGP cost是10,R2的是20,BGP就会把所有流量都塞给R1。但如果R1的带宽只有100M,R2有1G,这就是典型的次优:协议选了IGP cost更小的R1,人眼看到的却是带宽更大的R2才是理性选择。
场景二:MED引发的不对称。MED是EBGP邻居之间传递的偏好值,原则是值越小越优。很多人以为MED只在同一个AS传来时才有可比性,跨AS时必须谨慎,但实际网络中经常有两台ASBR从同一个上游AS分别学到同一条前缀,上游给你两个入方向配了不同MED,你的设备就会把流量集中到MED小的那个入口——哪怕那条链路延迟更高、更拥塞。
场景三:路由反射器导致的下游次优。主干路由器通过RR反射学到所有BGP路由,下游设备从RR学到的路由不携带真实的IGP metric信息,无法反映到实际下一跳的开销。于是明明有一台更近的BR可以直接学习这条路由,却因为RR反射的路径优先,流量在AS里多走了好几跳。这类问题的特点是:igp很健康,BGP邻居都正常,但流量模式怎么看怎么别扭。
场景四:Weight和LP的“手滑”。很多团队习惯在边界路由器上用route-map给某些前缀设置高的Local Preference。如果规则写得太宽——比如配了前缀列表但没精确匹配掩码长度,把/24和/32一并匹配了——那一条本不该走这条链路的明细路由也会被拉过来,次优路径就这么产生了。这种问题最难排查,因为配置“看起来”完全合理。
我再单独说一个很多资料里没讲透的点:次优路径还会引发“路由震荡”。当IGP拓扑发生变化时,BGP的最佳路径可能在不同候选路径之间来回切换,导致转发面持续更新,CPU飙高,BGP表不稳定。这时候你会在日志里看到频繁的“BGP: best path change”信息。很多人把这个当抖动问题排查,查来查去才发现是次优路径和主路径之间在“左右横跳”。
3. 排查寻路问题的实操方法:从show命令到流量验证
3.1 环路排查:show命令组合拳
排查环路,核心思路是“还原路由的传播路径”。
第一步,看BGP路由表,找到出问题前缀的完整路径列表。以主流厂商的命令为例:
show bgp ipv4 unicast 10.10.0.0/24这条命令会列出该前缀的所有路径,包括已接收的、被拒绝的,以及每条路径的AS_PATH、Next Hop、MED、Local Preference。如果同一条前缀在路由表里出现多次,AS_PATH各不相同,就要警惕了。
第二步,看AS_PATH的走向。在路径数量较多的场景,可以用正则表达式过滤:
show bgp ipv4 unicast regexp ^65001$如果发现一条路由的AS_PATH里含有本端AS号,那基本就是环路被防住了——路由一直被丢。如果AS_PATH里没有本端AS号,可流量现象却像环路,那就需要更大范围地检查。
第三步,查看BGP路由被丢弃的原因。很多平台有直接查看失效路由的命令:
show bgp rib-failure这能看到某个前缀因为什么原因没有进入路由表,比如“BGP route was not installed because the next hop is unreachable”“BGP route was not installed because the AS path contains the local AS”。
第四步,验证数据面。在路由器上发起ping或traceroute,观察TTL的递减规律。如果TTL逐渐归零,数据包在一个狭窄区域内反复绕圈,说明环路可能没有被BGP检测拦截,而是转发层面的问题。这种情况多见于“BGP路由正常但FIB表异常”或者“多台设备间静态路由与BGP路由互相作用”的场景。
第五步,检查BGP会话信息。有些环路源于邻居关系异常,比如AS号配置错误导致的“假EBGP”:
show bgp neighbors 192.0.2.1重点看“BGP version”“remote AS”和“local AS”的对应关系。如果远端设备声明的AS号和实际配置不一致,这里会暴露出来。
3.2 次优路径排查:路径比较的方法论
次优路径的排查不靠猜,靠“逐条比较”。
第一步,先确定当前选中的最优路径是谁。用上面的show命令看哪个路径前面有星号(*),那就是当前被选中的路径。
第二步,把候选路径的全部属性拉出来。包括Weight、Local Preference、AS_PATH长度、Origin、MED、下一跳的IGP cost。按BGP选路顺序从上到下逐个比较,找到“决定胜负的那一个属性”。这一步通常能定位次优的原因——比如两条路径其他全一样,但IGP cost一个10一个20,那你就能确认:次优的根因是IGP metric差异。
第三步,反向思考“为什么路由不是从另一条路径学到的”。有时候次优路径不是“选错了”,而是“根本没见过更优的那条路径”。比如你在边界路由器上只从RR学路由,而没有直接与真正的源设备建立IBGP会话,那你永远看不到那条更优路径。这时候需要检查是否还有未建立的对等体、未通过的入向策略、前缀被max-prefix限制等。
第四步,用traceroute验证实际转发路径。特别注意:BGP路由表里最优的那条路径,和数据面实际转发的路径可能不一致。多台设备之间路由策略复杂时,边界路由器选了对的路径,但内部路由器因为缺少明细路由或者默认路由方向不对,又把流量导到了另一台设备。这是我反复强调的一点——控制面选路和转发面动作必须分开验证。
3.3 用further checking验证跨AS环路与次优
跨AS场景下,单独一台设备的视角是有限的。如果怀疑问题发生在AS之间的边界,建议做几件事:
- 向对端AS的管理员索取对方BGP路由表里这条前缀的AS_PATH,对比本地设备看到的AS_PATH,判断在哪一跳开始分叉。
- 检查双方的入向、出向策略。很多环路的起点是一台的route-map里用了deny加精确的prefix-list,另一台的route-map里却用了permit加any,这种不对称会给环路创造条件。
- 次优路径的跨AS排查,重点看“MED属性是否被双方正确理解”。某些运营商把MED当作内部链路的加权指标,传递给对端后,对端可能把它当作全局偏好,导致选路标准在不同AS之间产生歧义。
4. 解决方案与配置优化:把环路挡在门外,让流量走直线
4.1 解决环路问题:从配置到设计
环路问题的修复,关键在“让AS_PATH恢复诚实”。
如果是AS号配置错误:将本端AS号改正,确保EBGP对等体之间的AS号不重复、与对端记录一致。记住,改完AS号后,会话会中断重协商,这是正常现象。
如果是私有AS号泄露:在边界设备上配置AS号替换,或者AS号过滤,保证私有AS号不出公网。这里要注意,AS号替换本身也有风险——如果一台设备同时与多个AS建立EBGP,替换规则要按邻居分别设置,不能一刀切。
如果是IBGP路由反射器环境下的环路:认真规划RR的层级。标准做法是:核心层RR、汇聚层客户端,不要层层反射、不要多RR互为客户端。Cluster ID在整个RR组里保持唯一,避免重复Cluster ID导致路由被误吞。
另外我强烈建议在所有EBGP边界启用TTL安全检查(GTSM),它虽然不直接防环,但能挡掉一批来自错误方向的BGP报文,间接减少环路有关的异常情况。
4.2 次优路径的优化策略:让协议听懂你的意图
解决次优路径,常见手段是对症下药,修改选路过程中的某个决定性属性。
如果希望按带宽或链路质量选择出口:用Local Preference。在入向接收的route-map里,给期望的链路学到的路由设更高的LP。这种方式在IBGP/EBGP都有效,且在整个AS内传播,是最常用的手段。
如果希望入方向流量走指定入口:用MED。在对端AS的边界路由器上,对从不同出口学到的路由设置不同的MED值,值越小越优选。注意MED只影响相邻AS,不要试图跨多跳控制远端的选路。
如果希望IGP cost不主导BGP选路:可以考虑调整BGP的Next Hop跟踪机制,在某些平台上,你可以让BGP对特定的下一跳进行持续探测,而不是完全依赖IGP表。这种方式适用于“IGP正常但BGP路由总选错下一跳”的场景。
如果遇到多路径场景:启用BGP负载均衡(Multipath)。前提是两条路径的AS_PATH长度一致、属性一致,然后让设备同时把多条等价路径放入路由表。这在双出口场景里能极大缓解次优路径造成的带宽浪费。
如果问题是“下游设备的次优”——下游路由器总是通过RR学到路由而不是通过直连的边界路由器:在下游与边界路由器之间增加直接IBGP会话,或者调整下游设备的LP策略,让直连EBGP学到的路由优先。
4.3 从设计层面根治:一次处理,长痛不如短痛
每次故障排查后,都应该回到网络设计层面问一个问题:为什么当初这个隐患会存在?
- 路由策略是否标准化?有没有人为了“临时解决一个问题”而在某台设备上加了无法解释的LP或AS_PATH prepend?
- IBGP会话是否全互联?如果为了减少会话数而使用RR,是否有完整的RR规划文档?
- 出口链路是否做了主备?如果做了,主备切换的判定依据是链路状态还是BGP属性?如果只用BGP属性判定,IGP故障导致次优路径时,BGP无从感知。
- 有没有定期做BGP路由审计?我见过很多网络问题,是三个月前一次配置变更埋下的种子。现在不少平台都支持“配置回滚”或“BGP路由变更记录”,用起来比事后翻日志高效得多。
我在实际网络里的一个体会是:环路问题修起来往往不难,难的是次优路径——它不会让网络“挂掉”,每天的监控曲线却总在提醒你“有点不对劲”。这个时候不要急着改配置,先把BGP选路逻辑完整过一遍,把每条候选路径的每个属性都拉出来看,用协议的逻辑打败协议。
最后分享一个小习惯:每次做完BGP策略变更,我都习惯性跑一遍pre-change和post-change的BGP路由表对比,特别关注那些“意外被吸收”或“意外被弹出”的前缀。大多数时候,你会发现次优路径的种子在变更前就已经存在,只是变更后的某条路径变得可见了而已。排查这些问题的天平往往不在于高深的原理,而在于你有没有把每条命令的输出认真看完。