标准的 Linux 网络协议栈使用由 sk_buff 结构包裹的包缓冲区,这些结构指向系统的主机内存页。多年来,这种以主机为中心的抽象已经足够使用。然而,大规模分布式计算和机器学习的兴起,使主机 CPU 内存复制成为了严重的架构瓶颈。
为了解决这一问题,内核最近引入了设备内存 TCP(Device Memory TCP,简称 devmem TCP)。它利用 dmabuf 架构,通过硬件报头分离(Header Splitting)技术,将接收到的数据包有效载荷(Payload)直接写入外设内存(如 GPU 显存)。通过切分协议报头以供标准主机 RAM 处理,同时将原始有效载荷通过 DMA 直接发送至设备,devmem TCP 既保护了主机内存带宽,又避免了 CPU 的复制开销。
然而,架构上的断层依然存在。高性能分布式应用通常依赖 InfiniBand 或 RoCE(基于融合乙太网的 RDMA)范式来进行直接内存访问。在容器化环境或缺乏裸机 RoCE ASIC 的配置中,开发者依赖于 Soft-RoCE(RXE)------一种将 RDMA 流量封装到标准 UDP/IP 帧中的软件仿真层。直到最近,仍没有任何底层连接机制能够让仿真的 RXE 实例直接与 dmabuf 内存提供程序进行交互。
在 Netdev 0x1A 会议上,开发者 Yanjun Zhu (朱彦军)展示了一个全新的技术框架,旨在填补这一空白。在题为《通过 Netkit 实现结合 RDMA(RXE) 的 Dmabuf/devmem》的演讲中,该方案跨网络命名空间(Network Namespace)构建了一个零拷贝数据通路,使标准的、未经修改的 RDMA 应用能够无缝利用基于设备内存的存储基础设施。
核心问题:RXE 与 Devmem 的冲突
阻碍 Soft-RoCE 利用 devmem TCP 的根本冲突,源于内核内部对内存页面的表征方式。Soft-RoCE 从根本上是围绕锁定并将传统用户空间虚拟区域映射到传统主机绑定的 struct page 引用而构建的。相反,devmem TCP 的有效载荷占据的是从外部设备内存提供程序分配的内存页池,这些页对标准主机 CPU 的内存例程通常是透明或不可访问的。
当应用在仿真的 RXE 网络上触发 RDMA 事务时,驱动程序会将命令包裹进传统的网络缓冲区。如果该缓冲区必须与非主机的 dmabuf 内存分配进行交互,传统的内核流水线就会崩溃:CPU 无法在不引入巨大 PCIe 通路惩罚或触发缺乏页面引用错误的前提下,直接读取或写入这些内存区域。因此,当时的挑战在于:如何创建一个高性能的软件控制面和硬件直接数据面,使标准 RDMA 用户空间工具能够驱动这些硬件隔离的设备内存队列,且无需重写物理网卡(NIC)驱动程序。
Netkit 作为架构桥梁
为了绕过容器虚拟乙太网(veth)设备的传统限制,Zhu Yanjun(朱彦军)的设计采用了 Netkit------一种现代的、经过 eBPF 优化的虚拟乙太网架构------作为核心互联组件。该框架建立了多层拓扑,将软件驱动的编排与硬件执行紧密结合:
============ 控制面 (软件层) ============
[ Pod / NetNS 0 (服务端) ] [ Pod / NetNS 1 (客户端) ]
rping server (应用) rping client (应用)
|| || (RDMA 流量)
rxe0 (Soft-RoCE) rxe1 (Soft-RoCE)
|| || (基于 Netkit)
netkit0 netkit1
|| ||
租借发送/接收队列 租借发送/接收队列
(BPF / 队列切分) (BPF / 队列切分)
\/ \/
============ 数据面 (硬件层) ============
NVIDIA 网卡 0 NVIDIA 网卡 1
dmabuf 提供程序 dmabuf 提供程序
(主机 RAM) (主机 RAM)
\________________________________/
点对点 DMA (P2P)
跨网卡零拷贝数据通路
在此架构中,控制面依赖于显式的硬件队列租借机制。控制代理将 eBPF 逻辑与队列切分功能结合,而不是去修改特定厂商的驱动结构。通过在物理接口层应用 ethtool n-tuple 流定向规则,底层网卡(例如 NVIDIA ConnectX-6)的特定硬件发送和接收队列被隔离,并直接租借给容器的 Netkit 端点(netkit0 和 netkit1)。
在数据面上,租借的路径原生绑定到 dmabuf 分配器。结合跨网卡边界的点对点 DMA(P2P),有效载荷在硬件层直接从设备内存传输到设备内存。通过将基于 Netkit 接口的 RXE 直接映射到这些专用的硬件资源,标准的 RDMA 流量获得了干净穿越 dmabuf 通路的能力。
为什么选择 Netkit 而非 Veth?
架构验证期间被提出的一个核心问题是:为什么标准的 veth 对(容器隔离的传统骨干)无法胜任此角色?其局限性深深根植于 veth 处理内存所有权和跨命名空间的方式:
-
缺乏硬件队列绑定能力 :标准
veth设备充当盲目的软件管道,在命名空间之间 shuffle 通用的网络缓冲区。它们完全缺乏将容器空间的虚拟接口直接锚定到特定租借物理硬件队列所需的内部驱动架构。 -
无法避免的内存复制 :将数据包通过传统的
veth边界传递,由于缓冲区被主机栈排队和处理,必然会引入无法避免的 CPU 内存复制开销。相比之下,Netkit 将dmabuf提供程序与 P2P DMA 执行相匹配,跨越虚拟接口边界实现了绝对的硬件级零拷贝数据通路,完全绕过了主机 RAM 复制。 -
原生 eBPF tcx 集成 :当通过 devmem 驱动 RDMA 有效载荷时,传统的基于套接字的跟踪工具会失效,因为 CPU 不会触碰有效载荷数据块。Netkit 原生暴露了高性能的
tcx/ingress和tcx/egresseBPF 钩子。这使得能够在接口上直接进行无侵入式的内联监控,绕过了传统跟踪点的高延迟开销。
通过 eBPF tcx 进行性能跟踪
为了在不降低系统性能的前提下保持对多吉比特(multi-gigabit)RDMA 流量的可观测性,该框架引入了一个挂载到 Netkit tcx 钩子上的内联 eBPF 数据包解析程序。
在以往,监控 Soft-RoCE 需要将重型 kprobes 挂载到诸如 rxe_xmit() 等函数上,这会在高负载下触发严重的上下文切换惩罚。tcx 方法通过在快速网络路径中直接检查数据帧、根据 ETH_P_IP 验证协议并过滤无关流量,解决了这个问题。
至关重要的是,该 eBPF 内核程序实现了一种零拷贝元数据提取策略。它不复制完整的物理帧,而是仅将第 3/4 层网络定义和专门的 RoCE 基础传输报头(BTH)片段读取到无锁环形缓冲区(BPF_MAP_TYPE_RINGBUF)中:
SEC("tc/ingress")
int rxe_tcx_monitor(struct __sk_buff *skb) {
struct roce_bth bth;
// 仅提取 RoCE 基础传输报头,跳过重型有效载荷
if (bpf_skb_load_bytes(skb, ETH_HLEN + IP_HLEN + UDP_HLEN, &bth, sizeof(bth)) < 0)
return BPF_OK;
// 将元数据输出到无锁环形缓冲区,供用户空间记录
bpf_ringbuf_output(&rxe_ringbuf, &bth, sizeof(bth), 0);
return BPF_OK;
}
一个用户空间跟踪守护进程(rxe_pkg_user_dump.c)不断轮询该环形缓冲区,执行内部操作码查找以对确切的 RDMA 操作(如 IB_OPCODE_RC_RDMA_WRITE_ONLY)进行分类,并将结构化元数据导出到标准 PCAP 文件中。这保持了足够低的内存压力,以满足实时可见性约束,同时不会挤爆用户空间边界。
概念验证 (PoC)
为了验证标准 RDMA 应用能否在 devmem 加速架构上无缝运行,该框架接受了使用标准 Linux 内核自测试工具(tools/testing/selftests/rdma)的评估。
配置首先通过 ethtool 在物理网络接口上启用硬件数据切分和 ntuple 流定向。首先在 Netkit 接口上执行了 ncdevmem 验证测试:在 10.00 GB 的接收流量传输量中,日志指标记录到了正好 100% 的 devmem 执行率,证实主机内存字节复制降到了绝对零。
在验证了底层 devmem 和 Netkit 基础之后,团队在 netkit0 上初始化了 rxe0,并在 netkit1 上初始化了 rxe1。跨网络命名空间运行标准的、未经修改的 rping 客户端-服务端应用获得了原生成功。该应用成功地将其有效载荷数据块直接通过硬件租借的设备内存分配进行发送和接收,无需对内部代码进行任何修改。
现场问答
在会议的问答环节中,该架构设计引发了内核网络专家和驱动维护者之间的深入技术讨论。
讨论的第一个焦点集中在加速数据路径期间对 IP 层的完全绕过。与会者质疑,如果发送流水线中消除了网络层,诸如邻居状态跟踪、ARP 解析和复杂路由查找等关键网络服务将如何维持。Zhu Yanjun (朱彦军) 澄清说,该框架依赖于明确的"快路径 / 慢路径"双重机制。连接握手阶段、邻居发现和传统的非 RDMA 流量继续通过慢路径走标准的 Linux IP 和邻居层。只有在 RDMA 连接被显式建立并标记为加速后,特定的有效载荷才会跳上 Netkit 快路径。这确保了与现有内核子系统逻辑的完全兼容。
现场还评估了该设计的长期依赖性,一位工程师询问该框架未来是否可以完全独立于 Netkit 运行------这也是演讲未来工作部分所暗示的里程碑。Zhu Yanjun (朱彦军)承认这项研究正在积极推进中。目前使用 Netkit 是将其作为易于使用的软件网络桥梁来建立核心编排,但长期愿景是将系统与其解耦。开发团队正在尝试利用 Qdisc(流量控制)子系统,或将 eBPF 钩子直接钉入驱动路径,从而将 Soft-RoCE 驱动直接与 dmabuf 分配器对齐,彻底剪掉虚拟化接口层。
然而,这一未来方向凸显了经典的架构权衡。Netkit 提供了一个优雅、高度隔离的沙盒,并带有非常适合容器编排的统一 tcx 钩子。完全绕过它去直接查看 Qdisc 条目或将 RXE 注入物理设备钩子,可能会抹平虚拟软件开销的最后几纳秒,但代价是失去 Netkit 非侵入式的可管理性和硬件无关的控制面。
最后,关于上游参与(Upstream)的必然问题被提了出来。Zhu Yanjun (朱彦军) 宣布,包含内核空间 eBPF 过滤机制、用户空间提取守护进程和自动化网络命名空间编排脚本的整个验证套件,已经托管在 GitHub 上。他承诺在会后立即将仓库链接直接发送到 Netdev 邮件列表,以启动社区测试和同行评审。
未来展望
目前的实现证明了 Netkit 可以成功充当链接 RXE 与 devmem 的中介。该项目的核心价值在于其方法论:它通过编排纯软件驱动和 eBPF 介导的通路,极大地优化了仿真的 RDMA 工作负载,同时无需将破坏性的修改强加给底层的物理厂商网络驱动程序。
虽然眼下的工作涉及巩固快路径兼容性以及完成代码库的社区评审,但路线图指向了更加直接的架构。将 RXE 完全下沉到网卡驱动层(NIC Driver Layer)以原生采用队列租借,将允许虚拟化的 RDMA 应用完全与网络栈解耦,使软件仿真一步步逼近裸机性能。
