<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>BGP · XB 现场笔记</title><link>https://www.xbcatm.com/zh/tags/bgp/</link><description>基于 HTTP、DNS、TLS、Caddy、SSH、发布与恢复的可复现运维现场笔记。</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://www.xbcatm.com/zh/tags/bgp/index.xml" rel="self" type="application/rss+xml"/><item><title>BGP 聚合收窄路由表</title><link>https://www.xbcatm.com/zh/posts/bgp-aggregation-shrinks-the-table/</link><pubDate>Fri, 08 Oct 2027 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/posts/bgp-aggregation-shrinks-the-table/</guid><description>抑制更具体前缀后，聚合可以减少下游表项，但覆盖路由仍需要明确授权、起源策略，以及成员不可达时的处理。</description><content:encoded>&lt;p&gt;聚合可以用一个覆盖前缀，替代若干更具体的路由通告。只有更具体前缀确实受到抑制、且其他对等体没有继续提供它们时，下游表项才会减少。成员不必填满整个汇总范围：几个稀疏子网也能形成一个较大的覆盖块，但该通告同时会吸引发往空洞地址的流量。因此，聚合既是规模问题，也是可达性和地址授权问题。&lt;/p&gt;
&lt;h2 id="聚合究竟减少了什么"&gt;聚合究竟减少了什么&lt;/h2&gt;
&lt;p&gt;对等体同时收到三个成员前缀和一条汇总时，仍然持有四条路由。FRR 的 &lt;code&gt;aggregate-address 10.1.0.0/16 summary-only&lt;/code&gt; 抑制被覆盖的更具体前缀通告，并不会把它们从聚合路由器自己的 BGP 表删除。生成汇总的前提是 BGP 表中至少有一个符合条件的更具体前缀，仅在其他路由表中存在一条记录还不够。&lt;/p&gt;
&lt;p&gt;稳定的汇总可以把部分成员变化挡在下游之外，但这个收益有前提。最后一个成员消失、汇总属性改变，或者出口策略变化，都可能继续产生更新。抑制通告不会修复客户链路，只会改变其他网络获得的故障信息。聚合者仍然需要监控内部成员，不能因为上游只看到一条稳定路由，就认为内部全部可达。&lt;/p&gt;
&lt;p&gt;汇总覆盖的地址通常也比列出来的几个子网更多。宣告之前，应检查整个范围的使用授权以及预期的汇总起源 AS。地址对齐、数值相邻、能节省表项，都不是拥有宣告权限的证据。提供商可以在自己的地址分配范围内合法汇总客户网络；成员来自不同起源 AS，并不自动意味着这次聚合非法，关键是整体授权和出口契约。&lt;/p&gt;
&lt;h2 id="保留清晰的起源"&gt;保留清晰的起源&lt;/h2&gt;
&lt;p&gt;FRR 的 &lt;code&gt;suppress-map&lt;/code&gt; 用路由映射选择哪些更具体前缀受到抑制。&lt;code&gt;as-set&lt;/code&gt; 处理的是另一个维度，即怎样表示成员路径中的 AS 信息。AS_SET 是无序集合，并非只包含客户起源号码的清单。历史上的 RFC 4271 在计算 AS 路径长度时，将整个集合计作一个，不会按集合成员数量逐个增加长度。&lt;/p&gt;
&lt;p&gt;RFC 9774 已经废弃 AS_SET 与 AS_CONFED_SET。除非运营者为了过渡显式选择其他行为，发言者不得继续通告这些集合，收到含集合的路由时应按撤回处理。应选择明确、获得授权的汇总起源，并配置相应 ROA，不能把 AS_SET 当作常规修补办法。邻居的起源过滤器也不会因为路由器生成了一条汇总，就自动接受这个范围。&lt;/p&gt;
&lt;h2 id="坏掉的样子"&gt;坏掉的样子&lt;/h2&gt;
&lt;p&gt;在选定转发表中的普通目的地址查找，使用最长的已安装匹配前缀。因此，有效的 &lt;code&gt;/24&lt;/code&gt; 会覆盖其上方的 &lt;code&gt;/16&lt;/code&gt;，不论两者的 BGP 本地优先级谁更高。不过，路由首先必须通过导入策略、下一跳解析和安装过程。BGP 为同一前缀选择候选路径，与转发时在不同前缀之间做匹配，是两个不同阶段。&lt;/p&gt;
&lt;p&gt;一个成员消失时，只有失去可用更具体路由的目的地才回落到汇总，健康成员仍可继续转发。某个客户撤回路由，不会天然让汇总覆盖的所有地址同时黑洞。在生成汇总的路由器上，对没有成员路由匹配的地址设置丢弃路径，可以防止数据包顺着默认路由返回上游，进而形成转发环路。&lt;/p&gt;
&lt;p&gt;丢弃时是否生成诊断报文，取决于设备和配置，不能保证必然静默，也不能保证 ICMP 一定送达。撤回汇总也不必然等于没有路由，因为另一个覆盖前缀或默认路由可能仍然存在。应该检查真实转发表和相关计数器，而不是只因为看不到某个更具体前缀，就断言汇总本身配置错误。&lt;/p&gt;
&lt;h2 id="快速验证"&gt;快速验证&lt;/h2&gt;
&lt;p&gt;将下面代码交给 Python 3 运行，保持断言开启。它不创建套接字，也不修改路由器配置。两个客户路由位于同一条覆盖丢弃路由之下；这个刻意缩小的模型只隔离最长前缀匹配和成员撤回的影响范围，不实现 BGP 会话、策略交换或者真实收敛过程。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ipaddress&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip_network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.0.0/16&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;discard&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.4.0/24&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer-a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.7.0/24&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer-b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;no-route&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefixlen&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.4.9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer-a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.7.9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer-b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.4.0/24&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.4.9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;discard&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.7.9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer-b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;withdraw A: A=discard, B=customer-b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.0.0/16&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.4.9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;no-route&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.1.7.9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;customer-b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;withdraw summary: A=no-route, B=customer-b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一行输出表示客户甲回落到丢弃路由，而客户乙仍然命中自己的表项。删除汇总之后，甲变成没有路由，这是因为夹具刻意没有放入默认路由；乙仍独立可达。可以把增加默认表项作为后续练习，观察无路由结果如何变化，避免把这个特定模型的结果误写成所有网络都会遵循的行为。&lt;/p&gt;
&lt;p&gt;在获得授权的实验路由器上，还应分别检查收到、选中、发出以及实际安装的路由，再撤回一个成员进行对照。确认汇总是否保留、属性是否改变，以及目的地址最终命中哪条路由。真实路由器集成与转发效果需要那一步实验；这里的 Python 断言仅证明所声明的查找模型，不能代替硬件转发表或协议实现验证。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc4271.html"&gt;RFC 4271 BGP-4&lt;/a&gt;，定义 ATOMIC_AGGREGATE、AGGREGATOR 与 AS_SET，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.frrouting.org/en/latest/bgp.html"&gt;FRR BGP 路由聚合&lt;/a&gt;，说明聚合生成、成员抑制与 AS-set 选项，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc4632.html"&gt;RFC 4632 CIDR&lt;/a&gt;，无类前缀与最长匹配转发模型，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9774.html"&gt;RFC 9774：废弃 AS_SET&lt;/a&gt;，更新的聚合与起源要求，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>BGP 组成了互联网的路由表</title><link>https://www.xbcatm.com/zh/posts/bgp-is-the-internet-routing-table/</link><pubDate>Sun, 12 Sep 2027 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/posts/bgp-is-the-internet-routing-table/</guid><description>BGP 让彼此独立的网络互相通告能提供哪些前缀、愿意接受哪些路径。与内部协议不同，它交换的既是可达性，更是策略。</description><content:encoded>&lt;p&gt;BGP 在独立运营的网络之间交换可达性，但互联网并不存在一张统一、权威的转发表。每台路由器都学习经过策略过滤的视图，选择路由，再尝试把可用下一跳安装进转发系统。两台路由器为同一个前缀选择不同路径，完全可能是正常情况。理解 BGP，需要把通告、选路策略和数据包转发分开，不能把它们合并成一个放之四海皆准的答案。&lt;/p&gt;
&lt;h2 id="as-路径同时承载历史与策略"&gt;AS 路径同时承载历史与策略&lt;/h2&gt;
&lt;p&gt;普通 eBGP 场景中，路由器向外宣告时会在 AS 路径前加上自己的号码。接收方通常排除已经包含自己 AS 的路径，用于避免自治系统之间的环路，但存在显式配置的例外和协议扩展。自治系统内部的 iBGP 通常不再增加 AS 号码；它的转发通告限制及路由反射器规则处理的是另一类内部环路问题。&lt;/p&gt;
&lt;p&gt;AS_PATH 还是过滤和选路的输入。重复前插可能让一条路由在看重路径长度的网络里吸引力下降，却不能推翻对方优先级更高的本地策略。也没有一条通用规则说，前插之后路由就会被过滤。必须结合真正的运营商策略、客户授权和接收条件，理解该字段在当前网络里的作用。&lt;/p&gt;
&lt;p&gt;LOCAL_PREF 会作为属性分发给内部 BGP 对等体，通常不传给外部对等体。部分实现提供的 weight 则只属于本地路由器，也不是标准 BGP 路径属性。把两者都描述成不会进入更新报文，会掩盖关键区别：本地优先级可以影响自治系统内其他设备的决策，而 weight 的效果一般局限在一台路由器。&lt;/p&gt;
&lt;h2 id="先比较同一个前缀"&gt;先比较同一个前缀&lt;/h2&gt;
&lt;p&gt;最佳路径过程比较的是同一前缀的多个候选路径。具体顺序取决于实现和配置，包括路径资格、本地策略、AS 路径长度、MED 比较范围及下一跳可达性。某个产品的 weight 优先列表并不是协议完整定义。MED 通常在来自相同邻居 AS 的路径之间比较，但实现可以提供改变这一行为的选项，不能把默认规则写成不可改变的限制。&lt;/p&gt;
&lt;p&gt;之后，转发过程在已安装目的路由中做最长前缀匹配。一个 &lt;code&gt;/25&lt;/code&gt; 与覆盖它的 &lt;code&gt;/24&lt;/code&gt;，并不是通过同一套最佳路径平局规则互相竞争。只要两者均被接受并安装，前者就匹配那一半地址，即使后者的 AS 路径更短。策略路由或其他额外转发机制还需要分别检查，不能从这条普通查找规则推断全部设备行为。&lt;/p&gt;
&lt;p&gt;路由表规模同样依赖观测点、地址族与时间。独立前缀数量、收到的全部候选路径以及硬件 FIB 表项，是不同统计口径。聚合可以减少部分通告，但多宿主和流量工程可能确实需要具体路由。仅按地址算出的可聚合数量，并不能证明相应的全部策略也能保留，因此不应把一个动态快照当作永久容量门槛。&lt;/p&gt;
&lt;h2 id="坏掉的样子"&gt;坏掉的样子&lt;/h2&gt;
&lt;p&gt;未经授权的起源通告属于前缀劫持；路由泄漏则是把学到的可达性传播到预期策略范围之外。两者可能重叠，却不是同义词。下面假设的 &lt;code&gt;/25&lt;/code&gt; 只展示查找效果，真实网络可能已经通过前缀长度、起源或客户过滤拒绝它。发现陌生更具体前缀值得调查，但不等于已经证明攻击正在生效。&lt;/p&gt;
&lt;p&gt;RPKI 起源验证将通告前缀、允许的起源和最大长度，与验证过的记录进行匹配。它不认证整条 AS 路径，也不判断每一个出口关系是否合法。合法起源的路由仍可能发生泄漏。因此，需要将起源验证与适当的导入、导出策略配合，并监控变化，不能笼统声称所有更新都未经检查便向全球扩散。&lt;/p&gt;
&lt;p&gt;健康会话也不能证明转发安装成功。硬件容量不足、下一跳无法解析，或设备编程失败，都可能使控制平面路由无法真正使用。失败后的行为取决于平台，不保证自动退回软件转发。容量规划要看设备实际分区、启用特性和安装遥测，而不是相信一个普遍适用的百万表项目标。排查时应保留相关错误和差异。&lt;/p&gt;
&lt;h2 id="快速验证"&gt;快速验证&lt;/h2&gt;
&lt;p&gt;用 Python 3 运行下面夹具，保持断言开启。前半段故意只模拟本地优先级和 AS 路径长度，其他选路条件视为相同；后半段则使用独立的转发表。代码采用文档专用地址，不创建会话、监听或网络通告，也不会接触任何真实路由器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ipaddress&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip_network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;policy-first&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;localpref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;64501&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64502&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64503&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;shorter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;localpref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;64504&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64503&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localpref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;policy-first&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localpref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;shorter&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;198.51.100.0/24&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;legitimate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;198.51.100.128/25&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;unexpected&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefixlen&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;198.51.100.20&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;legitimate&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;198.51.100.200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;unexpected&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;same prefix: local preference first, then path length&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;different prefixes: lower half legitimate, upper half unexpected&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本地优先级还不相同时，较长路径获胜；将优先级调成一致后，才由较短路径获胜。另一个独立查找中，低地址命中合法 &lt;code&gt;/24&lt;/code&gt;，高地址命中意外 &lt;code&gt;/25&lt;/code&gt;。这些输出解释的是两个不同决策，不能宣称已经实现或者验证真实 BGP。实际诊断仍需关联接收和发出的路径、选中路由、硬件安装状态，以及获得授权的客户端探测结果。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc4271.html"&gt;RFC 4271 BGP-4&lt;/a&gt;，决策过程与 AS 路径环路检测，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6811.html"&gt;RFC 6811 前缀起源校验&lt;/a&gt;，RPKI 校验能证明什么、不能证明什么，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc7908.html"&gt;RFC 7908 路由泄漏&lt;/a&gt;，泄漏通告的问题陈述，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cidr-report.org/as2.0/"&gt;CIDR Report&lt;/a&gt;，当前 IPv4 表规模与各 AS 的更具体前缀数量，已核验 2026-09-16。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.frrouting.org/en/latest/bgp.html"&gt;FRR BGP 路径选择&lt;/a&gt;，实现特定的选路控制与诊断，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>