TL;DR:BBRv3 默认将丢包率上限锁死在 2%,这在跨境、卫星等长肥管道(LFN)上会严重限制吞吐量。本文介绍一个安全的可调参数补丁,允许在特定条件下放宽该限制,同时保持 AQM 友好性。

背景:BBRv3 的 2% 天花板

BBRv3 通过测量带宽和 RTT 来估计瓶颈容量,并在探测带宽时设置了一个硬性丢包上限:
static const u32 bbr_loss_thresh = BBR_UNIT * 2 / 100; /* 2% loss */
一旦丢包率超过 2%,BBR 会认为发生了拥塞,冻结 inflight_hi ,停止探测更高带宽。
这在数据中心和低延迟网络中非常合理,但在以下场景中却成了瓶颈:

  • 跨境链路(中美/中欧):存在 2–5% 的稳定物理丢包
  • 卫星链路:高 RTT + 随机丢包
  • 高 BDP 链路:缓冲区深,但丢包并非总是拥塞

结果是:BBR 永远无法达到真实瓶颈带宽。

为什么不切回 BBRv1?

虽然 BBRv1 没有 2% 的硬性丢包限制,但它存在两个致命缺陷:

  • AQM 不友好:在 fq_codel / CAKE 等主动队列管理环境下,V1 容易填满缓冲,导致延迟飙升(Bufferbloat)。
  • 公平性较差:V1 的 Probe Up 阶段过于激进,在高并发场景下会挤压 Reno/Cubic 及其他 BBR 流的生存空间。

因此,我们需要的是一个保留 BBRv3 的 AQM 友好性和公平性,同时修补其 LFN 缺陷的方案,而非简单地倒退版本。

核心思想:条件放宽,而非无脑放开

我们的补丁引入两个 sysctl参数:

1
2
net.ipv4.tcp_bbr_lfn_loss_thresh_pct = 10
net.ipv4.tcp_bbr_lfn_min_rtt_fresh_ms = 5000

仅在满足以下 4 个条件时,才允许将 2% 放宽到 pct%

条件目的
mode == PROBE_BW && cycle_idx != PROBE_UP避开 RTT 滞后的探测上升期
rtt_us < 1.2 × min_rtt_us 确认没有队列堆积
min_rtt_stamp新鲜(≤ 5s) 防止使用陈旧的 RTT 基准
tx_in_flight ≤ 1.15 × BDP 防止 AQM 丢包被误判为物理丢包

这四个条件构成了一个安全沙箱,确保只有在“看起来真的只是背景噪音丢包”时才放宽限制。

实现细节

1. 内核核心变更(net/ipv4/sysctl_net_ipv4.c)

新增两个全局 sysctl 变量,供 BBR 模块读取:

1
2
3
4
int sysctl_tcp_bbr_lfn_loss_thresh_pct __read_mostly = 0;
int sysctl_tcp_bbr_lfn_min_rtt_fresh_ms __read_mostly = 5000;
EXPORT_SYMBOL(sysctl_tcp_bbr_lfn_loss_thresh_pct);
EXPORT_SYMBOL(sysctl_tcp_bbr_lfn_min_rtt_fresh_ms);

2. BBR 模块变更(net/ipv4/tcp_bbr.c)

bbr_is_inflight_too_high() 中加入动态阈值逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pct = READ_ONCE(sysctl_tcp_bbr_lfn_loss_thresh_pct);
if (pct > 0 &&
bbr->mode == BBR_PROBE_BW &&
bbr->cycle_idx != BBR_BW_PROBE_UP &&
bbr_min_rtt_is_fresh(bbr) &&
rs->rtt_us < (bbr->min_rtt_us * 6 / 5)) {

u32 roof = bbr_inflight_roof(sk);
if (rs->tx_in_flight > roof)
goto skip_relax;

eff_loss = max_t(u32, eff_loss,
((u32)pct * BBR_UNIT + 50) / 100);
}

3. 工程健壮性

  • Clang/LLVM 兼容:显式 unsigned long 转换
  • jiffies 回绕安全:使用 time_before()
  • 零开销:仅在发生丢包时读取 sysctl
  • 无残留风险:sysctl 注册在内核核心,非模块私有

AQM 兼容性:fq / fq_codel / CAKE

很多读者会担心:“放宽丢包阈值会不会把队列撑爆?”​
答案是:不会,因为补丁内置了三层 AQM 防护机制。

与 fq 的配合

  • pacing
    fq 提供硬件级 pacing,BBR 的 probe 节奏不受影响
  • 隔离
    每流独立队列,单流激进不会导致全局拥塞
  • 建议值​:pct=5-7

与 fq_codel 的配合(最关键)

这是最容易出问题的组合,但补丁已针对性处理:

  • CoDel 丢包 ≠ 物理丢包
    fq_codel 在缓冲区满时会主动丢包,这会被 BBR 误判为拥塞。
  • Inflight Roof(1.15×BDP)​
    补丁强制:只有当 tx_in_flight ≤ 1.15 × BDP时才放宽阈值。
    如果已经在 1.15×BDP 以上还丢包,直接拒绝放宽,让 fq_codel 接管。
  • 建议值​pct = 5-7 lfn_min_rtt_fresh_ms = 3000

与 CAKE 的配合

CAKE 是智能 AQM,会主动管理延迟和带宽:

  • 延迟目标优先​
    CAKE 看到 inflight 过高会自动丢包,补丁的 roof 机制同样生效。
  • 带宽感知​
    diffserv4 模式下,BBR 的 LFN 优化不会影响其他流。
  • 建议值pct = 4-6 lfn_min_rtt_fresh_ms = 5000

一句话总结

补丁从不对抗 AQM,它只是在 AQM 允许的“安全区”内,允许 BBR 忽略背景物理噪声。

如何使用

1. 编译内核

详细参阅:实战:编译集成 LFN 补丁的 BBRv3 内核

2. 配置参数

写入 /etc/sysctl.d/99-bbr-lfn.conf

1
2
3
# BBR LFN: allow up to 10% loss in PROBE_BW if RTT<1.2x min_rtt & inflight<=1.15xBDP
net.ipv4.tcp_bbr_lfn_loss_thresh_pct = 10
net.ipv4.tcp_bbr_lfn_min_rtt_fresh_ms = 5000

应用: sysctl --system

3. 推荐值速查

场景推荐值
默认 / 数据中心0(关闭)
跨境 / 高 RTT5–7
卫星 / 极端 LFN10
实验环境2–20

预期效果

指标原版 BBRv3补丁后
跨境 3-5% 丢包吞吐❌ 受限✅ 满速
队列敏感性✅ 高✅ 不变
AQM(CAKE/fq_codel)✅ 友好✅ 友好
突发拥塞反应✅ 快⚠️ 略慢

注意事项

  • ⚠️ 不要在数据中心或低 RTT 链路上开启
  • ⚠️ 不要设置 pct > 20
  • ✅ 始终配合 inflight roof 使用(补丁已内置)
  • ✅ 建议先在边缘节点进行灰度测试

总结

这个补丁并没有推翻 BBR 的设计哲学,而是在长肥管道的灰色地带里,给它一把更聪明的尺子。

默认关闭,按需开启;条件苛刻,绝不滥用。

如果你也在跨境或卫星链路上被 BBR 的 2% 天花板困扰,不妨试试这个补丁。

补丁地址GitHub Link
适用内核Linux 6.13+(BBRv3 主线)
许可证:Dual BSD/GPL
Happy hacking 🚀