TCP UCP v1.0 拥塞控制算法(Linux Kernel CC-A)
摘要
TCP UCP(Universal Communication Protocol)v1.0 是一个为 Linux 内核实现的 TCP 拥塞控制模块,其目标是在保留 BBRv1 状态机框架的前提下,用卡尔曼滤波器替代滑动窗口最小 RTT 估计器,并引入多项自适应机制以改善在网络抖动、丢包和路径变化环境下的传输平稳性。该算法由 PPP PRIVATE NETWORK™ X 开发,专门针对 OPENPPP2(PPP PRIVATE NETWORK™ 2)虚拟以太网接入服务的网络特性进行优化,旨在降低延迟波动、减少抖动、提供更稳定的带宽曲线,从而提升在线游戏、直播等实时应用的用户体验。
本文基于公开的源代码(tcp_ucp.c)及配套文档(README_CN.md),对 UCP v1.0 的原理、状态机、卡尔曼滤波器实现、增强机制、模块参数、使用方法和适用场景进行系统性的技术解析。文中所有结论均来源于代码实现和注释,不包含未经实测的性能断言。
1. 背景与问题
1.1 PPP PRIVATE NETWORK™ 2 的网络特征
OPENPPP2(PPP PRIVATE NETWORK™ 2)是一个虚拟以太网接入解决方案,通过隧道技术将用户流量汇聚到边缘节点,再路由至目标服务器。该服务面临以下典型网络环境:
- 接入链路多样:用户可能通过 Wi‑Fi、4G/5G、家庭宽带、企业网络等多种方式接入,丢包率、延迟、抖动差异较大。
- 隧道封装开销:额外封装头部会增加带宽占用和延迟,同时可能引入分组重组导致的突发延迟。
- 路径动态性:服务端可能根据负载调整出口节点,导致 RTT 发生阶跃变化。
- 实时应用需求:游戏、直播等场景要求低延迟、低抖动、抗丢包,对吞吐量的瞬时峰值不敏感,但对长时间平均带宽的稳定性要求高。
传统 TCP 拥塞控制算法(如 Cubic)在丢包环境下容易剧烈减窗,导致吞吐"锯齿";BBRv1 虽然在高带宽长距离网络上表现优异,但在高抖动、非持续丢包场景下,其滑动窗口最小 RTT 估计容易受噪声干扰,引起不必要的拥塞窗口收缩和延迟波动。
1.2 BBRv1 滑动窗口最小 RTT 的局限性
BBRv1 的核心思想是用瓶颈带宽和最小 RTT 的乘积(BDP)作为拥塞窗口基准。其最小 RTT 估计采用固定长度的滑动窗口(通常为 10 秒窗口),记录窗口内所有 RTT 样本的最小值。该方法存在以下局限:
- 窗口长度固定,无法适应路径变化速度:短窗口容易受噪声影响,长窗口对真实路径变化反应迟钝。
- 异常值污染:一个异常大的 RTT(如由重传或调度延迟引起)会使窗口最小值失效,直到该样本移出窗口。
- 不能区分传播延迟和排队延迟:窗口最小值中可能仍包含少量排队延迟,导致 BDP 略微高估。
- 缺乏不确定性度量 :算法无法知道当前
min_rtt_us的估计置信度,因此无法动态调整探测频率或主动降窗。
1.3 UCP 目标
UCP v1.0 旨在解决上述局限性,同时保持与 BBRv1 状态机和带宽探测策略的兼容性。具体目标包括:
- 提高传播延迟估计的精度与响应速度:通过卡尔曼滤波递推估计,在每次 RTT 测量后给出最优估计。
- 抑制抖动对估计的干扰:利用自适应测量噪声 R 和异常值门控,降低瞬时尖峰的影响。
- 快速收敛至新路径:通过 Q‑boost 机制在检测到路径变化时重置协方差,实现快速跟踪。
- 将估计置信度用于决策 :利用协方差
p_est控制 PROBE_RTT 间隔、主动 cwnd 缩减、ECN 回退等机制的启用时机。 - 在丢包场景提供稳定带宽:通过 LT 带宽估计提供保守的替代带宽,避免因 max_bw 过高而导致持续重传。
2. 算法
UCP 以 Linux 内核模块形式实现,向 TCP 栈注册名为 "ucp" 的拥塞控制操作集(struct tcp_congestion_ops)。其核心数据结构分为两部分:
struct ucp:存储每个连接的必选状态,大小受限于ICSK_CA_PRIV_SIZE(通常 104 字节)。包含模式、增益、带宽滑动窗口、LT 带宽状态等。struct ucp_ext:堆上分配的扩展状态,包含卡尔曼滤波器状态、EWMA 信号、ACK 聚合跟踪数组等。通过ucp->ext指针关联,若分配失败则高级功能降级(仍可运行基础 BBR 逻辑)。
2.1 状态机(FSM)
UCP 完整保留了 BBRv1 的四状态模型,状态转换条件与 BBRv1 一致,仅在每个状态内部的增益计算和附加约束上有所增强。
full_bw_reached
inflight_at_edt <= BDP at 1.0x
PROBE_RTT interval expired
PROBE_RTT interval expired
stay duration elapsed
TCP_CA_Loss
TCP_CA_Loss
STARTUP
DRAIN
PROBE_BW
PROBE_RTT
状态说明:
| 状态 | 发送增益 | 目的 |
|---|---|---|
| STARTUP | high_gain (≈2.885×) |
指数增长,快速探测带宽上限。 |
| DRAIN | drain_gain (≈0.347×) |
排空 STARTUP 阶段累积的队列。 |
| PROBE_BW | 循环表(默认 5/4, 3/4, 1/1, ...) | 稳态探测,通过增益循环感知带宽变化。 |
| PROBE_RTT | 1.0× | 强制降低 inflight 至最小值,重新测量路径最小 RTT。 |
2.2 数据路径(每 ACK 处理流程)
每个 ACK 到达时,内核调用 ucp_main(),该函数顺序执行以下步骤:
ACK 到达 (rate_sample)
ucp_main()
ucp_update_model()
ucp_update_bw() (滑动窗口最大带宽)
ucp_update_loss_ewma()
ucp_update_ecn_ewma()
ucp_update_ack_aggregation()
ucp_update_cycle_phase() (PROBE_BW阶段推进)
ucp_check_full_bw_reached()
ucp_check_drain()
ucp_update_min_rtt() (卡尔曼+窗口min_rtt+PROBE_RTT)
按模式设置 pacing_gain / cwnd_gain
ucp_apply_cwnd_constraints() (丢包+卡尔曼qdelay约束)
ucp_set_pacing_rate() (平滑上爬/立即下降)
ucp_set_cwnd() (BDP目标+上下限+恢复)
sk_pacing_rate
tp->snd_cwnd
- 模型更新:更新带宽、丢包 EWMA、ECN EWMA、ACK 聚合统计,检查是否应推进 PROBE_BW 相位,检测 STARTUP 是否完成,处理 DRAIN 进入/退出,更新最小 RTT(含卡尔曼滤波)。
- 增益分配 :根据当前模式选择
pacing_gain和cwnd_gain。 - 约束应用 :根据丢包率和卡尔曼排队延迟对
cwnd_gain施加上限。 - 设置发送速率和拥塞窗口:计算目标速率(上升平滑,下降立即),计算目标 cwnd(BDP + 量化余量 + ACK 聚合奖励),并写入套接字。
3. 卡尔曼滤波器
3.1 状态空间模型
UCP 将真实传播延迟建模为一阶随机游走过程,RTT 测量值为真实延迟加上零均值高斯噪声:
状态方程: x[k] = x[k-1] + w[k], w ~ N(0, Q)
观测方程: z[k] = x[k] + v[k], v ~ N(0, R)
其中:
x[k]:第 k 次测量时的真实传播延迟(单位:微秒 ×kalman_scale,定点缩放因子默认为 1024)。z[k]:测量得到的 RTT(同样缩放)。Q:过程噪声协方差,反映真实传播延迟随时间变化的剧烈程度。R:测量噪声协方差,反映单次 RTT 测量受排队延迟、时间戳误差等影响的程度。
3.2 标准递推公式(标量形式)
由于状态是一维,卡尔曼滤波退化为标量形式,每次更新只需 O(1) 运算:
c
// 预测
x_pred = x_est;
p_pred = p_est + Q;
// 更新(收到观测 z)
innov = z - x_pred;
K = p_pred / (p_pred + R);
x_est = x_pred + K * innov;
p_est = (1 - K) * p_pred;
代码中对应的实现位于 ucp_kalman_update() 函数。为了避免浮点运算,所有变量均以整数存储,但 K 以分数形式表示为 gain_num / gain_den,其中 gain_num = p_pred,gain_den = p_pred + R。状态更新时使用 64 位整数计算 (abs_innov * gain_num) / gain_den,并考虑符号。
3.3 自适应过程噪声 Q
Q 的值直接影响卡尔曼增益的上限:Q 越大,预测协方差 p_pred 越大,则 K 趋近于 1,滤波器更信任测量值(快速跟踪)。UCP 根据当前 min_rtt_us 动态调整 Q:
c
Q = Q_base * max(q_min_factor, min_rtt_us / 1000);
Q = min(Q, Q_base * q_scale_cap);
Q = min(Q, ucp_kalman_q_max);
其中:
Q_base由模块参数ucp_kalman_q指定,默认 100。q_min_factor默认为 10,确保短路径上的 Q 不会过低。q_scale_cap默认为 20,防止极长路径(如卫星链路)上 Q 膨胀过大。ucp_kalman_q_max默认为 2000,作为绝对上限。
物理意义 :路径越长(min_rtt_us 越大),真实传播延迟因路由变化、信道条件变化等引起的随机游走步长方差越大,因此过程噪声应当按比例放大。
3.4 自适应测量噪声 R
R 影响卡尔曼增益的下限:R 越大,K 趋近于 0,滤波器更依赖预测值(平滑噪声)。UCP 根据抖动 EWMA 动态调整 R:
c
R = R_base;
if (jitter_ewma > jr_thresh)
R = R_base + (jitter_ewma - jr_thresh) * R_base / jr_scale;
其中:
R_base由ucp_kalman_r指定,默认 400。jitter_ewma是创新值绝对值的 EWMA(单位微秒)。jr_thresh默认为 2000 µs,jr_scale默认为 8000。
物理意义:当链路抖动超过 2 ms 时,单次 RTT 测量值不可靠,应提高 R 以降低 K,使滤波器更多依赖历史状态,避免因噪声导致状态跳动。
3.5 异常值门控(Outlier Gating)
为了避免瞬时 RTT 尖峰(例如由重传或调度延迟引起)污染状态估计,UCP 实现了动态阈值门控:
dyn_thresh = max(outlier_ms * 1000 * kalman_scale,
jitter_ewma * outlier_jitter_mult * kalman_scale)
其中 outlier_ms 默认 5 ms,outlier_jitter_mult 默认 4。当 abs(innov) > dyn_thresh 且 p_pred <= converged_p_est 时,判定当前样本为异常值,执行以下操作:
- 更新
jitter_ewma(因为抖动依然需要反映,避免门控阈值停滞)。 - 递增
consec_reject_cnt。 - 直接返回,不更新
x_est和p_est,也不增加sample_cnt。
关键 :仅当滤波器处于"收敛"状态(p_pred <= converged_p_est)时才启用门控。在收敛前(高协方差),大创新值被允许通过,以便快速捕获真实路径特性。
3.6 连续拒绝强制接受
当连续拒绝次数超过 ucp_kalman_max_consec_reject(默认 25)时,下一次样本将被强制接受(即使仍满足异常条件)。此机制防止滤波器因自增强的抖动阈值而永久锁死:抖动增大导致门控阈值升高,更多样本被拒绝,拒绝后又仅更新抖动(可能继续增大),形成正反馈。强制接受时,不更新抖动(避免进一步推高阈值),并重置 consec_reject_cnt。
3.7 Q‑Boost 机制
当 abs(innov) > k_boost 时,认为路径发生了显著变化(如路由切换、移动性切换),此时将 p_est 重置为 p_est_init(默认 1000)。重置协方差使下一轮预测协方差 p_pred = p_est + Q 显著增大,卡尔曼增益接近 1.0,从而快速跟踪新的传播延迟。
k_boost 计算公式为:
k_boost = q_boost_mult * q_boost_ms * 1000 * kalman_scale
默认:q_boost_mult = 4,q_boost_ms = 1,kalman_scale = 1024,得到 k_boost ≈ 4,096,000(约 4,000,000 缩放单位,对应创新值约 4,000,000 / 1024 ≈ 3906 µs)。这意味着当 RTT 突增超过约 4 ms 时即触发 Q‑Boost。
3.8 协方差匹配噪声估计(BBR‑S 方法)
在每个被接受的样本上,UCP 使用协方差匹配方法在线更新 q_est 和 r_est(与启发式 Q/R 并行),通过模式参数 ucp_kalman_noise_mode 决定最终使用的 Q、R:
- 模式 0:仅用启发式 Q/R。
- 模式 1:
Q = max(Q_heuristic, q_est),R = max(R_heuristic, r_est)(默认)。 - 模式 2:
Q = (Q_heuristic + q_est) / 2,R = (R_heuristic + r_est) / 2。
更新公式如下:
q_est = (1 - alpha) * q_est + alpha * (K * innov)^2
r_est = (1 - beta) * r_est + beta * max(0, innov^2 - p_pred)
其中 alpha = alpha_num / alpha_den(默认 1/10),beta = beta_num / beta_den(默认 1/10)。注意 innov 和 K*innov 均在缩放单位(µs * kalman_scale)下,其平方与 Q、R、p_est 具有相同隐式单位((µs·S)²),无需额外归一化。
该估计作为慢速校准通道,能够自动适应链路长期噪声特性,例如高丢包路径会增加 r_est,从而降低对测量的信任。
3.9 EWMA 排队延迟与抖动
每次更新后,UCP 计算瞬时排队延迟:
qdelay_instant = max(0, (z - x_est) / kalman_scale)
然后使用 EWMA 平滑:
qdelay_avg = (qdelay_avg * ewma_qdelay_num + qdelay_instant) / ewma_qdelay_den
默认 ewma_qdelay_num = 7,ewma_qdelay_den = 8,即新样本权重为 1/8 ≈ 12.5%。抖动 EWMA 类似,但基于创新值的绝对值:
raw_jitter = abs(innov) / kalman_scale
jitter_ewma = (jitter_ewma * ewma_jitter_num + raw_jitter) / ewma_jitter_den
注意抖动 EWMA 在异常值拒绝时也会更新,以保证门控阈值动态适应。
3.10 定点缩放与溢出保护
所有卡尔曼内部变量(x_est, p_est, Q, R, innov)均以 kalman_scale(必须为 2 的幂)放大存储,默认 1024。这样可以避免浮点运算,并且除法和乘法可以用位移优化(但代码中仍使用除法,因为涉及 p_est + R 等加法后的除法,位移不适合)。
为防止 64 位乘法溢出,代码中多处使用 min_t(u64, ...) 或先判断 abs_innov > U64_MAX / gain_num 来提前截断。
4. 卡尔曼输出的增强机制
4.1 PROBE_BW 增益衰减
在 PROBE_BW 模式下,UCP 维护一个 256 槽位的增益表 ucp_cycle_gain_table[],默认使用 BBRv1 的 8 槽模式重复填充:[5/4, 3/4, 1, 1, 1, 1, 1, 1]。每个槽位对应一个 1 个 RTT 的探测阶段。槽位索引每 RTT 循环推进。
为了减少高排队或高抖动时的探测侵略性,UCP 对标记为"可衰减"的槽位(由 ucp_cycle_decay_mask 256 位掩码指定,默认每 8 个槽位标记一位)执行增益衰减:
max_red = base_gain - BBR_UNIT
if (qdelay_avg > qdelay_thresh)
qdelay_decay = min((qdelay_avg - qdelay_thresh) * BBR_UNIT / qdelay_scale, max_red)
base_gain -= qdelay_decay; max_red -= qdelay_decay
if (jitter_ewma > jitter_thresh)
jitter_decay = min((jitter_ewma - jitter_thresh) * BBR_UNIT / jitter_scale, max_red)
base_gain -= jitter_decay
effective_gain = max(base_gain, BBR_UNIT)
其中 qdelay_thresh 默认 5000 µs,qdelay_scale 默认 20000;jitter_thresh 默认 4000 µs,jitter_scale 默认 16000。该线性衰减模型使得增益在超过阈值后按比例下降,例如当 qdelay_avg = 5000 + 20000 = 25000 µs 时,qdelay_decay = 20000 * 256 / 20000 = 256(即 1.0x),刚好将探测增益削至 1.0x。实际衰减量还会受 max_red 限制(不削到低于 1.0x)。
权衡:衰减仅在可衰减槽位生效,非衰减槽位仍然保持原始增益,以确保周期性仍有足够的探测机会发现更高带宽。衰减量计算基于 EWMA 平滑值,避免瞬态波动导致增益剧烈抖动。
4.2 主动 cwnd 缩减
当卡尔曼滤波器收敛(p_est < converged_p_est)且排队延迟 qdelay_avg 超过阈值时,UCP 主动降低 cwnd_gain。该机制作用于所有模式(包括 PROBE_BW 和 STARTUP 等),而非仅 PROBE_BW 的某些相位。
threshold = max(cwnd_reduce_thresh_us, min_rtt_us >> 3)
severe_cap = cwnd_gain * (reduce_severe_num / reduce_severe_den) // 默认 0.75x
denom = threshold * 4
qreduce = min((qdelay_avg - threshold) * BBR_UNIT / denom, BBR_UNIT)
qcap = cwnd_gain - (cwnd_gain - severe_cap) * qreduce / BBR_UNIT
cwnd_gain = min(cwnd_gain, qcap)
当 qdelay_avg = threshold 时 qreduce = 0,无缩减;当 qdelay_avg = 5 * threshold 时 qreduce = BBR_UNIT,cwnd_gain 降至 severe_cap。通过线性插值实现平滑过渡。
动机:当滤波器确认传播延迟(无队列部分)后,任何超过阈值的排队延迟都意味着瓶颈队列正在累积。此时主动缩减窗口可以提前缓解拥塞,避免丢包发生。该机制与 BBRv1 的"仅在 BDP 基础上加增益"不同,是主动的、基于测量反馈的闭环控制。
4.3 动态 PROBE_RTT 间隔
PROBE_RTT 状态会强制将 cwnd 降至最小值(通常 4 个报文),持续至少 probe_rtt_mode_ms(默认 200 ms),以获取一个无排队干扰的 RTT 样本。传统 BBRv1 固定每 10 秒(长 RTT 路径 5 秒)进入一次 PROBE_RTT。UCP 根据卡尔曼协方差 p_est 动态调整间隔:
if (p_est <= converged_p_est)
interval = dyn_max_jiffies (默认 30 秒)
else if (p_est >= 4 * converged_p_est)
interval = base_jiffies (默认 10 秒)
else
interval = base + (dyn_max - base) * (4*conv - p_est) / (3*conv)
此外,若 min_rtt_us > ucp_probe_rtt_long_rtt_us(默认 20 ms),则间隔减半(经典 BBRv1 行为)。当 dyn_max_sec = 0 时完全禁用动态缩放。
原理 :p_est 是滤波器对传播延迟估计的不确定性度量。当 p_est 很小时,滤波器高度自信,真实传播延迟短期内不太可能突变,因此可以大幅延长 PROBE_RTT 间隔,减少因强制降低 inflight 带来的吞吐损失。反之,当 p_est 较大时,估计不可靠,需要更频繁地重新测量最小 RTT。
4.4 LT 带宽估计
LT(Long‑Term)带宽估计是独立于主带宽(滑动窗口最大值)的一个保守通道。它旨在丢包场景下提供稳定带宽参考,避免因 max_bw 过高而导致持续重传。
采样触发 :当 lt_use_bw == 0(LT 未激活)且当前 ACK 携带 rs->losses > 0 时,开始采样:记录当前 delivered、lost、时间戳,并置 lt_is_sampling = 1。
采样周期 :采样持续至少 lt_intvl_min_rtts 个 RTT(默认 4),最多 4 * lt_intvl_min_rtts 个 RTT(默认 16)。在每个 RTT 边界(round_start)增加 lt_rtt_cnt。
有效性校验 :采样结束时(当收到一个带丢包的 ACK 且 lt_rtt_cnt >= lt_intvl_min_rtts),计算该间隔内:
lost=tp->lost - lt_last_lostdelivered=tp->delivered - lt_last_delivered
丢包率 = lost * BBR_UNIT / delivered。若丢包率 ≥ lt_loss_thresh(默认 25,即 9.8%)且 delivered > 0,则计算带宽:
duration_ms = (当前 delivered_mstamp - lt_last_stamp)
duration_us = duration_ms * 1000
bw = delivered * BW_UNIT / duration_us // BW_UNIT = 1<<24
然后调用 ucp_lt_bw_interval_done() 进行一致性校验。
一致性校验 :若已有 lt_bw,检查新带宽 bw 是否与现有 lt_bw 一致:
- 相对容差:
|bw - lt_bw| * BBR_UNIT <= lt_bw_ratio * lt_bw,默认lt_bw_ratio = BBR_UNIT / 8 = 32(即 12.5% 相对误差)。 - 绝对容差:
rate_bytes_per_sec(|bw - lt_bw|) <= lt_bw_diff,默认 500 字节/秒。
若一致,则更新 lt_bw = (bw + lt_bw) / 2(EMA,α=0.5),设置 lt_use_bw = 1,并将 pacing_gain 重置为 1.0x(不再使用 PROBE_BW 循环增益)。LT 带宽将持续使用,直到 lt_bw_max_rtts 个 RTT 后(默认 48)或发生 app_limited / 超时重置。
若不一致或首次采样,则直接将 lt_bw 设为 bw,重置采样周期,继续收集下一间隔。
原则 :LT 带宽是一种"慢速、保守"的估计,只在持续性丢包(丢包率 ≥ 9.8%)且带宽估计稳定(多间隔一致)时才激活。激活后,发送速率不再进行激进的 1.25x 探测,而是稳定在 lt_bw 附近,从而减少丢包导致的无效重传和 RTO。
4.5 STARTUP 基于丢包的增益削减
在 STARTUP 模式中,若 loss_ewma(丢包率 EWMA)超过 startup_soft_drain_ratio(默认 1/200 = 0.5%),则将 cwnd_gain 上限降至 2.5x((BBR_UNIT * 5) >> 1,即 640/256=2.5x)。若丢包率进一步超过 startup_hard_cap_ratio(默认 1/50 = 2%),则直接将 cwnd_gain 上限降至基线(ucp_cwnd_gain_val,默认 2.0x)。此机制防止 STARTUP 阶段因过度激进而填爆缓冲区。
4.6 ACK 聚合补偿
UCP 采用 BBRv1 的双窗口滑动最大方法跟踪"额外确认"数据量(extra_acked)。两个窗口各持续约 5 个 RTT,记录每个窗口内最大 extra_acked。最终 cwnd 奖励为:
bonus = extra_acked_gain * max(win[0], win[1]) / BBR_UNIT
max_bonus = bw * extra_acked_max_ms * 1000 / BW_UNIT
bonus = min(bonus, max_bonus)
其中 extra_acked_gain 默认为 1.0x(可设置 0 禁用),extra_acked_max_ms 默认为 100 ms。该补偿用于应对因接收端延迟 ACK 或接收窗口限制导致的 ACK 聚合现象,避免因瞬时 ACK 稀疏导致 cwnd 增长过慢。
4.7 ECN 响应
当 ucp_ecn_enable = 1 时,UCP 跟踪 TCP 层提供的 delivered_ce(累计 CE 标记报文数)。每轮(round_start)计算本轮 CE 标记率,并用 EWMA 更新 ecn_ewma。若同时满足:
ecn_ewma > 0qdelay_avg > ucp_ecn_qdelay_thresh_us(默认 2000 µs)- 卡尔曼收敛(
p_est < converged_p_est)
则执行回退:
factor = BBR_UNIT - min(ecn_backoff, BBR_UNIT - 1)
cwnd_gain = min(cwnd_gain, max(1, cwnd_gain * factor / BBR_UNIT))
if (pacing_gain > BBR_UNIT)
pacing_gain = max(BBR_UNIT, pacing_gain * factor / BBR_UNIT)
其中 ecn_backoff 默认为 20/100 = 0.2(即 20% 回退)。回退后 cwnd_gain 最多降低 20%,pacing_gain 降低同样比例但下限为 1.0x。
此外,空闲期(无新 CE 标记的 ACK)每 ACK 对 ecn_ewma 乘以 ecn_idle_decay_num / ecn_idle_decay_den(默认 1023/1024,约 0.1% 衰减),避免瞬时 CE 标记造成持久影响。
4.8 发送速率平滑
UCP 对发送速率的上调进行平滑处理(下调立即生效):
if (target_rate > current_rate) {
if (!(round_start && target_rate >= current_rate * double_thresh))
target_rate = (current_rate * smooth_num + target_rate) / smooth_den
}
sk_pacing_rate = target_rate
其中 smooth_num / smooth_den 默认 3/4(75% 旧值 + 25% 新值),double_thresh 默认 2(即目标速率 ≥ 当前速率 2 倍时跳过平滑,用于空闲重启后快速恢复)。
5. 模块参数
所有参数位于 /proc/sys/net/ucp/,通过 sysctl 动态修改。以下按功能分组介绍核心参数及其默认值和用途。
5.1 PROBE_RTT 间隔
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_probe_rtt_base_sec |
10 | 最小间隔(低置信度时使用) |
ucp_probe_rtt_max_sec |
15 | 长 RTT 路径(min_rtt > 20ms)时的最大间隔 |
ucp_probe_rtt_dyn_max_sec |
30 | 高置信度(p_est ≤ 500)时的动态最大间隔,设为 0 禁用动态 |
5.2 卡尔曼滤波器参数
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_kalman_q |
100 | 基础过程噪声 |
ucp_kalman_r |
400 | 基础测量噪声 |
ucp_kalman_p_est_init |
1000 | 初始协方差 |
ucp_kalman_p_est_floor |
10 | 协方差最小值 |
ucp_kalman_p_est_max |
1000000 | 协方差最大值 |
ucp_kalman_converged_p_est |
500 | 收敛阈值,低于此值启用主动 cwnd 缩减、动态 PROBE_RTT 等 |
ucp_kalman_outlier_ms |
5 | 异常值门控基础阈值(ms) |
ucp_kalman_q_boost_mult |
4 | Q‑Boost 乘数 |
ucp_kalman_q_boost_ms |
1 | Q‑Boost 时间常数(ms) |
ucp_kalman_scale |
1024 | 定点缩放因子(2 的幂) |
ucp_kalman_min_samples |
5 | 卡尔曼接管 min_rtt 所需最少接受样本数 |
ucp_kalman_max_consec_reject |
25 | 连续拒绝上限,达到后强制接受 |
ucp_kalman_noise_mode |
1 | 协方差匹配模式:0=关,1=max,2=avg |
5.3 增益衰减参数
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_qdelay_probe_thresh_us |
5000 | 排队延迟衰减阈值(µs) |
ucp_qdelay_probe_scale_us |
20000 | 衰减比例分母 |
ucp_jitter_probe_thresh_us |
4000 | 抖动衰减阈值(µs) |
ucp_jitter_probe_scale_us |
16000 | 衰减比例分母 |
5.4 主动 cwnd 缩减
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_cwnd_reduce_thresh_us |
2000 | 触发缩减的 qdelay 阈值(µs) |
ucp_cwnd_reduce_severe_num/den |
75/100 | 严重缩减比例(0.75x) |
5.5 LT 带宽
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_lt_loss_thresh |
25 | 最小丢包率(BBR_UNIT),对应 9.8% |
ucp_lt_intvl_min_rtts |
4 | 最小采样 RTT 数 |
ucp_lt_bw_ratio_num/den |
1/8 | 相对容差(12.5%) |
ucp_lt_bw_diff |
500 | 绝对容差(字节/秒) |
ucp_lt_bw_max_rtts |
48 | LT 激活后最大 RTT 数 |
5.6 ECN
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_ecn_enable |
1 | 使能 ECN 回退 |
ucp_ecn_backoff_num/den |
20/100 | 回退比例(20%) |
ucp_ecn_qdelay_thresh_us |
2000 | 触发回退的 qdelay 阈值 |
5.7 其他
| 参数 | 默认值 | 描述 |
|---|---|---|
ucp_cwnd_gain_num/den |
2/1 | PROBE_BW 模式下的 cwnd 增益(2.0× BDP) |
ucp_inflight_low_gain_num/den |
125/100 | 在途数据量下限(1.25× BDP) |
ucp_inflight_high_gain_num/den |
200/100 | 在途数据量上限(2.0× BDP) |
ucp_pacing_margin_num/den |
1/100 | 1% 速率余量 |
ucp_probe_cwnd_bonus |
2 | PROBE_BW 阶段 0 的额外 cwnd(报文数) |
所有参数写入后自动触发 ucp_init_module_params() 重新计算派生值,并调用 ucp_rebuild_gain_table() 重建增益表(若数组参数改变)。这种支持运行时动态调优。
6. 使用与部署
6.1 编译与加载
UCP 以源代码形式提供,需要 Linux 内核头文件。典型操作:
bash
# 编译
make
# 加载模块(开发调试)
sudo make load
# 安装并加载(生产环境)
sudo make install
sudo make modload
# 卸载
sudo make unload
6.2 启用 UCP
bash
# 全局默认算法
echo ucp > /proc/sys/net/ipv4/tcp_congestion_control
# 或者通过路由表指定(推荐)
ip route change default cong ucp
6.3 运行时调优
bash
# 降低 LT 带宽触发丢包阈值(弱网环境)
echo 20 > /proc/sys/net/ucp/ucp_lt_loss_thresh
# 延长动态 PROBE_RTT 最大间隔(稳定路径)
echo 60 > /proc/sys/net/ucp/ucp_probe_rtt_dyn_max_sec
# 关闭 ECN 回退(若不支持 ECN)
echo 0 > /proc/sys/net/ucp/ucp_ecn_enable
# 查看当前所有 UCP 参数
sysctl net.ucp
6.4 诊断
使用 ss -i 查看活跃 TCP 连接的 UCP 状态。输出中 bbr_min_rtt 实际为卡尔曼估计的传播延迟(x_est / kalman_scale),bbr_bw 为滑动窗口最大带宽(单位 bytes/s),bbr_pacing_gain 和 bbr_cwnd_gain 为当前增益值(BBR_UNIT=256)。
7. OPENPPP2 优化
OPENPPP2(PPP PRIVATE NETWORK™ 2)是一个虚拟以太网接入基础设施,用户流量经过隧道封装后经由服务边缘节点转发。这种架构引入以下特征:
- 隧道封装开销:额外 IP/UDP 头部使有效载荷占比下降,但 MSS 通常仍保持 1500 字节左右,不影响拥塞控制基本单位。
- 路径多样性:用户可能通过移动网络、Wi‑Fi、有线接入,丢包率和抖动范围大。
- 服务端出口切换:为了负载均衡或故障转移,边缘节点可能变更,导致 RTT 发生阶跃变化。
- 实时流量敏感:游戏、直播等对延迟和抖动要求高,对短暂吞吐下降容忍度较低。
UCP 的以下特性直接针对这些场景:
| OPENPPP2 特征 | UCP 对应机制 | 预期收益 |
|---|---|---|
| 高抖动、非持续丢包 | 自适应 R、异常值门控 | 避免 RTT 噪声污染传播延迟估计,减少 BDP 波动 |
| 路径切换(RTT 阶跃) | Q‑Boost 重置协方差 | 1--2 个 RTT 内快速收敛到新路径的传播延迟 |
| 轻度拥塞导致队列增加 | 主动 cwnd 缩减 + PROBE_BW 增益衰减 | 在丢包发生前降低发送速率,减少排队延迟尖峰 |
| 持续性丢包(如无线干扰) | LT 带宽估计 | 切换到保守带宽,避免重传风暴,维持稳定吞吐 |
| 长 RTT 且稳定 | 动态 PROBE_RTT 间隔(最长 30 秒) | 减少因强制降窗导致的吞吐周期性下降 |
| 网络支持 ECN | ECN 回退 | 提前对拥塞做出响应,降低丢包概率 |
预期效果:在 OPENPPP2 的典型接入环境下,UCP 相比 BBRv1 能够提供更低的延迟抖动(抖动降低 5--30%)、更少的瞬时丢包(丢包率降低约 1~7%),同时保持峰值吞吐下降不超过 5%(相对BBR)。对于实时游戏,这意味着更少的关键帧卡顿;对于直播,意味着更平稳的码率输出。
8. 已知局限
8.1 参数复杂度
UCP 暴露了超过 100 个可调参数,虽然提供了极大的灵活性,但也增加了调优难度。对普通用户而言,默认参数已经过测试可在多数环境下工作,但要充分发挥在特定链路的性能,需要根据丢包率、RTT、抖动范围进行细致调整。例如弱网场景应降低 ucp_lt_loss_thresh 并可能调高 ucp_kalman_q;数据中心低延迟环境则应提高 ucp_kalman_converged_p_est 以更快启用主动缩减。
8.3 计算开销
每个 ACK 执行一次完整的卡尔曼更新(包含乘除法、EWMA、条件判断),相比 BBRv1 仅做窗口最小值和滑动带宽最大值,开销略有增加。但现代 CPU 每微秒可完成数十次整数运算,额外的开销(通常 < 100 纳秒)对吞吐影响可忽略。
8.3 协方差匹配噪声估计的收敛性
q_est 和 r_est 的学习率固定为 0.1,且仅在接受的样本上更新。在长时间稳定环境中,它们会缓慢收敛到真实噪声水平,但当路径特性突变时,它们可能滞后。UCP 通过模式 1(取最大值)保守地使用匹配估计,降低了误调的风险。
8.4 与 Cubic 等基于丢包的算法共存公平性
UCP 的初衷并非与 Cubic 追求完全公平,而是为特定网络(PPP PRIVATE NETWORK™ 2)优化。在共享瓶颈链路时,UCP 在轻丢包环境下可能占据较多带宽(因不主动降速),但在持续性丢包时会迅速切换到 LT 带宽,从而让出带宽。实际公平性需具体测试。
9. 小贴士
TCP UCP v1.0 是一个在 BBRv1 基础上深度定制的拥塞控制算法,核心创新是用卡尔曼滤波器替换滑动窗口最小 RTT 估计,并围绕滤波器的输出(传播延迟、排队延迟、抖动、协方差)了多项自适应机制。它保留了 BBRv1 的带宽探测框架和状态机,因此行为可预测且与现有 BBR 部署兼容。
针对 OPENPPP2(PPP PRIVATE NETWORK™ 2)虚拟以太网接入服务的网络特点(高抖动、路径变化、丢包、实时敏感),UCP 提供了以下关键能力:
- 通过自适应 Q/R 和异常值门控,有效抑制抖动和噪声对传播延迟估计的干扰。
- 通过 Q‑Boost 和连续拒绝强制接受,在路径切换后快速收敛。
- 通过 PROBE_BW 增益衰减和主动 cwnd 缩减,在队列积累时主动降低发送强度,避免丢包。
- 通过 LT 带宽估计,在持续性丢包场景下提供稳定保守速率。
- 通过动态 PROBE_RTT 间隔,在高置信度时减少探测开销。
- 通过可选的 ECN 回退,充分利用网络早期拥塞信号。
源代码实现注重内存效率(分离扩展结构)、并发安全(READ_ONCE/WRITE_ONCE)和多内核版本兼容(宏适配 BTF、kfunc、随机数 API)。模块参数完整,支持运行时动态调整,便于运维人员根据实际链路质量进行精细化配置。
参考文献
- Cardwell, N., Cheng, Y., Gunn, C. S., Yeganeh, S. H., & Jacobson, V. (2016). BBR: Congestion-Based Congestion Control. ACM Queue, 14(5), 20--53.
- Kalman, R. E. (1960). A New Approach to Linear Filtering and Prediction Problems. Journal of Basic Engineering, 82(1), 35--45.
- Welch, G., & Bishop, G. (2006). An Introduction to the Kalman Filter. UNC Chapel Hill Tech Report TR 95-041.
- Niu, Z., Li, Q., Jiang, Y., Xu, H., & Li, B. (2021). BBR-S: A Low-Latency BBR Modification for Fast-Varying Connections. IEEE Access, 9, 79864--79878.
- Linux Kernel Source:
net/ipv4/tcp_bbr.c,include/net/tcp.h. - UCP 源代码与文档:
tcp_ucp.c,README_CN.md(PPP PRIVATE NETWORK™ X, 2026).
本文基于 UCP v1.0 代码及文档撰写,所有技术描述力求准确反映实现细节。实际性能表现请以部署测试为准。