BGP,全称是Border Gateway Protocol,边界网关协议。我最早接触它的时候,是被那句“BGP是互联网的粘合剂”给唬住了,觉得这是只有运营商和顶级网络专家才需要碰的东西。直到后来自己动手搭实验环境、处理真实网络故障,才慢慢意识到,BGP其实没那么玄乎,它本质上就是一套“如何从一堆可达路径里挑一条最好的路”的规则体系。今天这篇东西,我不打算从头讲到尾,把RFC翻一遍,也不打算把默认优先级表格丢给你就完事。我想换个角度,从“选路到底是怎么发生的”这个核心问题切入,把属性之间的博弈、优先级背后的逻辑、以及实际维护中那些文档上写不清的坑,都揉碎了讲清楚。不管你是刚接触网络的新人,还是在职场上被BGP路由折腾过的工程师,这篇文章应该都能给你一些不一样的启发。1. BGP选路不是“选快”,而是“选优”:先搞懂它的决策本质很多人容易陷入一个误区,觉得BGP选路既然是“选路”,那肯定是哪条路延迟低、带宽大就走哪条。这种想法放到IGP(比如OSPF、IS-IS)里,大体成立,因为IGP看的确实是带宽、时延、开销这些物理或者逻辑上的“成本”。但BGP根本不管这套,它跑在自治系统之间,面对的是成千上万个AS,它关心的核心问题只有一个:这条路径能不能到达目的前缀,以及这条路是不是最符合策略的那一条。1.1 为什么BGP倾向于“不换路”BGP选路的一个底层逻辑,是抑制震荡。想象一下,全球互联网有多少条路由在持续更新,如果每条路由都因为带宽抖动频繁切换,那整个世界都会跟着抖起来。所以BGP的设计哲学是:只要还有一条可达的旧路由,就不要轻易切换到新路由,哪怕新的看起来“更好”。这正是为什么BGP选路规则里,第一条可用的最优候选路由会一直保持,直到它彻底失效,而不是像IGP那样周期性重新计算。这一点很多人学BGP时容易忽略。我们总是盯着那十几条选路规则看,却忘了这套规则是搭在“稳定性优先”的地基上的。明白了这个底层逻辑,你才能理解后面所有属性的意义——它们不是用来帮你找“最快路径”的,而是用来帮你找“最符合策略”的路径的。1.2 决策过程是单线程的“淘汰赛”实际选路不是把所有路径拿过来做综合评分,然后取总分第一。BGP的决策过程是一套顺序执行的淘汰赛:从第一条规则开始,拿所有候选路径比一轮,如果有且只有一条胜出,那直接选它,后面所有规则统统不执行;如果还有多条打平,再进入下一条规则,直到最后只剩下一条。这个机制很重要,因为它意味着第一条属性的“情绪稳定”和“取向偏好”,会直接影响后面所有规则的“出场机会”。举个最简单的例子:如果某条路由的Weight(权重)特别高,那么在权重比较这一关它就直接胜出了,后面什么AS路径长度、LOCAL_PREF,压根没有机会参与比较。所以我们在维护路由时,经常说“想要控制选路,就要尽量在靠前的属性上做文章,这样效率最高,也最好排查”。1.3 选路规则里的“先手优势”我把完整的决策顺序放在这里,后面会逐条拆解。你可以把它当作一张速查卡:Weight(权重)最高者优先(Cisco私有属性,本地有效)LOCAL_PREF(本地优先级)最高者优先本地始发路由(network / aggregate / redistribute)优先于从对等体学习到的路由AS_PATH长度最短者优先ORIGIN类型:IGP < EGP < INCOMPLETEMED(多出口鉴别器)最小者优先外部路由(EBGP)优先于内部路由(IBGP)经过的IGP邻居的下一跳度量最小者优先会话建立时间较早者优先(老路由更稳)Router-ID最小者优先对等体地址最小者优先这套顺序,十个人有十一个能背错,但实际工程里最重要的是前六条,后面几条大多是拓扑完全相同、没有其他区分手段时的“兜底方案”。你只要把前六条的逻辑吃透,就已经能解决90%以上的选路问题了。2. 从Weight到AS_PATH:手把手拆解“先到先得”的四大关键属性这一节我打算不按表格顺序平铺,而是按实战中“由近到远”的视角来拆:先从本设备自己能控制的属性讲起,再到从邻居学到的属性,这样你会有一种“层层递进、每一步都能操作”的感觉。2.1 Weight:只属于本设备的“独裁者”Weight是Cisco实现里的私有属性,它在本地路由器上生效,不会传递给任何邻居。你可以把它理解成“这台路由器自己内心的一票否决权”:数值越大越优,默认值是0,本地宣告的直连路由权重通常是32768。这玩意儿的最大特点就是范围极小、控制力极强。在实操里,我经常用Weight来做一些“只影响本机出方向”的临时调整。比如某天一条出口链路抖动,运营商那边的BGP路由变了,但我想让本设备暂时多走另一条备份链路,又不想动上游策略,那直接在入方向的路由策略里set weight 55555,问题就解决了。因为Weight只对本地有效,其他邻居、其他路由器完全感知不到,所以特别适合做故障期的“快速止血”,不会造成全网路由震荡。但也有个坑:Weight无法跨设备传递,也无从在show output里直观比较。如果你在多台设备上都设了Weight,一定要保证策略一致,否则很容易出现“这台设备往左走,那台设备往右走”的分裂路径现象。在排查这种问题时,我会第一句问的就是:“你们在哪些设备的入方向set了weight?”2.2 LOCAL_PREF:自治系统内部的“共识决议”如果说Weight是“个人的执念”,那LOCAL_PREF就是“一个自治系统内部的共识”。它是IBGP邻居之间传递的属性,默认值为100,也是“越大越优”。它的核心价值在于:当你的AS有多个出口点(连了多个运营商/多个上游)时,你想要全AS的出方向流量都优先走某一个出口,就可以通过LOCAL_PREF来实现。我讲一个实际案例,很多做企业网络的同事应该都有共鸣:双线接入,一条是电信,一条是联通,我们希望在正常情况下,所有出方向流量都走电信,只有电信挂了才走联通。这个需求用LOCAL_PREF就非常优雅:在电信侧设备上对从电信收到的路由,设置LOCAL_PREF为150;联通侧保持默认100。因为LOCAL_PREF会在IBGP全网传递,所以AS内所有路由器都会计算出“去往任意前缀的最优路径是电信那条”,就把流量优先引过去了。当电信链路断了,该前缀从BGP表中消失,联通那条自然成为备选,流量自动切换。这里有个细节值得注意:LOCAL_PREF只在AS内部传递,不会带着出AS。也就是说,你给上游运营商下发的路由加LOCAL_PREF,对上游没有任何影响——它的作用范围是“接收方自己所在的AS”。2.3 AS_PATH长度:跨AS决策的“硬通货”这条规则可能是大家最先记住的:AS路径越短越优。为什么会这样设计?因为AS_PATH本身记录了这条路由穿越的自治系统集合,路径越短,意味着对端AS越“近”,跨域跳数越少,通常也意味着更稳定、更少的中转。对运营商网络来说,AS_PATH长度往往被当作一种“路由成本”的近似值。但这个规则在实践中经常被“恶意”利用。最典型的就是AS_PATH Prepending:人为地在路由上重复添加自己的AS号,把路径“变长”,从而让下游邻居“看不起”这条路由,于是他们就更倾向走另一条更短的路径。这几乎是所有双线/多线接入场景里,控制入方向流量的标准姿势。我做过多线接入优化时,就经常给备份链路的出方向策略里prepend两三次自己的AS号,让对端运营商感觉“这条路绕了远路”,从而把入方向流量尽量压制在主链路上。实测下来,一般在备份链路上prepend 2到3次比较合适——太少了不管用,太多了万一主链路全挂,备份链路撑不住全量流量,就悲剧了。2.4 AS_PATH在选路中的另一个身份:防环和策略工具除了选路,AS_PATH还有一个专长:防环。BGP明确规定,如果一条路由的AS_PATH里包含了自己的AS号,那它就收到了一条“在AS内绕了一圈又回来”的路由,这种情况必须直接丢弃。这就是BGP最重要的防环机制,它根本不需要额外配置,天然自洽。在实际维护中,AS_PATH也经常被用来做“路径过滤”。比如我们跟某些不靠谱的下游有互联,为了防止他们一不小心成了我们所有流量的中转,我们可以用AS_PATH ACL精确匹配、只允许特定AS_PATH通过。这种打法比用前缀过滤器更精细,也更难被绕过。我习惯在做安全排障的时候,同时挂上前缀过滤和AS_PATH过滤两道关卡,宁可过度防护,也不给路由泄露留机会。3. 谁是“最轻”的那一个:ORIGIN、MED与下一跳的隐秘权重很多人学到前四条就以为差不多了,但真实故障往往就藏在后面几条“不太起眼”的属性里。ORIGIN、MED、IGP下一跳度量,这三兄弟在多数情况下打前四条打平了才登场,但一旦登场,往往决定了流量方向的天平往哪边倾斜。3.1 ORIGIN:路由出生地的“血统”标记ORIGIN属性用来表示这条路由是怎么进入到BGP世界的,有三种取值:IGP(通过network宣告,最可信,值2)、EGP(外部网关协议,已基本绝迹)、INCOMPLETE(通过重分布等途径进入,可信度最低,值1)。它的优先级是IGP > EGP > INCOMPLETE,也就是说,它是“越小越优”(数值上2优于1,但因为EGP实际几乎不出现,所以核心就是IGP优于INCOMPLETE)。实战中你直接配置ORIGIN的机会不多,但它经常在“暴力重分布”的场合里冒出来搞事。比如有人把OSPF整个重分布进BGP,那产生的路由ORIGIN就是INCOMPLETE,血统最低。如果同一个前缀同时存在network宣告和重分布两种来源,即使后者的AS_PATH更短,BGP也会因为ORIGIN优先级更高而选择那个“血统更纯”的network路由。这很容易让人困惑:路径短为啥不走?原因就在这儿——血统很重要,出生决定命运。3.2 MED:跨AS的“价格标签”与它的边界限制MED全称Multi-Exit Discriminator,多出口鉴别器,它是唯一一个正经用来“跨AS”传递并影响对端AS选路的属性,但它有个硬约束:MED只能传递给相邻的AS,不会继续往更远的地方传。机制上前置条件是默认值0,越小越优。它的应用场景很典型:两个AS之间有两条物理链路互联,AS1希望AS2去往某前缀时优先走其中一条链路。那AS1就可以在自己的两条出口上对播出的该前缀设置不同的MED值,比如主链路MED=50,备份链路MED=200,AS2收到后会自动优选MED更小的那一条。用大白话讲,就是给两条路贴了不同的“价格标签”,对端就会自动选“便宜”的那条。但MED有个比较坑的地方:它的比较是有限制的。BGP默认MED比较只发生在“源自同一个AS的两条路由”之间,也就是需要参数bgp always-compare-med来打破这个限制,否则不同AS来源的路由之间不做MED比较。我曾经在排障时看到两个上游给同一个前缀发了不同的MED,但路由器始终不走MED更小的那条,结果一查才发现,它们来自不同的AS,默认根本不会触发MED比较。这个参数官方文档写得零散,但实际运维里极其关键。3.3 下一跳IGP度量的“战术价值”:最终路径优化到了这个阶段,BGP已经选出了“外部视角最优”的路由,但如果它要真正把流量发出去,还需要知道下一跳在自己的IGP路由表里有多“好”。所以第8条规则就登场了:比较到达BGP下一跳地址的IGP度量值,越小越优。这条规则的存在,是BGP和底层IGP之间恰到好处的一种“协同”。因为BGP自己不看物理拓扑细节,它依赖IGP来告诉它“怎么走最划算”。如果两条BGP路由下一跳不同,但其他所有属性全打平,那IGP度量小的一方就会胜出。尤其是在一个复杂的IBGP体系里,这个规则经常在“多台Route Reflector指向不同物理出口”的场景下发挥真实作用。经验上,我通常不会主动去调IGP度量来影响BGP选路——太绕了,而且很容易把IGP内部的链路开销搞得异常。但我会在排查选路异常时,先顺手看一下这两条路由的下一跳在IGP里的度量值。有两次我排了半天都没找到问题,最后就是这一关“兜底”才把真正的差值揪出来。4. 我们在真实网络里是怎么“摆弄”这些属性的:四类调控手法前两节我们拆了属性,这节我想重点落地:既然知道了BGP按顺序比属性,那实际维护中我们是怎么用工具达到“我要它走这条,它就得走这条”的?这四类手法是我在工作中最常用的,建议你收藏。4.1 入方向工具:控制“别人怎么看待你的路由”所谓入方向,是指“其他AS往你的AS发送流量时,会选择哪条路”。由于路由是你宣告出去的,对你自己的BGP路由做属性修改,只影响别人对你AS内的路径偏好。常见操作:AS_PATH Prepending:把备份链路宣告的路由人为拉长,让上游觉得这条路绕远,从而减少入流量MED设置:在给不同上游的出口上设置不同的MED,引导对端优先走指定链路前缀精确宣告:用更精确的前缀(比如/24而不是/16)在主链路宣告,让更细粒度的最优路由自然出现这套手法里的AS_PATH Prepending,通常会配合ip as-path access-list或者route-policy一起用。比如我最近维护的一个双线出口,就做了这样的配置(示意):route-policy PREPEND permit node 10 if-match ip-prefix important-prefix apply as-path prepend 65001 65001 65001 apply med 500 end-policy # 上面这个策略仅在备份链路方向生效, # 主链路方向不做任何修改,靠自然属性胜出。这样设完之后,我用show ip bgp 8.8.8.0/24一查,非常直观:主链路AS_PATH长度短,备份链路AS_PATH长度被拉长了,入方向流量自然集中到主链路。要测试效果的话,可以在维护窗口手动把主链路的物理接口shutdown,观察备份链路是否能承接流量,再恢复。4.2 出方向工具:控制“你的流量怎么走出去”出方向,是指“你的AS访问外部目标时,优先走哪条出口”。这完全由你本地及AS内部的策略决定。核心工具就是Weight和LOCAL_PREF。只影响某一台本地设备:使用Weight影响整个AS:使用LOCAL_PREF,并通过IBGP全量传递我早年在维护双出口时,刚开始不懂LOCAL_PREF的“网内共振”特性,只在出口路由器A上设置了路由策略,结果别的主机访问外网还是走的旧路径。后来才明白,LOCAL_PREF必须靠IBGP在整个AS内同步,才能让全AS的路由器达成共识。于是我把策略改到出口设备的入方向,并确认IBGP邻居关系正常建立,再一查show ip bgp,所有路由器都认了这条LOCAL_PREF=200的路由,出方向流量才顺利切过去。4.3 出/入方向的组合拳:多技术出口的最优路径矩阵当你的AS有多个出口、多条链路、多个运营商时,单独靠任何一个属性都不完美。我们通常会用“组合拳”来构建一张最优路径矩阵。假设企业在两个城市各有一个机房,分别连接两个不同的运营商,且通过专线/Overlay组了IBGP全网。我们需要实现:南方用户走南方出口、北方用户走北方出口、附近机房互备。这种场景我会把LOCAL_PREF和AS_PATH Prepend搭配起来玩:南出口设备上对南方运营商的线路宣告全国前缀,AS_PATH不修饰,LOCAL_PREF默认或稍高北出口设备上对同一前缀宣告时AS_PATH prepend,LOCAL_PREF低一些这样外部流量从南方进来找不到更优路径,逆向往北走;内部流量出境则优先走本地区域,两边形成流量平衡这种矩阵设计,不是一次配置完就一劳永逸的,而是要持续观察流量曲线、对端路由表反馈来微调参数。做网络优化的人,本质上就是在这些属性参数里“弹钢琴”。4.4 策略下发前的“小动作”:过滤与抑制,先堵后梳在实际操作中,我很少只单纯改属性,而是一上来先做“过滤+抑制”的预处理:入方向:挂前缀列表、AS路径过滤器,把不想要的、不该收的路由直接挡在门外出方向:只宣告我们真正持有的、合法的前缀,防止路由泄露或恶意路由广播针对震荡路由:使用bgp dampening抑制半衰期高的路由,防止“一会儿通一会儿断”影响全局为什么要先做这一步?因为属性调控是基于“已有路由”的,如果有大量垃圾路由混进来,那即使LOCAL_PREF调得再优,也只是在垃圾堆里挑“相对好的垃圾”,完全没意义。把不健康的路径先剔掉,剩下那些可比较的路径才有应用选路策略的价值。5. 那些年我们踩过的选路坑:真实排障案例与思维复盘讲完理论和方法,不聊几个真实踩坑案例,总觉得少了点灵魂。下面这三个案例都是我在维护不同类型的BGP网络时实际碰到的,问题都很典型,希望你能从中看到自己网络的影子。5.1 案例一:LOCAL_PREF“传不出AS”引发的双向流量失衡某次做跨城双线优化,我按老经验在主出口上对某段重要前缀设置了LOCAL_PREF=180,备份链路默认100。配置完成后,同城数据中心内部访问外网的情况正常,但我顺手检查了一下上游的入方向流量,发现几乎全是走备份链路进来的,与我预期的“主链路优先”完全相反。当时我第一反应是主链路宣告出了问题,查了附属的所有节点,发现宣告正常,MED默认0。后来才回过神来:LOCAL_PREF作为IBGP属性,它只在AS内部传播,我设置的180只对内部路由有效,对上游AS没有任何意义。上游AS判断“走哪条路进入我的AS”,取决于我宣告给它的AS_PATH和MED,而不是我本地LOCAL_PREF的数值。这个案例给我们的教训是:方向对应关系必须时刻记清——控制“出”靠Weight和LOCAL_PREF,控制“入”靠AS_PATH Prepending和MED。方向搞反,跑断腿都查不出问题。5.2 案例二:MED比较的“非对称陷阱”在双归接入时突然出现某金融客户做双归接入,两条链路分别接两个不同的运营商,上游各自宣告了相同的网段。我们原本预期去往某些地址时,因为运营商B的MED较小,流量会优先走B链路。但实测中发现流量几乎总走A链路,怎么都切不过去。排查链路层层递进:首先排除物理、接口、BGP会话问题;再用show ip bgp对比两条路由的完整属性,发现它们的AS_PATH长度、LOCAL_PREF都完全一致,只有MED不同;理论上应该走MED更小的B链路。问题来了:为什么没走?后来我才想起来,这个场景下两条路由是来自两个不同AS的。BGP默认规则是:只有同一AS来源的路由才做MED比较,不同AS来源直接跳过MED比较,进入后面“教条式”的规则比拼。也就是说,MED想跨不同AS比较,必须在设备上全局开启bgp always-compare-med。在这个真实切换案例里,这参数开不开,直接决定了流量是否按预期流动。5.3 案例三:AS_PATH短不一定绝对优先,ORIGIN血统一击绝杀某次做路由优化,我们想让一部分流量从更短AS_PATH的主链路走。按常规理解,AS_PATH最短一定会胜出。可是配置完成后,我们用工具追踪路由路径,流量却仍绕道备份链路,主链路上的AS_PATH虽然短,但就是没被选中。用show ip bgp prefix细看属性,发现主链路那条路由的ORIGIN是INCOMPLETE,备份链路那条是IGP。回头再对照决策规则的顺序,AS_PATH比较(规则4)排在ORIGIN之前,所以只要AS_PATH有长短差异,理应立刻生效。但这个案例中两条AS_PATH长度其实一样,它们打平后进入ORIGIN比较,于是血统更正的IGP反而胜出。后来我们用network命令显式宣告这个前缀,让ORIGIN变成IGP,再对照show ip bgp一看,选路立刻切到了主链路。这个案例说明:决定选路的永远是决策顺序里最先出现差异的那一条属性。不是哪个“显眼”就哪个说了算,而是“先比谁”才说了算。理清属性顺序,你才能预判结果。6. 属性跟踪与调试指南:日常维护里我用得最顺手的几条命令网上有很多BGP的show命令大全,但真正日常维护用得最频繁的其实就那几条。我在这里把它们串成一个完整的排障链路,让你遇到选路异常时能一条龙排查。6.1 show ip bgp:不是只盯着BGP table,还要学会“逐行理解”show ip bgp是基础,但我强烈建议你多看一眼Network Next Hop Metric LocPrf Weight Path这一行里的每个字段。尤其是当你的前缀有多种来源时,你会看到同一个Network下面挂着多行不同Next Hop的路径,每一行都对应一条“候选路径”。通过它的输出,我们能定位到“具体打平到了哪一步”:如果某行有>标记,说明它是当前最优路径;顺着它的属性回溯,就能知道它到底赢在哪一条规则上。如果某些行完全相同的属性一长串,那大概率后面几条“兜底规则”在起作用,这时也要警惕“该加参数区分路径了”。6.2 show ip bgp rib-failure:一个被严重低估的调试入口很多人在BGP选路不理想时,只盯BGP表,却忽略了show ip bgp rib-failure这个命令。它专门用来展示那些BGP认为是最优路径、但为什么没有装进路由表(RIB)的记录。出现RIB failure通常意味着路由冲突,比如去往同一前缀,有其他协议(如静态路由、OSPF)的路径在路由表里占据了优先级,BGP就算选出来也放不进去。这是一个特别容易让人抓狂的坑:你查BGP表,明明有一条最优路径,策略也都对,但流量就是不过去。结果一看RIB failure,才发现底层路由表被一条静态路由霸占了。所以每次选路排查,我都会先跑一遍show ip bgp rib-failure,五秒定位是否有“BGP赢了属性,却输了安装权”的诡异局面。6.3 show bgp neighbor和debug ip bgp updates:观测邻居的“心情状态”最后是邻居层面的排查。BGP选路的前提是邻居关系稳定。show bgp neighbors是基础,但我更常用它来看“发过来/收过去”的更新统计,确认当前更新的内容与预期一致。遇到选路突然变化,并伴随便更新,再考虑抓包或开启debug ip bgp updates。不过这类debug命令要小心用,生产环境开大范围debug会瞬间刷爆CPU,我通常只加peer-address参数限定单个邻居,调试完立即关闭。整个排障思路其实就是一层层剥洋葱:邻居会话 → 路由接收/发送 → BGP表的属性比较 → RIB安装 → 全局路由表转发。哪一层断了,就在哪一层深挖。不会一步到位,但每层都能找到对应的命令快速验证。7. 从“会配”到“会调”:关于选路优化的进阶经验到这儿,各位可能已经把核心属性和基本调试命令都消化完了。可如果你经常跟BGP打交道,一定会有种感觉:能配置是一回事,调得好不好是另一回事。最后我想分享几条进阶经验,它们不是标准教科书里会写的,但对实际网络“手感”的提升帮助很大。7.1 永远把“稳定性”放在“最优”之前BGP的基因是稳定性优先。所以我在做任何调优前,都会先问自己一个问题:这个改动会不会导致路由震荡?把一条路由从一个出口切到另一个出口,哪怕策略上完全可行,也要考虑对业务的影响面。最稳妥的做法是先在测试环境或维护窗口内做小范围验证,观察一段时间的选路稳定性和流量曲线,确认没有抖动了,再全量下发。生产网络里,稳定性就是最大的可用性。7.2 不要迷信“唯一正确答案”,属性参数本身就是可调参数我碰过不少同行在调LOCAL_PREF或MED时,会把某个数值当成“神谕”:比如LOCAL_PREF一定要200,MED一定要100。其实BGP选路中的属性数值只是相对大小,重要的是“比较关系”,而不是“绝对数值”。你能在合理范围内灵活调整,是为了适应不同的链路质量、成本和策略。比如主备链路的LOCAL_PREF差50还是差150,取决于你对主链路的“偏爱程度”以及备份链路的承载能力——给备份链路留出足够的“触发空间”,但也不至于主链路一有风吹草动就浪费了备份能力。7.3 用“路由起源验证”来守住最后一层底线现在大规模网络都在推RPKI(资源公钥基础设施)和BGP安全机制,很多老工程师会觉得这是运营商的事。但我建议企业网络也在Edge设备上启用“路由起源验证”,配合前缀过滤,这会大大降低误收恶意路由、路由劫持的风险。这也是BGP维护从“被动响应”走向“主动防御”的重要一步。技术上,初期可以先开启接收RPKI无效路由的警告模式,观察一段时间再决定是只接受有效路由,还是预警后由人工介入。回到开头那一点:BGP选路不是选“快”,而是选“优”,但这个“优”的标准,全部沉淀在那一条条有顺序的属性规则里,又有一层层本地策略和全局策略在中间博弈。希望你在读完这篇文章后,能重新审视自己网络里那些“想不通”的路径选择,顺着属性比较的顺序,找到那个真正主导一切的关键差异。当你有一天能够不看文档,就能凭show输出预判出流量该往哪走的时候,你会觉得,BGP这门手艺真的很有意思。
BGP,全称是Border Gateway Protocol,边界网关协议。我最早接触它的时候,是被那句“BGP是互联网的粘合剂”给唬住了,觉得这是只有运营商和顶级网络专家才需要碰的东西。直到后来自己动手搭实验环境、处理真实网络故障,才慢慢意识到,BGP其实没那么玄乎,它本质上就是一套“如何从一堆可达路径里挑一条最好的路”的规则体系。今天这篇东西,我不打算从头讲到尾,把RFC翻一遍,也不打算把默认优先级表格丢给你就完事。我想换个角度,从“选路到底是怎么发生的”这个核心问题切入,把属性之间的博弈、优先级背后的逻辑、以及实际维护中那些文档上写不清的坑,都揉碎了讲清楚。不管你是刚接触网络的新人,还是在职场上被BGP路由折腾过的工程师,这篇文章应该都能给你一些不一样的启发。1. BGP选路不是“选快”,而是“选优”:先搞懂它的决策本质很多人容易陷入一个误区,觉得BGP选路既然是“选路”,那肯定是哪条路延迟低、带宽大就走哪条。这种想法放到IGP(比如OSPF、IS-IS)里,大体成立,因为IGP看的确实是带宽、时延、开销这些物理或者逻辑上的“成本”。但BGP根本不管这套,它跑在自治系统之间,面对的是成千上万个AS,它关心的核心问题只有一个:这条路径能不能到达目的前缀,以及这条路是不是最符合策略的那一条。1.1 为什么BGP倾向于“不换路”BGP选路的一个底层逻辑,是抑制震荡。想象一下,全球互联网有多少条路由在持续更新,如果每条路由都因为带宽抖动频繁切换,那整个世界都会跟着抖起来。所以BGP的设计哲学是:只要还有一条可达的旧路由,就不要轻易切换到新路由,哪怕新的看起来“更好”。这正是为什么BGP选路规则里,第一条可用的最优候选路由会一直保持,直到它彻底失效,而不是像IGP那样周期性重新计算。这一点很多人学BGP时容易忽略。我们总是盯着那十几条选路规则看,却忘了这套规则是搭在“稳定性优先”的地基上的。明白了这个底层逻辑,你才能理解后面所有属性的意义——它们不是用来帮你找“最快路径”的,而是用来帮你找“最符合策略”的路径的。1.2 决策过程是单线程的“淘汰赛”实际选路不是把所有路径拿过来做综合评分,然后取总分第一。BGP的决策过程是一套顺序执行的淘汰赛:从第一条规则开始,拿所有候选路径比一轮,如果有且只有一条胜出,那直接选它,后面所有规则统统不执行;如果还有多条打平,再进入下一条规则,直到最后只剩下一条。这个机制很重要,因为它意味着第一条属性的“情绪稳定”和“取向偏好”,会直接影响后面所有规则的“出场机会”。举个最简单的例子:如果某条路由的Weight(权重)特别高,那么在权重比较这一关它就直接胜出了,后面什么AS路径长度、LOCAL_PREF,压根没有机会参与比较。所以我们在维护路由时,经常说“想要控制选路,就要尽量在靠前的属性上做文章,这样效率最高,也最好排查”。1.3 选路规则里的“先手优势”我把完整的决策顺序放在这里,后面会逐条拆解。你可以把它当作一张速查卡:Weight(权重)最高者优先(Cisco私有属性,本地有效)LOCAL_PREF(本地优先级)最高者优先本地始发路由(network / aggregate / redistribute)优先于从对等体学习到的路由AS_PATH长度最短者优先ORIGIN类型:IGP < EGP < INCOMPLETEMED(多出口鉴别器)最小者优先外部路由(EBGP)优先于内部路由(IBGP)经过的IGP邻居的下一跳度量最小者优先会话建立时间较早者优先(老路由更稳)Router-ID最小者优先对等体地址最小者优先这套顺序,十个人有十一个能背错,但实际工程里最重要的是前六条,后面几条大多是拓扑完全相同、没有其他区分手段时的“兜底方案”。你只要把前六条的逻辑吃透,就已经能解决90%以上的选路问题了。2. 从Weight到AS_PATH:手把手拆解“先到先得”的四大关键属性这一节我打算不按表格顺序平铺,而是按实战中“由近到远”的视角来拆:先从本设备自己能控制的属性讲起,再到从邻居学到的属性,这样你会有一种“层层递进、每一步都能操作”的感觉。2.1 Weight:只属于本设备的“独裁者”Weight是Cisco实现里的私有属性,它在本地路由器上生效,不会传递给任何邻居。你可以把它理解成“这台路由器自己内心的一票否决权”:数值越大越优,默认值是0,本地宣告的直连路由权重通常是32768。这玩意儿的最大特点就是范围极小、控制力极强。在实操里,我经常用Weight来做一些“只影响本机出方向”的临时调整。比如某天一条出口链路抖动,运营商那边的BGP路由变了,但我想让本设备暂时多走另一条备份链路,又不想动上游策略,那直接在入方向的路由策略里set weight 55555,问题就解决了。因为Weight只对本地有效,其他邻居、其他路由器完全感知不到,所以特别适合做故障期的“快速止血”,不会造成全网路由震荡。但也有个坑:Weight无法跨设备传递,也无从在show output里直观比较。如果你在多台设备上都设了Weight,一定要保证策略一致,否则很容易出现“这台设备往左走,那台设备往右走”的分裂路径现象。在排查这种问题时,我会第一句问的就是:“你们在哪些设备的入方向set了weight?”2.2 LOCAL_PREF:自治系统内部的“共识决议”如果说Weight是“个人的执念”,那LOCAL_PREF就是“一个自治系统内部的共识”。它是IBGP邻居之间传递的属性,默认值为100,也是“越大越优”。它的核心价值在于:当你的AS有多个出口点(连了多个运营商/多个上游)时,你想要全AS的出方向流量都优先走某一个出口,就可以通过LOCAL_PREF来实现。我讲一个实际案例,很多做企业网络的同事应该都有共鸣:双线接入,一条是电信,一条是联通,我们希望在正常情况下,所有出方向流量都走电信,只有电信挂了才走联通。这个需求用LOCAL_PREF就非常优雅:在电信侧设备上对从电信收到的路由,设置LOCAL_PREF为150;联通侧保持默认100。因为LOCAL_PREF会在IBGP全网传递,所以AS内所有路由器都会计算出“去往任意前缀的最优路径是电信那条”,就把流量优先引过去了。当电信链路断了,该前缀从BGP表中消失,联通那条自然成为备选,流量自动切换。这里有个细节值得注意:LOCAL_PREF只在AS内部传递,不会带着出AS。也就是说,你给上游运营商下发的路由加LOCAL_PREF,对上游没有任何影响——它的作用范围是“接收方自己所在的AS”。2.3 AS_PATH长度:跨AS决策的“硬通货”这条规则可能是大家最先记住的:AS路径越短越优。为什么会这样设计?因为AS_PATH本身记录了这条路由穿越的自治系统集合,路径越短,意味着对端AS越“近”,跨域跳数越少,通常也意味着更稳定、更少的中转。对运营商网络来说,AS_PATH长度往往被当作一种“路由成本”的近似值。但这个规则在实践中经常被“恶意”利用。最典型的就是AS_PATH Prepending:人为地在路由上重复添加自己的AS号,把路径“变长”,从而让下游邻居“看不起”这条路由,于是他们就更倾向走另一条更短的路径。这几乎是所有双线/多线接入场景里,控制入方向流量的标准姿势。我做过多线接入优化时,就经常给备份链路的出方向策略里prepend两三次自己的AS号,让对端运营商感觉“这条路绕了远路”,从而把入方向流量尽量压制在主链路上。实测下来,一般在备份链路上prepend 2到3次比较合适——太少了不管用,太多了万一主链路全挂,备份链路撑不住全量流量,就悲剧了。2.4 AS_PATH在选路中的另一个身份:防环和策略工具除了选路,AS_PATH还有一个专长:防环。BGP明确规定,如果一条路由的AS_PATH里包含了自己的AS号,那它就收到了一条“在AS内绕了一圈又回来”的路由,这种情况必须直接丢弃。这就是BGP最重要的防环机制,它根本不需要额外配置,天然自洽。在实际维护中,AS_PATH也经常被用来做“路径过滤”。比如我们跟某些不靠谱的下游有互联,为了防止他们一不小心成了我们所有流量的中转,我们可以用AS_PATH ACL精确匹配、只允许特定AS_PATH通过。这种打法比用前缀过滤器更精细,也更难被绕过。我习惯在做安全排障的时候,同时挂上前缀过滤和AS_PATH过滤两道关卡,宁可过度防护,也不给路由泄露留机会。3. 谁是“最轻”的那一个:ORIGIN、MED与下一跳的隐秘权重很多人学到前四条就以为差不多了,但真实故障往往就藏在后面几条“不太起眼”的属性里。ORIGIN、MED、IGP下一跳度量,这三兄弟在多数情况下打前四条打平了才登场,但一旦登场,往往决定了流量方向的天平往哪边倾斜。3.1 ORIGIN:路由出生地的“血统”标记ORIGIN属性用来表示这条路由是怎么进入到BGP世界的,有三种取值:IGP(通过network宣告,最可信,值2)、EGP(外部网关协议,已基本绝迹)、INCOMPLETE(通过重分布等途径进入,可信度最低,值1)。它的优先级是IGP > EGP > INCOMPLETE,也就是说,它是“越小越优”(数值上2优于1,但因为EGP实际几乎不出现,所以核心就是IGP优于INCOMPLETE)。实战中你直接配置ORIGIN的机会不多,但它经常在“暴力重分布”的场合里冒出来搞事。比如有人把OSPF整个重分布进BGP,那产生的路由ORIGIN就是INCOMPLETE,血统最低。如果同一个前缀同时存在network宣告和重分布两种来源,即使后者的AS_PATH更短,BGP也会因为ORIGIN优先级更高而选择那个“血统更纯”的network路由。这很容易让人困惑:路径短为啥不走?原因就在这儿——血统很重要,出生决定命运。3.2 MED:跨AS的“价格标签”与它的边界限制MED全称Multi-Exit Discriminator,多出口鉴别器,它是唯一一个正经用来“跨AS”传递并影响对端AS选路的属性,但它有个硬约束:MED只能传递给相邻的AS,不会继续往更远的地方传。机制上前置条件是默认值0,越小越优。它的应用场景很典型:两个AS之间有两条物理链路互联,AS1希望AS2去往某前缀时优先走其中一条链路。那AS1就可以在自己的两条出口上对播出的该前缀设置不同的MED值,比如主链路MED=50,备份链路MED=200,AS2收到后会自动优选MED更小的那一条。用大白话讲,就是给两条路贴了不同的“价格标签”,对端就会自动选“便宜”的那条。但MED有个比较坑的地方:它的比较是有限制的。BGP默认MED比较只发生在“源自同一个AS的两条路由”之间,也就是需要参数bgp always-compare-med来打破这个限制,否则不同AS来源的路由之间不做MED比较。我曾经在排障时看到两个上游给同一个前缀发了不同的MED,但路由器始终不走MED更小的那条,结果一查才发现,它们来自不同的AS,默认根本不会触发MED比较。这个参数官方文档写得零散,但实际运维里极其关键。3.3 下一跳IGP度量的“战术价值”:最终路径优化到了这个阶段,BGP已经选出了“外部视角最优”的路由,但如果它要真正把流量发出去,还需要知道下一跳在自己的IGP路由表里有多“好”。所以第8条规则就登场了:比较到达BGP下一跳地址的IGP度量值,越小越优。这条规则的存在,是BGP和底层IGP之间恰到好处的一种“协同”。因为BGP自己不看物理拓扑细节,它依赖IGP来告诉它“怎么走最划算”。如果两条BGP路由下一跳不同,但其他所有属性全打平,那IGP度量小的一方就会胜出。尤其是在一个复杂的IBGP体系里,这个规则经常在“多台Route Reflector指向不同物理出口”的场景下发挥真实作用。经验上,我通常不会主动去调IGP度量来影响BGP选路——太绕了,而且很容易把IGP内部的链路开销搞得异常。但我会在排查选路异常时,先顺手看一下这两条路由的下一跳在IGP里的度量值。有两次我排了半天都没找到问题,最后就是这一关“兜底”才把真正的差值揪出来。4. 我们在真实网络里是怎么“摆弄”这些属性的:四类调控手法前两节我们拆了属性,这节我想重点落地:既然知道了BGP按顺序比属性,那实际维护中我们是怎么用工具达到“我要它走这条,它就得走这条”的?这四类手法是我在工作中最常用的,建议你收藏。4.1 入方向工具:控制“别人怎么看待你的路由”所谓入方向,是指“其他AS往你的AS发送流量时,会选择哪条路”。由于路由是你宣告出去的,对你自己的BGP路由做属性修改,只影响别人对你AS内的路径偏好。常见操作:AS_PATH Prepending:把备份链路宣告的路由人为拉长,让上游觉得这条路绕远,从而减少入流量MED设置:在给不同上游的出口上设置不同的MED,引导对端优先走指定链路前缀精确宣告:用更精确的前缀(比如/24而不是/16)在主链路宣告,让更细粒度的最优路由自然出现这套手法里的AS_PATH Prepending,通常会配合ip as-path access-list或者route-policy一起用。比如我最近维护的一个双线出口,就做了这样的配置(示意):route-policy PREPEND permit node 10 if-match ip-prefix important-prefix apply as-path prepend 65001 65001 65001 apply med 500 end-policy # 上面这个策略仅在备份链路方向生效, # 主链路方向不做任何修改,靠自然属性胜出。这样设完之后,我用show ip bgp 8.8.8.0/24一查,非常直观:主链路AS_PATH长度短,备份链路AS_PATH长度被拉长了,入方向流量自然集中到主链路。要测试效果的话,可以在维护窗口手动把主链路的物理接口shutdown,观察备份链路是否能承接流量,再恢复。4.2 出方向工具:控制“你的流量怎么走出去”出方向,是指“你的AS访问外部目标时,优先走哪条出口”。这完全由你本地及AS内部的策略决定。核心工具就是Weight和LOCAL_PREF。只影响某一台本地设备:使用Weight影响整个AS:使用LOCAL_PREF,并通过IBGP全量传递我早年在维护双出口时,刚开始不懂LOCAL_PREF的“网内共振”特性,只在出口路由器A上设置了路由策略,结果别的主机访问外网还是走的旧路径。后来才明白,LOCAL_PREF必须靠IBGP在整个AS内同步,才能让全AS的路由器达成共识。于是我把策略改到出口设备的入方向,并确认IBGP邻居关系正常建立,再一查show ip bgp,所有路由器都认了这条LOCAL_PREF=200的路由,出方向流量才顺利切过去。4.3 出/入方向的组合拳:多技术出口的最优路径矩阵当你的AS有多个出口、多条链路、多个运营商时,单独靠任何一个属性都不完美。我们通常会用“组合拳”来构建一张最优路径矩阵。假设企业在两个城市各有一个机房,分别连接两个不同的运营商,且通过专线/Overlay组了IBGP全网。我们需要实现:南方用户走南方出口、北方用户走北方出口、附近机房互备。这种场景我会把LOCAL_PREF和AS_PATH Prepend搭配起来玩:南出口设备上对南方运营商的线路宣告全国前缀,AS_PATH不修饰,LOCAL_PREF默认或稍高北出口设备上对同一前缀宣告时AS_PATH prepend,LOCAL_PREF低一些这样外部流量从南方进来找不到更优路径,逆向往北走;内部流量出境则优先走本地区域,两边形成流量平衡这种矩阵设计,不是一次配置完就一劳永逸的,而是要持续观察流量曲线、对端路由表反馈来微调参数。做网络优化的人,本质上就是在这些属性参数里“弹钢琴”。4.4 策略下发前的“小动作”:过滤与抑制,先堵后梳在实际操作中,我很少只单纯改属性,而是一上来先做“过滤+抑制”的预处理:入方向:挂前缀列表、AS路径过滤器,把不想要的、不该收的路由直接挡在门外出方向:只宣告我们真正持有的、合法的前缀,防止路由泄露或恶意路由广播针对震荡路由:使用bgp dampening抑制半衰期高的路由,防止“一会儿通一会儿断”影响全局为什么要先做这一步?因为属性调控是基于“已有路由”的,如果有大量垃圾路由混进来,那即使LOCAL_PREF调得再优,也只是在垃圾堆里挑“相对好的垃圾”,完全没意义。把不健康的路径先剔掉,剩下那些可比较的路径才有应用选路策略的价值。5. 那些年我们踩过的选路坑:真实排障案例与思维复盘讲完理论和方法,不聊几个真实踩坑案例,总觉得少了点灵魂。下面这三个案例都是我在维护不同类型的BGP网络时实际碰到的,问题都很典型,希望你能从中看到自己网络的影子。5.1 案例一:LOCAL_PREF“传不出AS”引发的双向流量失衡某次做跨城双线优化,我按老经验在主出口上对某段重要前缀设置了LOCAL_PREF=180,备份链路默认100。配置完成后,同城数据中心内部访问外网的情况正常,但我顺手检查了一下上游的入方向流量,发现几乎全是走备份链路进来的,与我预期的“主链路优先”完全相反。当时我第一反应是主链路宣告出了问题,查了附属的所有节点,发现宣告正常,MED默认0。后来才回过神来:LOCAL_PREF作为IBGP属性,它只在AS内部传播,我设置的180只对内部路由有效,对上游AS没有任何意义。上游AS判断“走哪条路进入我的AS”,取决于我宣告给它的AS_PATH和MED,而不是我本地LOCAL_PREF的数值。这个案例给我们的教训是:方向对应关系必须时刻记清——控制“出”靠Weight和LOCAL_PREF,控制“入”靠AS_PATH Prepending和MED。方向搞反,跑断腿都查不出问题。5.2 案例二:MED比较的“非对称陷阱”在双归接入时突然出现某金融客户做双归接入,两条链路分别接两个不同的运营商,上游各自宣告了相同的网段。我们原本预期去往某些地址时,因为运营商B的MED较小,流量会优先走B链路。但实测中发现流量几乎总走A链路,怎么都切不过去。排查链路层层递进:首先排除物理、接口、BGP会话问题;再用show ip bgp对比两条路由的完整属性,发现它们的AS_PATH长度、LOCAL_PREF都完全一致,只有MED不同;理论上应该走MED更小的B链路。问题来了:为什么没走?后来我才想起来,这个场景下两条路由是来自两个不同AS的。BGP默认规则是:只有同一AS来源的路由才做MED比较,不同AS来源直接跳过MED比较,进入后面“教条式”的规则比拼。也就是说,MED想跨不同AS比较,必须在设备上全局开启bgp always-compare-med。在这个真实切换案例里,这参数开不开,直接决定了流量是否按预期流动。5.3 案例三:AS_PATH短不一定绝对优先,ORIGIN血统一击绝杀某次做路由优化,我们想让一部分流量从更短AS_PATH的主链路走。按常规理解,AS_PATH最短一定会胜出。可是配置完成后,我们用工具追踪路由路径,流量却仍绕道备份链路,主链路上的AS_PATH虽然短,但就是没被选中。用show ip bgp prefix细看属性,发现主链路那条路由的ORIGIN是INCOMPLETE,备份链路那条是IGP。回头再对照决策规则的顺序,AS_PATH比较(规则4)排在ORIGIN之前,所以只要AS_PATH有长短差异,理应立刻生效。但这个案例中两条AS_PATH长度其实一样,它们打平后进入ORIGIN比较,于是血统更正的IGP反而胜出。后来我们用network命令显式宣告这个前缀,让ORIGIN变成IGP,再对照show ip bgp一看,选路立刻切到了主链路。这个案例说明:决定选路的永远是决策顺序里最先出现差异的那一条属性。不是哪个“显眼”就哪个说了算,而是“先比谁”才说了算。理清属性顺序,你才能预判结果。6. 属性跟踪与调试指南:日常维护里我用得最顺手的几条命令网上有很多BGP的show命令大全,但真正日常维护用得最频繁的其实就那几条。我在这里把它们串成一个完整的排障链路,让你遇到选路异常时能一条龙排查。6.1 show ip bgp:不是只盯着BGP table,还要学会“逐行理解”show ip bgp是基础,但我强烈建议你多看一眼Network Next Hop Metric LocPrf Weight Path这一行里的每个字段。尤其是当你的前缀有多种来源时,你会看到同一个Network下面挂着多行不同Next Hop的路径,每一行都对应一条“候选路径”。通过它的输出,我们能定位到“具体打平到了哪一步”:如果某行有>标记,说明它是当前最优路径;顺着它的属性回溯,就能知道它到底赢在哪一条规则上。如果某些行完全相同的属性一长串,那大概率后面几条“兜底规则”在起作用,这时也要警惕“该加参数区分路径了”。6.2 show ip bgp rib-failure:一个被严重低估的调试入口很多人在BGP选路不理想时,只盯BGP表,却忽略了show ip bgp rib-failure这个命令。它专门用来展示那些BGP认为是最优路径、但为什么没有装进路由表(RIB)的记录。出现RIB failure通常意味着路由冲突,比如去往同一前缀,有其他协议(如静态路由、OSPF)的路径在路由表里占据了优先级,BGP就算选出来也放不进去。这是一个特别容易让人抓狂的坑:你查BGP表,明明有一条最优路径,策略也都对,但流量就是不过去。结果一看RIB failure,才发现底层路由表被一条静态路由霸占了。所以每次选路排查,我都会先跑一遍show ip bgp rib-failure,五秒定位是否有“BGP赢了属性,却输了安装权”的诡异局面。6.3 show bgp neighbor和debug ip bgp updates:观测邻居的“心情状态”最后是邻居层面的排查。BGP选路的前提是邻居关系稳定。show bgp neighbors是基础,但我更常用它来看“发过来/收过去”的更新统计,确认当前更新的内容与预期一致。遇到选路突然变化,并伴随便更新,再考虑抓包或开启debug ip bgp updates。不过这类debug命令要小心用,生产环境开大范围debug会瞬间刷爆CPU,我通常只加peer-address参数限定单个邻居,调试完立即关闭。整个排障思路其实就是一层层剥洋葱:邻居会话 → 路由接收/发送 → BGP表的属性比较 → RIB安装 → 全局路由表转发。哪一层断了,就在哪一层深挖。不会一步到位,但每层都能找到对应的命令快速验证。7. 从“会配”到“会调”:关于选路优化的进阶经验到这儿,各位可能已经把核心属性和基本调试命令都消化完了。可如果你经常跟BGP打交道,一定会有种感觉:能配置是一回事,调得好不好是另一回事。最后我想分享几条进阶经验,它们不是标准教科书里会写的,但对实际网络“手感”的提升帮助很大。7.1 永远把“稳定性”放在“最优”之前BGP的基因是稳定性优先。所以我在做任何调优前,都会先问自己一个问题:这个改动会不会导致路由震荡?把一条路由从一个出口切到另一个出口,哪怕策略上完全可行,也要考虑对业务的影响面。最稳妥的做法是先在测试环境或维护窗口内做小范围验证,观察一段时间的选路稳定性和流量曲线,确认没有抖动了,再全量下发。生产网络里,稳定性就是最大的可用性。7.2 不要迷信“唯一正确答案”,属性参数本身就是可调参数我碰过不少同行在调LOCAL_PREF或MED时,会把某个数值当成“神谕”:比如LOCAL_PREF一定要200,MED一定要100。其实BGP选路中的属性数值只是相对大小,重要的是“比较关系”,而不是“绝对数值”。你能在合理范围内灵活调整,是为了适应不同的链路质量、成本和策略。比如主备链路的LOCAL_PREF差50还是差150,取决于你对主链路的“偏爱程度”以及备份链路的承载能力——给备份链路留出足够的“触发空间”,但也不至于主链路一有风吹草动就浪费了备份能力。7.3 用“路由起源验证”来守住最后一层底线现在大规模网络都在推RPKI(资源公钥基础设施)和BGP安全机制,很多老工程师会觉得这是运营商的事。但我建议企业网络也在Edge设备上启用“路由起源验证”,配合前缀过滤,这会大大降低误收恶意路由、路由劫持的风险。这也是BGP维护从“被动响应”走向“主动防御”的重要一步。技术上,初期可以先开启接收RPKI无效路由的警告模式,观察一段时间再决定是只接受有效路由,还是预警后由人工介入。回到开头那一点:BGP选路不是选“快”,而是选“优”,但这个“优”的标准,全部沉淀在那一条条有顺序的属性规则里,又有一层层本地策略和全局策略在中间博弈。希望你在读完这篇文章后,能重新审视自己网络里那些“想不通”的路径选择,顺着属性比较的顺序,找到那个真正主导一切的关键差异。当你有一天能够不看文档,就能凭show输出预判出流量该往哪走的时候,你会觉得,BGP这门手艺真的很有意思。