3. 云原生网络数据平面基础

在 DPU 云原生网络加速工程中,理解 Linux 网络数据平面的收发包路径是后续一切优化的起点。无论是用 eBPF 卸载、用 TC 做流量整形,还是把 OVS 数据面下沉到 DPU,本质上都是在回答同一个问题:一个数据包从网卡进入系统,到最终被容器里的进程读到,中间经过了哪些环节,每个环节的开销在哪里,哪些环节可以被旁路或加速。

一、Linux 网络协议栈的收发包路径

先看接收方向。网卡收到报文后,通过 DMA 把数据写入预先分配的接收环形缓冲区(RX Ring),然后发起中断。为了降低高频小包场景下的中断开销,现代网卡普遍启用 NAPI 机制:中断处理函数只做少量工作,随后触发软中断(NET_RX_SOFTIRQ),由内核在轮询模式下批量从 RX Ring 取包。每个报文被包装成 sk_buff(简称 skb),这是贯穿整个协议栈的核心数据结构,记录了报文数据指针、协议头偏移、所属网络命名空间等信息。

skb 随后沿协议栈向上传递:链路层处理(如 VLAN 剥离、ARP 判断)→ 网络层 ip_rcv 做路由查找与 netfilter PREROUTING 钩子 → 判断是本地投递还是转发。若是本地投递,进入 ip_local_deliver,经过 netfilter INPUT 钩子,再交给传输层。TCP 在 tcp_v4_rcv 中完成连接查找、序号校验、乱序重组,把数据放入 socket 接收队列,最后唤醒阻塞在 recv() 上的应用进程,通过 copy_to_user 把数据拷贝到用户态。

发送方向基本对称:应用调用 send() 写入 socket 发送缓冲区,TCP 负责分段、拥塞控制与重传,IP 层做路由与分片判断,netfilter OUTPUT/POSTROUTING 钩子依次执行,最后进入 qdisc(排队规则)排队,由网卡驱动通过 TX Ring 发出。整个路径中,skb 的分配与释放、跨层函数调用、用户态与内核态之间的数据拷贝,是三个最主要的固定开销来源。

二、netfilter 与 TC:两个关键的钩子框架

netfilter 是内核协议栈内的包过滤与处理框架,它在收发包路径上埋了五个钩子点:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。iptables/nftables 就是基于这些钩子实现的。它的特点是工作在协议栈内部、能感知连接状态(conntrack),但代价是每个包都要走一遍规则链匹配,规则多时线性查找开销明显。

TC(Traffic Control)则位于更靠下的位置,直接挂在网络设备的收发队列上。它分为 ingress 和 egress 两个方向:egress 通过 qdisc 实现排队、整形、限速;ingress 则通过 clsact qdisc 挂载过滤器,可以在协议栈处理之前就对包做分类、丢弃或重定向。TC 的 eBPF 挂载点(tc ingress / tc egress)是当前云原生数据面最常用的加速入口之一,因为它比 netfilter 更早介入,且能直接操作 skb 甚至做 XDP 级别的重定向。

记忆要点:netfilter 偏“连接与策略”,TC 偏“队列与转发”。做加速时优先考虑 TC/XDP 挂载点,因为它们更靠近网卡,能更早决定包的命运。

三、OVS 与 eBPF:从内核模块到可编程数据面

OVS(Open vSwitch)是虚拟化与容器网络中广泛使用的虚拟交换机,传统实现由内核 datapath 模块加用户态 ovs-vswitchd 组成。第一个包走慢路径上送用户态查流表,后续命中流表的包走快路径直接在内核转发。它的优势是功能完整、支持 OpenFlow,但内核模块与用户态之间的交互、以及多级流表匹配,会带来额外延迟。

eBPF 提供了另一条路线:把转发逻辑编译成字节码,挂到 TC、XDP 或 socket 层,在内核中安全执行,无需修改内核源码、无需加载内核模块。在云原生场景中,Cilium 就是典型代表——它用 eBPF 替代了大量 iptables 规则和 OVS 流表,实现服务负载均衡、网络策略与可观测性。相比 OVS,eBPF 数据面路径更短、可编程性更强,但需要处理内核版本兼容与程序复杂度管理。

四、容器网络命名空间与 veth 对

容器网络隔离的基础是 network namespace。每个容器拥有独立的 netns,里面有自己的网卡、路由表、iptables 规则和端口空间。要让容器与外界通信,通常使用 veth 对:一对虚拟网卡,一端在容器 netns 内(如 eth0),另一端在宿主机 netns 内(如 veth1234)。从一端发出的包会立刻从另一端出现,相当于一根虚拟网线。

宿主机侧通常再把 veth 接入网桥(如 docker0、cni0)或 OVS 网桥,由网桥完成同主机内容器间转发;跨主机则依赖 VXLAN 等隧道封装。下面这张图把本节的核心对象串起来:从网卡到协议栈、netfilter/TC 钩子、OVS/eBPF 数据面,再到容器 netns 与 veth 对的位置关系。

物理网卡 RX/TX Ring · NAPI Linux 网络协议栈 链路层 VLAN / ARP / skb 构建 netfilter PREROUTING 路由判断 / conntrack 网络层 ip_rcv 本地投递 / 转发判断 netfilter INPUT iptables / nftables 规则 传输层 tcp_v4_rcv 连接查找 / 重组 / 入队 socket 接收队列 copy_to_user → 应用 TC / XDP clsact qdisc eBPF 挂载点 OVS 数据面 内核 datapath + ovs-vswitchd OpenFlow 流表 eBPF 数据面 TC / XDP 程序 Cilium / 自研 无内核模块 容器 netns eth0 容器内网卡 veth 对 虚拟网线 宿主机 veth1234 接入 转发/回注 数据包路径:网卡 → TC/XDP → 协议栈(netfilter 钩子)→ socket → 应用;容器侧经 veth 对接入 OVS/eBPF 数据面 加速思路:把转发决策前移到 TC/XDP 或 eBPF,减少协议栈与用户态交互开销

五、把路径串起来看加速机会

理解了上述结构,就能定位常见的加速点。第一,用 XDP 在驱动层直接处理包,绕过 skb 分配,适合 DDoS 清洗和简单转发。第二,用 TC eBPF 在 ingress/egress 做服务负载均衡和策略执行,替代大量 iptables 规则,避免规则链线性匹配。第三,用 eBPF 或 OVS 卸载把容器间转发从协议栈中拉出来,减少 netfilter 与路由查找开销。第四,在 DPU 上把这些数据面进一步下沉,让宿主机 CPU 专注于业务。

一个可参考的观察方法是:在宿主机上用 tc -s qdisc show dev eth0 查看队列统计,用 bpftool prog show 确认 eBPF 程序挂载点与运行次数,用 ovs-dpctl dump-flows 查看 OVS 快路径流表命中情况。若发现大量包走了慢路径或 iptables 规则命中数极高,就说明数据面还有下沉空间。这些命令的具体输出会随内核版本和配置不同而变化,实际使用时以本机结果为准。

注意:netfilter、TC、OVS、eBPF 四者并非互斥,实际生产环境常常叠加使用。做优化时要先确认当前包的完整路径,避免只优化了其中一段却让另一段成为新瓶颈。