
BGP作为骨干网和IDC出口最常用的动态路由协议平时老老实实跑着的时候没人想起它一旦链路闪断、设备重启或者上游做了策略调整各种奇奇怪怪的问题就全冒出来了。很多时候业务中断并不是BGP本身down了而是主备切换瞬间路由收敛行为跟预期不一致导致流量黑洞或者来回路径不一致。这篇文章我就结合自己实际抓包排障的经历聊聊BGP主备倒换的那些坑以及不对称路由到底是怎么产生的、怎么从报文层面去定位。先说一个我印象特别深的故障。某机房核心出口做了双机冗余一台主一台备上行分别对接两个运营商。某天凌晨主设备说要升级内存我提前把业务切到备机结果切完之后业务全部超时。当时第一反应是路由没过去但登到备机上show bgp neighbor一看邻居状态都是Established路由表也有。后来在备机的上联口抓包才发现它一直在往外发BGP Update但回包全部丢了——对端运营商还在往主设备的物理地址发下一跳报文备机收到的BGP报文源MAC全是主机的。这就是典型的“路由策略切换了但转发面并没有真正切换干净”的场景。这类问题靠看路由表是看不出来的必须在报文转发的关键路径上抓包对比才能定位到是哪一跳出了问题。后面我会把抓包拆解的思路、主备倒换的完整过程以及不对称路由的产生机理和规避方式一条条说清楚。1. 内容整体设计与思路拆解1.1 从“冗余”到“冗余陷阱”主备倒换为什么这么容易出事网络架构里做BGP主备设计本质上是想消除单点故障——一台设备挂了另一台立刻接管流量。这个思路本身没问题问题出在“接管”这两个字上。很多人理解的主备切换就是把优先级调一下让备份路由器开始干活但实际生产环境里切换涉及的东西远比“多了一条路由”复杂。先用一个简单拓扑把场景说清楚。核心交换机下挂两台出口路由器Router A作为主Router B作为备两台路由器分别跟两个上游运营商建立EBGP邻居同时跟核心交换机建立IBGP邻居。正常状态下Router A通过EBGP学到运营商A的默认路由Router B通过EBGP学到运营商B的默认路由两台路由器再把这些路由通过IBGP互相宣告同时各自向核心交换机下发默认路由Router A的优先级更高。这个架构里主备切换不仅仅是一台设备的事情它牵涉到三个层面的联动控制层面BGP邻居状态要重新收敛路由要重新计算数据层面核心交换机的默认路由下一跳要从Router A切到Router B物理层面如果路由器跟上联运营商之间还有二层透传设备MAC表项也要跟着刷新这三层不是同步完成的时间差就是故障窗口。BGP协议本身收敛时间可以很快但底层转发表、ARP表、MAC表的刷新速度未必跟得上于是就会出现“路由已经切换了但流量还往老路径上送”的尴尬局面。我见过很多次所谓的BGP倒换故障最后查下来根本不是BGP协议有问题而是硬件转发表项切换太慢或者根本没触发切换。这也是为什么我强调要在数据面抓包验证而不是只看路由表和控制面的状态。控制面说“我切了”不代表数据面真的切了报文才是最终的真相。1.2 不对称路由的成因分类先分清“天生”和“后天”不对称路由这个词在BGP场景下特别容易让人迷糊因为它的成因太杂了。同样表现为来回路径不一致底层的原因可能完全不同。我习惯把不对称路由分两类一类是“天生不对称”一类是“后天不对称”。天生不对称指的是网络设计上就是往返路径不一样的。比如访问内部服务器的时候去程走运营商A的线路回程因为源地址策略路由走运营商B的线路。这种设计在很多做多出口负载均衡的IDC里是故意为之的本身不算故障。反方向是好的但如果中间有一台防火墙或者IPS做状态检测这种设计就会出大事防火墙上只能看到单向流量会话直接给你拦掉。后天不对称指的是正常情况下是对称的因为某些异常事件变成了不对称。主备倒换就是最常见的诱因。举个例子正常时候去程和回程都走Router A某次链路抖动Router A的EBGP邻居闪断又恢复但这段时间里Router B已经接替了去程流量。等Router A恢复以后去程因为本地优先级还是走Router A回程却可能因为Router B学到的是更优的路由而继续走Router B于是来回路径就岔开了。搞清楚这两类的区别对排障思路的影响非常大。天生不对称需要从设计层面调整后天不对称则要先找到触发事件再针对性做收敛优化或者路由策略修正。但不管哪一类定位思路都是一样的——抓包看路径看报文的进出接口对比正常基线和异常时刻的差异。2. 核心细节解析与实操要点2.1 BGP主备倒换的完整过程拆解BGP主备倒换不是一蹴而就的它是一连串事件按照特定顺序推进的过程。我用一次典型的手动主备切换来拆解这个过程因为手动切换是可控的每一步都能观测理解了手动切换自动故障切换就是一个加速版。整个切换流程大致是这么走的第一步调整路由优先级。把Router B从备份状态提升为主状态通常通过修改本地优先级Local Preference或者MED值来实现。如果是用路由策略控制则重新下发新的route-map让Router B学到的路由优先级高于Router A。这一步做完控制面的路由选择开始偏向Router B。第二步BGP路由重新计算。由于路由优先级变了Router B上原本处于备选状态的路径变成最优路径它需要把这条新路径通告给自己的IBGP邻居也就是核心交换机。核心交换机收到Update报文后替换原有的最优路径。第三步核心交换机更新转发表。这是最关键的一步。控制面收到了新的路由信息但硬件转发表是否立刻更新取决于设备的实现机制。大多数情况下会有一个短暂的收敛窗口这个窗口内可能出现丢包。第四步物理链路层面完成切换。Router B开始承担流量转发后它跟上游运营商之间的链路开始有实际的业务流量通过如果上游设备此前已经把流量送到Router A还需要等待MAC地址表老化或者由 gratuitous ARP 来刷新。这个过程里最容易出问题的就是第三步和第四步之间的空隙以及第一步之后第二步之前的窗口。前者是本地转发表切换慢后者是BGP收敛本身的延迟。在实际操作里手动切换我还遇到过更隐蔽的问题。Router A和Router B跟核心交换机之间的互联如果是以太网链路切换后核心交换机的ARP表项可能还指着Router A的接口MAC。Router B发出的报文能到达核心交换机但核心交换机回包还是发给Router A于是Router A明明已经不再承担转发任务了却还在不断收到回程流量这些流量又因为没有对应的转发条目而被丢弃。这种故障用一句话概括就是路由层面切了但二层转发层面没切干净。2.2 主备倒换的核心参数配置与选型逻辑不同厂商的设备上BGP主备倒换的配置方式有差异但核心参数的概念是通用的。我挑几个最关键的说一下这些参数决定了倒换的速度和可靠性。首先是最常用的本地优先级Local Preference。这个值只在AS内部传递默认值是100越大越优。主备场景下通常把主设备的本地优先级调高比如主设备设为200备设备保持100。这样即使两条路径都学到了流量也一定优选主设备。这里常见的坑是local-preference只影响本AS内的选路不会传给EBGP邻居。如果上游有两个运营商你想让运营商A的流量过来走主设备光设local-preference是不够的因为运营商的选路发生在他们的AS内部。第二个是MED值这个值会传递给对端AS用于影响对端进入本AS的选路。主备倒换时如果出现入向流量不切换的情况多半要调整发给上游的MED值。但注意MED默认只在相邻AS之间传递多跳EBGP环境下可能被重置这又是一个隐藏坑。第三个是AS Path通过附加AS号来降低某条路径的优先级。这种方式操作起来直观但会让路由表变得难看也增加了排障时读路由的难度我一般不太推荐在核心链路上用AS Path做主备控制。然后是BGP定时器。Keepalive默认60秒Hold time默认180秒这两个值决定了BGP邻居对链路故障的感知速度。生产环境里很多故障之所以恢复慢就是因为链路上加了传输设备物理层断了BGP不一定立刻感知要等Hold time超时才重新收敛。把Keepalive调到3秒Hold time调到9秒即3倍关系是常见的优化手段但这属于刀尖舔血的操作。定时器调的太短网络轻微拥塞就可能误判邻居故障引发频繁倒换。我见过某机房为了追求快速收敛把Hold time设成6秒结果一遇上广播风暴两台路由器疯狂互相判死业务直接瘫痪。所以调定时器之前先想清楚你的网络抖动容忍度是多少。最后还有一个经常被忽略的参数GTSM通用TTL安全机制它通过限制BGP报文的TTL值来防止伪造BGP报文的攻击。主备倒换场景下如果两台设备的互联链路经过了多跳TTL限制会导致BGP邻居起不来这属于配置层面很容易踩的坑。2.3 抓包定位的诊断架构设计遇到BGP主备倒换类故障很多人的第一反应是登录设备看日志。日志当然要看但日志只能告诉你控制面发生了什么数据面是否真的按预期转发必须靠抓包来验证。抓包诊断的第一步是选好抓包点。原则上讲抓包点应该放在所有关键转发路径上但现实是IDC的网络拓扑往往比较复杂不可能每个接口都抓。我一般按优先级从高到低选三个位置第一个位置是核心交换机的上行接口连接Router A和Router B的接口。这个位置能看到核心交换机往哪台路由器发送流量以及从哪台路由器接收到流量是判断主备是否真正切换的最直接证据。第二个位置是两台出口路由器的上联接口。这里能看到BGP报文和业务报文的进出情况。特别是BGP报文如果在主设备的上联接口上还能抓到BGP报文说明邻居关系还在但业务流量已经不再从这里经过了需要进一步确认原因。第三个位置是核心交换机下联到业务侧的接口。如果故障表现为部分业务通、部分业务不通这个位置的抓包能帮你缩小范围判断是路由问题还是二层问题。抓包工具方面命令行环境下tcpdump是首选简单可靠几乎任何Linux设备都能用。关键要掌握几个实用选项-i指接口-s 0抓全包避免截断导致分析困难-w写文件方便后续分析。带BGP环境的网络里还建议加上 -s 96 这种精确长度选项让单个报文只保留足够分析头部的长度降低磁盘占用。在Windows环境或者带图形界面的抓包终端上Wireshark更直观。BGP协议Wireshark支持得非常好能直接解析出NLRI里的前缀、AS Path、Local Pref等信息比人肉看十六进制高效太多。但要注意Wireshark抓包本身是带性能开销的在核心设备上长时间全量抓包可能引发CPU升高影响转发性能。所以生产环境里我通常是短时间定向抓包抓到关键报文就停然后离线分析。3. 实操过程与核心环节实现3.1 模拟主备倒换的典型环境搭建排障经验的积累离不开复现环境。我自己习惯在eNSP或者GNS3里搭一套BGP主备倒换的实验环境跑通以后再对照生产环境的抓包结果来分析。虚拟环境做不到100%还原真实硬件的行为差异但协议交互流程是一模一样的足够验证大部分逻辑问题。实验拓扑大概这样三台路由器R1、R2、R3R1模拟运营商AR2模拟运营商BR3作为核心交换机。两台出口路由器R4和R5分别连接R1和R2同时通过交换机连接R3R4和R5之间建立IBGP邻居。网络规划上R1和R2各宣告一条网段R4和R5向R3宣告默认路由R4的优先级高于R5。配置的时候有几个地方要特别注意。R4和R5之间的IBGP会话要设置loopback地址作为更新源保证物理链路断了会话还能维持这是很多BGP实验环境起不来的常见原因。R3上则要配置两条默认路由分别指向R4和R5管理距离或者优先级让R4的路径更优。在这个环境里模拟主备倒换最常用的手段是直接shutdown R4的上联接口强制流量切换到R5。这种方式最接近真实的链路故障也最方便观察整个收敛过程。如果要模拟设备重启可以在R4上执行reload观察启动后的重新收敛。相比之下route-map策略切换因为不涉及物理链路变化表现会更平滑但实际生产故障很少是这种温和的切换。3.2 抓包数据的关键特征与逐包解读在实验环境里跑一次主备倒换然后在R3连接R4的接口上抓包会看到非常清晰的几个阶段。第一阶段是BGP Keepalive报文的周期性出现。正常状态下每隔几秒就有一次这是邻居关系健康的标志。第二阶段是链路故障瞬间的报文异常R4的接口shutdown后Keepalive中断R3和R4之间的邻居关系开始进入超时倒计时。第三阶段是路由撤销和重计算Hold time超时后R4向R3发送BGP Notification报文宣告会话终止R3清除从R4学到的路由。第四阶段是路径切换R3的路由表重新计算把默认路由的下一跳切到R5同时开始向R5发送数据流量。逐包解读的时候有几个最容易忽略的信号BGP Open报文里的Hold Time字段它决定了后续的故障感知速度如果两台设备配置的Hold Time不一致会以较小值为准Update报文里的NLRI字段主备倒换后新的Update报文的AS Path长度往往更长或更短这个变化直接反映了路径优先级的调整Notification报文的Error Code和Subcode比如Cease错误码6代表会话被人为关闭如果排障时看到大量的Cease多半是有人改了配置而不是链路故障这里还要提到一种特别迷惑性的抓包现象。主设备已经不再承担转发任务了但它的上联接口还能抓到流量。原因可能是上游路由器的转发项还没老化仍然把流量送到主设备也可能是主设备的接口处于二层透传模式流量只是穿过去并非目的地。这时候光看图不看接口信息很容易误判。我自己的经验是抓包后第一件事不是看BGP报文而是先统计一下接口上的流量构成。用tcpdump抓个一分钟的包大概统计一下BGP报文、ARP报文、ICMP报文、业务TCP报文的比例再跟正常基线做对比。这个动作看似简单但能非常快地定位问题大致方向比钻进BGP报文里逐字节分析高效得多。3.3 典型案例复盘双出口主备切换后的流量黑洞用一个真实案例来把前面的理论串起来。这个案例是我去年处理的典型的双出口主备架构主设备Router A通过运营商M上联备设备Router B通过运营商N上联核心交换机同时连接Router A和Router B。某天晚上Router A的CPU突然飙高远程登录已经非常卡顿我们决定做一次手动主备切换把流量切到Router B上。切换动作很快完成了Router B的BGP邻居全部Established路由表正常看起来一切顺利。但业务监控立刻报警海外客户的访问量断崖式下跌国内客户倒是没什么影响。我第一时间在核心交换机的上行口抓包发现核心交换机已经把去往出口的流量全部从Router A的接口切到了Router B的接口这部分是正常的。但再看Router B的上联接口抓包发现报文只出不进——Router B持续往外发送TCP SYN报文和BGP Keepalive报文但对方的回包全部没有出现。继续在上联口的入方向抓包发现了一个非常重要的现象Router A的接口仍然不断收到来自运营商M的回包但这些报文的源MAC已经指向了运营商M的出口网关目的MAC还是Router A的接口MAC。也就是说运营商M的出口设备根本不知道主备已经切换它还在把回程流量往Router A的物理地址上送。Router A收到这些回程报文以后因为自己的路由优先级已经降级而且默认路由的下一条已经指向了Router B所以直接丢弃或转发给了核心交换机但核心交换机认为回程流向已经切换到Router B了对来自Router A的报文处理策略又跟预期不一致最终结果就是回程流量黑洞。这个案例最典型的启示是主备切换不只是本地设备的事情对端设备也需要感知到切换的发生。本地可以快速完成路由计算和转发表更新但上游设备什么时候把流量切过来取决于它的故障感知能力和收敛速度。如果上游设备没有及时检测到路径变化流量黑洞就会持续。解法有几个层面一是让Router A在切换时主动向上游发送BGP路由撤销明确告诉运营商M这条路径已经不可用二是配合BFD让链路状态变化很快传递到上游三是如果条件允许通过向运营商申请BGP会话的附加路径Add-Path能力让两台路由器同时向上游通告路由由上游自行选路从机制上消除切换延迟。4. 常见问题与排查技巧实录4.1 BGP主备倒换中的典型故障问题速查踩的坑多了慢慢就形成了一张问题速查表。遇到主备倒换问题的时候我一般先对照这张表做初步判断能省去大量盲目的排查时间。现象一切换后全部流量不通。优先检查核心交换机的默认路由下一跳是否已经切换以及Router B的上联链路是否真的能通。用ping测一下Router B到运营商网关的连通性再检查Router B是否学到了完整的路由表。有一种情况是Router B的EBGP会话虽然建立了但收到的路由条目被入口策略过滤掉了导致路由表不完整。现象二部分流量通部分流量不通。这种大概率是不对称路由加状态检测设备导致的。检查去程路径是否经过防火墙回程路径是否绕过了防火墙。如果在流量路径里有防火墙必须确认防火墙上的会话表是否能看到完整的双向流量。从设计角度说主备切换后所有流量必须保证往返路径经过同一台防火墙否则会话必断。现象三切换后延迟急剧增大但丢包并不多。这种通常不是BGP收敛问题而是切换后的路径绕远了。比如Router A本来直连运营商MRouter B的上游运营商N跟目标网络的互联带宽不够或者出口的RTT天然就高。这种情况需要先确认切换后的真实路径再决定是否要调整路由策略。现象四反复倒换抖动不停。这是最烦人的一个问题。排除硬件故障后最常见的原因是BGP定时器设置不合理。Keepalive时间设得太短链路稍有一点拥塞或者队列延迟抖动就触发Hold time超时邻居关系闪断恢复后另一台设备又因为同样原因闪断两台设备来回抢主。这种场景下先检查两端设备的BGP计时器配置再排查链路质量不要急着改协议参数。现象五切换成功但路由表中出现了不该有的路径。比如Router A和Router B之间通过IBGP交互路由时可能因为水平分割规则以外的配置问题导致路由环路。查看BGP路由表里的下一跳属性确认没有指向自己的下一跳。4.2 从抓包视角的独家排障技巧与心得最后分享几个我自己总结的独家排障技巧这些很难从官方文档里学到全是实战里熬出来的经验。第一个技巧是抓包前先确认抓包点的端口镜像方向。很多交换机做端口镜像时默认只镜像入方向或者出方向如果没选对方向最容易出现的假象是“出方向全是报文入方向一个包都没有”然后误判为链路单向不通。我习惯在做镜像配置时同时开入方向和出方向两个会话分别存文件分析时对照看。第二个技巧是善用BGP的tcpdump过滤表达式。抓BGP报文不用把整个链路的流量全抓下来一条精准的过滤表达式能省下大量的时间和磁盘空间。比如抓跟某个邻居的BGP报文可以写成tcpdump -i eth0 -s 96 -w bgp_capture.pcap tcp port 179 and host 192.0.2.1如果确认是IPv6环境记得加上 ip6 关键字。还有一种情况是BGP跑在非标准端口上需要针对性改动端口号。第三个技巧是Wireshark里用Follow TCP Stream功能分析BGP会话。BGP报文虽然承载在TCP之上但它的状态机变化非常复杂用Follow TCP Stream可以快速看到一次会话从Open到Update再到Notification的全过程。特别是看到BGP Notification报文里的错误码可以立刻定位到问题的具体类型。比如错误码2代表Open消息错误通常是参数协商不一致错误码3代表Update消息错误通常是路由属性有问题。Wireshark对BGP协议的解析深度足够不需要什么高端功能基础的过滤和分析就够用了。第四个技巧是抓包时间基准。分析抓包文件时要同时打开绝对时间和相对时间两种显示模式。绝对时间用于跟设备日志做时间轴对齐确认事件顺序相对时间用于精确计算各阶段耗时比如从链路中断到路由切换完成一共花了多少毫秒。这种时间分析对优化收敛速度特别有用可以明确知道瓶颈出在BGP检测阶段、路由计算阶段还是转发表下发阶段。第五个技巧是别忽略ARP和NDP报文。BGP主备倒换场景下很多问题其实出在二层地址解析上。切换后核心交换机要刷新ARP表如果ARP学习失败或者学到的是旧的MAC地址流量就会一直送给错误的设备。我在任何一次主备倒换排障里都会顺手看一下抓包里有没有异常的ARP请求风暴或者ARP欺骗报文。4.3 从排障到预防主备倒换的运维改进建议排障排到最后总归要回到一个问题上下次怎么避免同样的事情发生。基于几次重大的故障复盘我总结了一套主备倒换的运维改进清单分享出来供参考。第一建立主备倒换的标准化操作流程。切换不是拍脑袋决定的事从切换前检查确认备机状态、确认上游链路冗余、确认业务低谷期、切换动作执行按步骤操作、每步确认状态、切换后验证业务探测、路径确认、持续观察一段时间每一步都要有明确的执行标准和责任人。我见过太多次切换失败是因为切换前没检查备机的CPU状态上去以后备机直接被打满。第二引入持续的路由质量监控。只看BGP邻居状态是远远不够的要监控路由表里的关键前缀是否正常路由路径的AS Path是否发生了变化下一跳是否符合预期。现在主流的网络监控平台都已经支持通过BGP监控协议BMP采集路由状态可以做到秒级感知路由变化。如果条件不允许部署BMP至少要在核心设备上做SNMP告警监控BGP状态变化和路由表条目数量波动。第三定期做主备倒换演练。这个听起来是废话但真正坚持做的团队少之又少。演练不是随便找个时间切一下就行要有预案、有观测手段、有回退方案。我建议每季度至少做一次完整的主备切换演练同时把切换耗时记录在案对比每次切换的时间差异如果某次切换耗时明显变长说明设备状态或者转发性能出现了劣化需要及时排查。第四维护一份完整的报文基线库。在一个稳定运行的网络里定期抓包保存作为后续排障的对照基准。这个基线库不一定要很大每个关键接口存一份代表正常状态的抓包文件就行。当故障发生时拿故障时的抓包跟基线对比往往一眼就能看出差异在哪里。这个方法比拿着一张路由表到现场边看边猜靠谱得多。还有一点值得特别强调BGP主备倒换不是孤立的网络事件它跟上层应用的感受有直接关系。TCP长连接对网络中断的容忍度很低哪怕BGP只断几秒钟一批TCP连接就会断开重连业务侧就能感知到。所以在做BGP收敛优化的时候不要只盯着路由协议的指标也要从应用角度评估可接受的断流时间再反推网络侧需要做到多快的收敛。如果业务要求亚秒级切换那光靠BGP收敛是不够的可能需要引入BFD联动、设备间会话保持等更高级的手段。说到底网络排障的尽头不是把故障修好而是通过每次故障沉淀出体系化的防御能力。BGP主备倒换本身是件好事它保证了网络的高可用性但只有当你真正理解了倒换过程中每一个报文的去向、每一次路由计算的因果、每一个转发层面的时延你才能在倒换发生时从容应对而不是被一个接一个的异常报文打得措手不及。这也是为什么我一直强调抓包——协议栈可以调试配置可以核对唯独真实转发的报文不会说谎它记录的才是网络最真实的状态。