两个站点通过 IPsec 隧道建立 BGP 邻居,互相学习前缀,于是拓扑图被改称为路径控制。正是这个标签开始了混乱。会话确实交换可达性,也确实施加策略,但它无权决定由哪家运营商、哪根光缆或哪台路由器承载加密报文。我见过一个团队重建一条本来能用的隧道,因为他们以为一次 BGP 路由变更会把流量切到另一条光纤路径上,而会话从来无法影响那条路径。

人们以为会话买到了什么

大部分预期来自实验室里路由变更的样子。你通过隧道宣告一个前缀,远端把它装进表里,流量随之移动。同样的序列也会发生在真正配有流量工程旋钮的路由器上,于是两者被混为一谈。实验室里两个站点通常共用一条接入链路,正因如此,差异在那里永远不会显现。

BGP 是可达性协议。它告诉邻居你能为某个前缀投递报文,并让双方对收到的提议排序。这在隧道之上确实有用:站点来去时前缀出现和消失,而且你可以在每台边缘设备上不写静态路由就拒绝某个网段。它做不到的是把运营商的 routers 交到你手里。

底层承载外部报头。你的隧道端点把加密报文发往对端地址,两个地址之间的网络按自身运营商安装的路由转发它们。BGP 会话里的任何东西都改变不了这个决定,除非同一家运营商提供能做到这一点的受支持服务。

会话实际承载什么

BGP 发言者向对端的 179 端口打开 TCP 连接,使用 RFC 4271 中定义的消息格式和路径属性。当对端地址位于隧道内部时,会话开始之前隧道必须已经起来、该地址必须可达。完成的 IKE 交换并不是 BGP 邻居。基于路由的 IPsec 实现在存在匹配的隧道路由时才放行流量,而基于策略的实现需要受保护选择器内包含对端地址。把这件事弄反,就会出现隧道是绿的、会话却干坐着的经典状态。

会话起来之后,策略决定什么穿过它。前缀列表、AS-path 过滤器、最大前缀数上限以及关于默认路由的明确决定是最低要求,而且两个方向都适用。接受一切的邻居可能给你一条默认路由,悄悄取代本地互联网接入。两个方向需要各自的列表,因为从邻居接受什么和向邻居宣告什么是两个不同的决定。

router bgp 65010
 neighbor 10.255.0.2 remote-as 65020
 address-family ipv4 unicast
  neighbor 10.255.0.2 prefix-list SITE-B-IN in
  neighbor 10.255.0.2 prefix-list SITE-B-OUT out
  neighbor 10.255.0.2 maximum-prefix 50

接着 MTU 咬人。封装缩小了可用载荷,于是一次大更新可能卡住一条看起来完全建立的会话:邻居还起着,前缀却永远不来,日志里也没有明显的东西。在责怪过滤器之前,先在隧道接口上限制 TCP MSS,或者设置留出开销余量的隧道 MTU。

外部报文仍然去哪

从一个站点到另一个站点的加密报文,沿本地路由器为对端公网地址选出的路径发出。如果两个站点从同一家运营商买 transit、经过同一处城域设施,或者一侧位于运营商级 NAT 之后,隧道只是碰巧才熬过运营商故障。在监控工具里数隧道图标,对此什么也说明不了。

路由选择和转发安装也是两件不同的事。一个前缀可以在 BGP 表里是最好的,却仍然不在转发表里,因为下一跳无法解析,或者更具体的路由胜出。当有人报告 BGP 学到了前缀但流量不通时,有用的问题是它有没有被安装、指向哪个下一跳。

对设计评审来说,诚实的答案是共享依赖清单:接入电路、上游运营商、设施,以及回程路径上任何有状态的设备。隧道之上的会话无法移除它并不坐落其上的依赖。

值得分开的三个决定

当设计把这些混在一起,每一次故障讨论都会绕圈。先在纸上分开,再把每一个映射到真正执行它的设备上。

DecisionWho controls itTypical failure
Which prefixes may cross the relationship?Both sides, through prefix and AS-path policy you configure deliberatelyA default route accepted by mistake, or a vague aggregate
Which overlay next hop wins?Local BGP selection plus next-hop resolution on your own routersPrefix learned, never installed in the forwarding table
Where do the encrypted packets travel?The underlay operators, unless a supported service adds real controlPath diversity that was never there

每一行有不同的负责人。第一行是谈判,第二行是你设备上的配置,第三行大体上是别人的网络。一份点名它触及哪一行的变更申请,比一份只说 BGP 问题的申请容易批准得多。

值得规划的故障模式

接受邻居的汇总路由是最常见的自伤。有人为了简化交换而宣告一条短聚合,远端接受了它,于是本不在隧道之后那些网段的流量跟着隧道走并死掉。按精确预期前缀过滤,或者使用边界正确的 security 前缀列表,绝不要因为会话看起来整齐就接受裸聚合。

撤销时机是第二件。检测取决于保持定时器、取决于你是否启用了 BFD、取决于隧道的对端失效检测,以及远端停止宣告的速度。已有会话是另一个问题:新路由可以恢复新连接,而已经建立的 TCP 会话仍在使用过期地址,路径上有状态防火墙或 NAT 可能保留已不再匹配的表项。把应用恢复放进验收标准,而不是假设一次路由变更能解决一切。

第三件是 回程路径的不对称。流量可以经隧道到达,却从一条从未被设计来承载它的运营商链路返回,表现为单向音频、握手失败或防火墙丢弃响应。两个方向要分别检查。

合同里写什么,以及如何验证

以书面形式索要允许的前缀:谁有权源出每个网段、是否允许默认路由、隧道服务支持哪些地址族。RFC 8212 让显式的导入和导出策略成为遵循它的实现中 eBGP 的预期,所以一个仍然依赖隐式全盘接受的邻居值得一问。

然后从设备而不是拓扑图去验证。FRR 风格路由器上的有用命令:

show bgp summary
show bgp ipv4 unicast 10.10.0.0/16
show bgp ipv4 unicast neighbors 10.255.0.2 advertised-routes
show ip route 10.10.0.0/16

再加两项路由表给不了你的观察。在外层接口上抓包,确认封装后的报文究竟指向哪个地址,例如 tcpdump -ni eth0 udp port 51820 用于 WireGuard 隧道,或 IPsec 的 ESP 过滤器。然后向对端公网地址做跟踪,并 把跳数与隧道内的跟踪做对比;如果两者走的是同一条运营商链,你的冗余活在路由策略里,而不是网络里。

最后,刻意测一次撤销。在维护窗口里把隧道拉下来,记录前缀还被安装多久、已有会话会发生什么,以及远端是否回落到一条你真正会接受的路由。那次演练比任何拓扑图都更能说明设计。

路由不是授权。你同意交换的前缀,对哪些用户能访问隧道之后的哪个服务什么也没说,所以把认证、允许的服务和主机防火墙留在原处。可达的邻居也不是无限 transit 或任意源出地址的许可,这类权限属于合同里的商业问题,而不属于某条 BGP 策略行。

  • 点名每一侧可以源出的前缀,以及永远不应接受的前缀。
  • 在隧道上限制 MSS,并确认大更新真的能到达。
  • 列出共享的底层依赖,而不是隧道数量。
  • 测量一次真实的撤销,并记录应用做了什么。

相关文章