摘要

  • 传统 HoldTimer 观察的是从邻居收到合格 BGP 消息的时间;即使反向 UPDATE、撤回或 KEEPALIVE 全部堵塞,它仍可能不断被入站消息刷新。
  • RFC 9687 定义本地配置的 SendHoldTimer:在规定时间内没有任何 BGP 消息成功发出时,本端记录原因、释放资源、关闭 TCP,并把状态机送回 Idle。
  • 安全部署的核心不是把计时器调短,而是把“生成消息、进入发送缓冲、实际发送、对端处理、数据面恢复”分层取证,并限制故障后的重连震荡。

设想一个边界路由器刚刚撤销一条失效路径。撤回已经由策略进程产生,本地 RIB 也已选出替代路径。与此同时,对端每三十秒仍送来 KEEPALIVE,监控面板于是显示一切正常。问题在 TCP 的另一个方向:邻居不再读取,本端发送队列持续增长,最新路由事实被困在套接字里。

旧通告却仍在远端生效。流量继续进入已被本端否定的路径。这里不存在“会话完全死亡”这一清晰事件;危险恰恰来自半条会话仍然健康。

一条 TCP 连接可以承载两个相反的事实

TCP 提供双向字节流,但两个方向的进展并不绑定。RFC 9687 给出的典型场景是远端接收窗口归零:远端仍可向本端写入 BGP 消息,本端却不能把关键消息写到远端。过载的控制进程、卡死的读取线程或异常队列,也可能制造同样的不对称。

RFC 4271 的 HoldTimer 是接收侧证据。收到 UPDATE 或 KEEPALIVE 时,本端按状态机规则重启它。这个证据只能回答“邻居最近有没有发来合格消息”,不能回答“邻居是否已处理本端最近的撤回”。

工程现场常把几个较弱信号误当成完整证明:路由进程生成 UPDATE,不等于字节已经离开;内核接受写入,不等于远端应用已读取;TCP 仍为 Established,不等于 BGP 进程可用;构造出 NOTIFICATION,也不等于对方能收到。对单向故障而言,最后一次成功发出 BGP 消息的时间,比会话徽标更有解释力。

RFC 9687 把处置时钟交给被堵塞的一端

RFC 9687 在 BGP 状态机中加入 SendHoldTime、SendHoldTimer 和事件 29 SendHoldTimer_Expires。SendHoldTime 是本地、逐邻居配置的政策值,不是双方协商的新能力;因此远端不支持该机制,也不妨碍本端依据自身发送证据采取行动。

会话从 OpenConfirm 进入 Established 时,只要 SendHoldTime 非零,发送保持计时器便启动。每次成功发送一条 BGP 消息,计时器重启;如果 SendHoldTime 或协商后的 HoldTime 为零,则按规范停止。离开 Established 时,计时器随会话资源一起释放。

非零 SendHoldTime 必须大于协商 HoldTime。若协商 HoldTime 为零,即使本地配置了非零 SendHoldTime,也要停止 SendHoldTimer。这不是格式细节,而是避免发送侧计时器变成一个更快、相互矛盾的 HoldTimer。

RFC 建议默认启用,并把“八分钟”和“两倍协商 HoldTime”中的较大值作为默认。领导层不应把这个建议误读成所有邻居都适合八分钟。路由服务器、反射器、受限客户设备与普通外联的负载、表规模和重连成本完全不同。

计时器到期后,本端必须记录 Send Hold Timer Expired,释放 BGP 资源,关闭 TCP,更新重试状态并转到 Idle。只有在不延迟清理的前提下,才可以尝试发送 NOTIFICATION。IANA 为此分配错误码 8、子码 0;但故障本身可能阻止错误消息抵达,因此本地日志和时间线才是首要凭证。

四种健康状态不能压成一个绿点

HoldTimer 问的是入站 BGP 消息何时最后到达;SendHoldTimer 问的是本端何时最后成功发送 BGP 消息;BFD 检查的是转发路径的快速连续性;TCP 重传或 keepalive 则回答传输层问题。

它们出现不同结论是合理的。BFD 可以正常,因为路径仍通;HoldTimer 可以正常,因为入站 KEEPALIVE 还在;TCP 可以 Established,因为双方都未关闭;SendHoldTimer 却可能到期,因为出站 BGP 没有进展。这个“分歧”不是监控噪声,而是诊断本身。

因此事件记录至少要区分:入站消息已收到、本端出站已推进、远端路由已处理、数据面已转发。前两项由 BGP 与套接字证据支撑,后两项必须用远端路由视图、FIB 和真实报文验证。SendHoldTimer 不能识别所有 BGP 僵尸,也不能证明数据面失败;它只对持续无法发送这一窄条件提供有界处置。

断开是修复动作,也是一笔成本

会话重置会使从该邻居学习的路径失效,触发最优路径重算、FIB 更新和替代通告。重连后还可能出现全表传输。对高扇出的路由反射器或路由服务器,一个正确的本地动作也可能扩展成明显的收敛波。

计时器太短,会把调度抖动、短暂背压或可恢复的零窗口变成不必要的断会。若根因仍在,重连与全表交换又会加重远端压力,健康机制就变成振荡器。计时器太长,则撤回和替代路径长期排队,陈旧路由继续掌权。

选择值时,应以协商 HoldTime 为硬约束,以实际队列时延、维护停顿、UPDATE 峰值、CPU 调度、表规模和重试成本为依据。不同邻居类别需要不同容忍度。可选的会话振荡抑制能限制快速重试,却不能修复容量不足或读取线程饥饿;它也不能替代根因分析。

有效演练必须保留底层路径

拔线并不能验证 SendHoldTimer,因为 HoldTimer 或 BFD 很可能先触发。正确演练要让底层转发和入站 BGP 保持正常,同时有控制地停止远端 BGP 接收处理。

BIRD 3.3.0 文档提供测试用 disable rx,并明确警告不得用于生产。它可以在隔离环境中制造所需的不对称,但演练必须限定邻居、路由和恢复步骤,不能把测试开关变成长期配置。

故障前,记录软件版本、协商 HoldTime、有效 SendHoldTime、计时器状态及正常队列基线。故障中,证明入站 KEEPALIVE 继续到达、最后成功发送时间不再推进、发送队列或零窗口持续存在,并让一条受控撤回或 UPDATE 确实被阻塞。

到期时,捕获本地错误原因、时间、NOTIFICATION 是否尝试、TCP 关闭与 FSM 转移。解除故障后,验证会话不会反复重连,受控路由得到纠正,FIB 与报文跟随新状态,队列回到基线。FRRouting 的支持清单与 BIRD 的配置文档只是测试起点;实际构建、回移补丁和本地配置决定生产行为。

谁能断会,谁就必须拥有证据

业务关键互联的断开权限不能只靠值班直觉。应保留最后生成消息、最后成功发送、队列年龄和深度、TCP 窗口、重传、入站消息时间、计时器重启及最终原因。路由证据还要指出哪些撤回或替代没有送达、远端陈旧视图维持多久、重置后如何收敛。

这些资料往往分散在路由守护进程、操作系统、远端门户、采集器和 NOC 工单中。若没有一个责任主体能把它们拼接起来,断会权限不是过度谨慎,就是任意。实用的数据主权并非“数据在本地”这么简单,而是组织能否访问、保留并使用足以证明处置正当性的运行数据。