Hotdry.
systems

OpenBSD PF 队列突破 4Gbps 限制:HFSC 调度器 64 位升级技术细节

解析 OpenBSD PF HFSC 队列调度器从 32 位向 64 位整数迁移的技术实现,说明如何解除约 4.29 Gbps 的隐式带宽上限。

随着 10G、25G 甚至 100G 网络接口在数据中心和高端企业环境中逐步普及,OpenBSD 防火墙在高速链路上的队列调度能力面临新的挑战。OpenBSD PF(Packet Filter)长期以来通过 pf.conf 中的 [queue](https://man.openbsd.org/pf.conf#QUEUEING) 规则支持 HFSC(Hierarchical Fair Service Curve)流量整形,然而内核中一项延续多年的 32 位整数限制,使得实际可配置的带宽上限被锁定在约 4.29 Gbps—— 这一数值恰好是 u_int32_t 能表示的最大值。当用户在 10G 或更高带宽的接口上配置 bandwidth 10G 时,PF 不会报错,而是静默回绕(wrap-around),产生不可预测的调度行为,导致队列整形失效。

问题根源:HFSC 服务曲线结构体的 32 位瓶颈

HFSC 调度器的核心数据结构 struct hfsc_sc(service curve)使用 32 位无符号整数存储带宽参数。在千兆网络时代,这一上限从未被触及;然而,随着高速网卡驱动逐步进入 OpenBSD 内核(ixembnx 等驱动已支持多队列 MSI/MSI-X 中断),10G 以上链路的实际流量开始突破该瓶颈。更为隐蔽的问题在于:当配置值超出 4.29 Gbps 时,PF 不会抛出任何诊断信息,而是将高位截断,导致实际生效的带宽值远低于预期。例如配置 bandwidth 10G 时,实际生效的可能是约 5.7 Gbps(10 Gbps 减去 4.29 Gbps 的倍数),这种静默错误极难排查。

同样受影响的还有 pftop(1) 监控工具。该工具在显示队列带宽统计时同样使用 32 位变量,超过 4 Gbps 的数值会被错误渲染,运维人员无法从监控数据中察觉真实的带宽上限是否被正确应用。

修复方案:64 位整数迁移与 pftop 显示修正

OpenBSD 开发者近期提交的内核补丁通过两项关键改动解决了上述问题。首先,将 struct hfsc_sc 中的带宽字段从 u_int32_t 扩展为 u_int64_t,从结构层面消除了 4.29 Gbps 的隐式上限。补丁还相应调整了内核中所有涉及带宽计算的宏与函数,确保 64 位运算在各类 CPU 架构上正确执行。由于 OpenBSD 内核本身已经完成了大量 SMP(对称多处理)优化工作,这一改动不会引入新的锁竞争问题 ——HFSC 调度器的内部锁粒度在前期优化中已经过审慎调整。

其次,补丁同步修复了 pftop(1) 中的显示 bug。该工具原本使用 32 位整数字段解析和格式化带宽值,导致超过 4 Gbps 的队列统计被错误截断。修正后,运维人员可以在 pftop 输出中准确看到 10G、25G、100G 队列的实际带宽配置与实时使用率,从而为容量规划和故障排查提供可靠数据。

面向工程实践的配置参数建议

升级至包含该补丁的 OpenBSD -current 或后续稳定版本后,运维人员可以放心使用 10G 及以上带宽配置。以下是针对不同链路规格的推荐队列参数,假设使用 FQ-CoDel 或 HFSC 调度器:

10G 对称链路(约 10 Gbps 实际带宽):

queue root_on_ix0 on ix0 flows 4096 bandwidth 9500M max 9500M qlimit 2048 default
queue latency parent root_on_ix0 bandwidth 500M prio 7
queue bulk parent root_on_ix0 bandwidth 7000M prio 1

25G 对称链路:

queue root_on_ix1 on ix1 flows 8192 bandwidth 24000M max 24000M qlimit 4096 default
queue latency parent root_on_ix1 bandwidth 1000M prio 7
queue bulk parent root_on_ix1 bandwidth 18000M prio 1

100G 链路(数据中心骨干):

queue root_on_ix2 on ix2 flows 16384 bandwidth 95000M max 95000M qlimit 8192 default
queue latency parent root_ix2 bandwidth 2000M prio 7
queue bulk parent root_ix2 bandwidth 75000M prio 1

上述配置中 bandwidth 值设为物理链路的约 90%–95%,目的是让本地的队列整形而非 ISP 或上游设备成为瓶颈,从而更好地控制延迟与抖动。flows 参数决定了调度器维护的流表规模,高速链路建议相应增大;qlimit 控制队列缓冲大小,在缓冲区膨胀(bufferbloat)敏感的场景下可适当降低。

值得注意的是,如果系统尚处于 CPU 瓶颈阶段(即在没有启用任何队列的情况下也无法跑满物理带宽),则应优先排查中断亲和性、MSI-X 队列数量、以及 net.bpf.bufsize 等系统级参数,而非直接增加队列层级。systat pfvmstat 1 是定位 CPU 是否成为瓶颈的有效工具。

验证手段与监控要点

部署新内核后,建议通过以下步骤验证 64 位带宽限制已被解除:

使用 ifconfig 确认网卡已启用多队列模式(如 ix0: flags=... mtu 9000 txqueuelen 1000),随后加载包含队列规则的 pf.conf,通过 pfctl -vs queue 检查各队列的生效带宽是否与配置一致。对于 10G 以上链路,pftop 的输出应能正确显示十位数甚至百位数的 Gbps 数值。若仍有问题,可检查内核补丁是否完整应用 ——dmesg 中应包含 "hfsc: using 64-bit bandwidth counters" 或类似的初始化信息。

在监控层面,推荐将 pfctl -vs queue 的输出纳入定期采集脚本,解析 bandwidth 字段与实时 pkts/bytes 计数器比对,以检测是否存在配置回绕或调度异常。结合 systat pf 中的状态表统计,可以有效评估队列调度对不同优先级流量的实际保障效果。

小结

OpenBSD PF 的 HFSC 调度器通过从 32 位向 64 位整数的关键迁移,解除了长期隐含的约 4.29 Gbps 带宽上限,使系统能够从容应对 10G、25G、100G 等高速网络环境。该补丁同时修正了 pftop 的显示问题,为运维监控提供了可靠的可视化手段。升级内核后,结合合理的队列层级设计(根队列带宽设为物理链路的 90%–95%)、适当规模的流表(flows)与缓冲区(qlimit)参数,以及基于 systat pfpftop 的持续监控,即可充分发挥高速链路的整形与调度能力。

资料来源:OpenBSD Journal(undeadly.org)2026 年 3 月 19 日报道《PF queues break the 4 Gbps barrier》,原始补丁发表于 openbsd-tech 邮件列表。

查看归档