
删除 Inflight Bounds为什么 KCC 放弃了 BDP 钳位一段被继承的设计BBR 的核心循环只有三个增益——1.25× 探测、0.75× 排水、1.0× 巡航。cwnd 不被人为设限它由 pacing rate 和 ACK clock 共同决定自然收敛到 BDP 附近。但 BBRv2 引入了一对 cwnd 钳位inflight_lo默认 1.25× BDP和inflight_hi默认 2.0× BDP。目标是在探测阶段把 cwnd 锁在一个安全区间——不要过低导致欠填充不要过高导致丢包。KCC 在最初构建时继承了这个设计。参数化更灵活低端默认 1.0×高端默认 2.0×但本质是同一件事。后来我们删掉了它。两把钳子两条路径要理解为什么删先要看钳子夹在什么地方。cwnd 路径——kcc_set_cwnd()每收到一个 ACK 就计算一次目标 cwnd。把钳子放在这里意味着每一个 ACK 都要检查我算出来的 cwnd 是不是太低/太高了低就垫上去高就压下来。pacing 路径——bbr_set_pacing_rate()决定发包速度。内核 BBR 在这里有一个bbr_inflight_hi_from_bw()它对 pacing 的 inflight 做了 2× BDP 上限。但这不夹 cwnd——它限制的是允许在途的数据量不是窗口本身。两者的区别微妙但重要cwnd 钳位改变的是算法认为自己需要多少空间pacing 钳位改变的是算法实际发送多少数据。前者是容量估计偏差后者是行为约束。1.0× 下限自己挡自己KCC 的 DRAIN 模式STARTUP 过渡到 PROBE_BWpacing gain 0.344x但 cwnd_gain 保持在 2.885x。所以下限想挡也没东西可挡——target cwnd 已经是 2.885x远超 1.0x。那下限会挡什么挡 PROBE_BW 周期内的 0.75x 探测阶段。每 8 轮 PROBE_BW有 6 轮巡航、1 轮上探、1 轮下探。下探时 pacing gain 0.75x。如果算法算出一轮内 inflight 略微低于 BDP1.0x 下限把它垫回 BDP——这是保护但也是过度保护0.75x 阶段的目的就是让 inflight 有机会降到 BDP 以下以便确认 BDP 还是对的。但在多流场景1.0x 下限才是真问题——不是挡排水是聚合过配见下文。单独说1.0x 下限放在 cwnd 路径并无实际害处。把它和 2.0x 上限一起删掉的理由不是它对 drain 有害——是它和上限是同一逻辑的两面而这个逻辑该由其他机制处理。/* The pacing gain of 1/high_gain in BBR_DRAIN is calculated to typically drain * the queue created in BBR_STARTUP in a single round: */staticconstintbbr_drain_gainBBR_UNIT*1000/2885;从上限看关注点分离2.0× BDP 上限放在 cwnd 路径逻辑是这样的ACK 聚合可能让一个 ACK 确认超过 1 BDP 的数据cwnd 会爆炸。所以要夹。但内核 BBR 处理同样的问题用的是一个更精确的工具——bbr_quantization_budget()。它不是硬夹到 2×而是按 TSO 粒度、偶数轮次、probe 余量计算一个刚好够的量化头寸。然后 ACK 聚合有专门的bbr_ack_aggregation_cwnd()补偿有额外数据才加没有就不加。换言之cwnd 路径本身就有两个工具精确处理上限问题。2.0× 钳位是一个更粗糙的兜底——它覆盖了这两个工具本该处理好的情况。是否需要这个兜底如果你的量化预算和聚合补偿是正确的它从来不会触发。如果触发了说明前两个工具有问题你应该修它们而不是加一个钳子。多流过配1.25× 的聚合效应假设瓶颈带宽 B8 条流共享。每条流认为自己的公平均速大约是 B/8。如果每条流都放了一个 1.25× BDP 下限那总会有人感到压力Σ inflight_floor 8 × (0.25 × B/8 B/8) 8 × 1.25 × B/8 1.25 × B八条流的 cwnd 总和不低于瓶颈的 1.25 倍。这不是八个人分一张饼——每个人说我至少要吃 1.25 口的份额一共预定了 10 口的量。池子里只有 8 口。所以 1.25× 下限在一个多流路径上不是保险是过配的根源。每条流都觉得我的下限很安全聚合起来就是大家都不安全。这就是为什么 KCC 从一开始就没用 BBRv2 的 1.25× 默认而用 1.0×——不是因为 1.0× 更好而是因为 1.25× 的聚合效应在共享瓶颈上制造了它声称要避免的问题。删掉之后少了两把钳子what changes?inflight 钳位被取下后PROBE_BW 下探阶段不会被下限强制垫回 BDP——可以暂时低于 BDP确认容量估计仍然正确。不会因为钳子而跳过排水周期。STARTUP 阶段不受影响——KCC 的 STARTUP 用的是指数爬升cwnd acked钳子本来就只设下限不设上限。下限和 BDP 目标在 STARTUP 本来就不是语义正确的约束。cruise 阶段的收敛完全交给 ACK clock——这和内核 BBR v5.4 一模一样。pacing rate 决定发送速度cwnd 提供空间。两者各司其职。多流场景从代码层面不会再有一个硬编码的过配因子。聚合 inflight 接近瓶颈容量而非高于它。选路而非修路inflight bounds 不是错的。它们在另一种路径上完全合理——浅缓冲区路径、单流主导的场景、BBRv2 需要兼容 CUBIC 共存策略的地方。KCC 选的路是另一条跟着内核 BBR v5.4 的 cwnd 模型把更极致的边界处理留给 pacing 路径和独立工具。ACK 聚合有补偿TSO 有量化预算多流过配有 drain-to-target 排水——每个问题有它对应的解法而不是让一个通用钳位覆盖所有。删掉两把钳子不是简化是各归其位。Tags: TCP, BBR, KCC, congestion control, inflight bounds, separation of concerns