EDT (原地盖戳排队) vs IFB(重定向到虚拟网卡:上下文切换)

8 阅读4分钟

从第一性原理出发,eBPF EDT (Earliest Departure Time) 的核心思想是将流量控制从**“基于空间的排队(Buffer-based)”转变为“基于时间的调度(Time-based)”**。

在传统的 HTBIFB 方案中,我们通过在内存中开辟一个“池子”(队列)来吸收突发流量;而在 EDT 模型中,内核不再关注包存放在哪,而是关注包何时准许发送

结论

eBPF EDT 通过在数据包(skb)上打一个**“离网时间戳”**来取代物理队列。它利用 eBPF 灵活的计算能力和内核 FQ (Fair Queue) 调度器的时钟控制,在不增加中间设备(如 IFB)、不引入上下文切换开销的情况下,实现了极其精准的流量整形(Shaping)。


1. EDT 的底层运作机制

EDT 的核心逻辑由两部分协同完成:一个 eBPF 程序 和一个 FQ Qdisc

A. 计算离网时间(BPF 逻辑)

每当一个数据包准备从网卡发出时,挂载在 tc egress 的 eBPF 程序会执行以下逻辑:

  1. 查询速率限制:从 BPF Map 中读取该容器/流对应的带宽限制(Rate)。

  2. 计算时间间隔:根据包的大小(Len),计算发送这个包理论上需要占用的时间。

    Δt=PacketSizeConfiguredRate\Delta t = \frac{PacketSize}{ConfiguredRate}

  3. 确定发送时间

    • 读取该流上一个包的“预定发送时间”(LastDepartureTime)。
    • 当前包的发送时间 = max(CurrentTime,LastDepartureTime)+Δt\max(CurrentTime, LastDepartureTime) + \Delta t
  4. 打戳:将这个计算出的时间直接写入 skb->tstamp 字段。

  5. 状态更新:将最新的发送时间更新回 BPF Map,供下一个包使用。

B. 强制执行(FQ Qdisc 逻辑)

skb 带着 tstamp 到达物理网卡的 FQ 队列时:

  • 如果 tstamp 是过去的时间,立即发送。
  • 如果 tstamp 是未来的时间,FQ 调度器会将包挂起,直到系统时钟达到该时间戳。

2. 为什么它能比 IFB 减少重传?(第一性原理分析)

IFB 虽然也有缓冲区,但它本质上还是一个“黑盒”:包进去了,满了就丢。而 EDT 是**“节奏控制器”(Pacing)**。

  1. 平滑发送节奏(Anti-Burst)

    传统的限速(Policing)在令牌桶满时会瞬间放行一堆包,空了则全部丢弃。EDT 强制每一个包之间必须有精准的 Δt\Delta t 间隔。对于 TCP 协议栈来说,它看到的不是丢包,而是稳定的、稍微变长的 RTT。这会诱导 TCP 的拥塞控制算法(如 BBR)自动进入一个平稳的发送状态,而不是反复进入“丢包-重传”的恶性循环。

  2. 零拷贝与无上下文切换

    IFB 需要将数据包从物理网卡 ingress 路径重定向(Redirect)到虚拟网卡的 egress 路径,这涉及到 CPU 在不同网络路径间的跳转。EDT 直接在原始 skb 上修改时间戳,数据包在内存中原地不动,直接由物理网卡的调度器处理。


3. EDT vs. IFB vs. Policing 深度对比

特性Policing (Drop)IFB + HTBeBPF + EDT (Cilium)
内核路径原地丢弃重定向到虚拟设备原地打戳
限速手段剪裁(Clip)排队(Buffer)节奏控制(Pace)
重传风险极高(信号剧烈)中(依赖队列长度)极低(信号平滑)
多核扩展性优秀差(全局锁竞争)极优(Per-CPU 状态)
资源消耗极低较高(内存+CPU切换)中(仅 BPF 计算开销)

4. 事实与实践:Cilium 的做法

作为 Kube-OVN 的维护者,你可能关注到 Cilium 在 1.6 版本后全面转向了 EDT 模式。

  • 实现细节:Cilium 在 BPF Map 中维护了 struct bandwidth 状态,记录了每个 Cgroup 或 IP 的 last_tstamp
  • 硬件卸载:由于 EDT 只是给包打上一个 tstamp,现代的高级网卡(如 Mellanox ConnectX 系列)甚至可以识别这个时间戳,直接在硬件层级进行 Pacing 发送,从而将 CPU 压力彻底卸载。

思考与推测

Kube-OVN 的背景下,目前基于 OVS 的流量控制更多依赖于 OVS 自带的 ingress_policing_rate(基于丢包)或 QoS 模块。如果 Kube-OVN 要实现类似的 EDT 效果,可能需要:

  1. 旁路掉 OVS 的默认限速,在 veth 宿主机端挂载 eBPF 逻辑。
  2. 确保物理网卡上配置了 FQ 作为根 Qdisc(这可能与现有的 OVS 队列策略冲突)。