做大模型 Infra 的人迟早会撞到「网络」这堵墙:千卡训练的 NCCL all-reduce、KV-cache 的 RDMA 直读、推理网关的百万 QPS……一旦标准内核协议栈不够用,就要在 XDP / DPDK / AF_XDP 这三条「绕过内核」的路径里做选择。本文把三者的原理、数据流、取舍一次性讲透。

一、为什么内核协议栈不够快

先建立基准:为什么需要绕过内核? 标准 Linux 网络栈(sk_buff + TCP/IP 协议栈 + socket)每收一个包要走的路:

1
2
网卡 RX → DMA 到内存 → 硬中断 → 软中断 NET_RX_SOFTIRQ → netif_receive_skb
→ sk_buff 分配/拷贝 → IP/TCP 协议栈处理 → socket 接收队列 → 用户态 read()

这套路径有四个「慢点」:

  1. 上下文切换:硬中断 → 软中断 → 内核态 → 用户态,每个包多次跨越特权级。
  2. sk_buff 分配/释放:每个包都 alloc_skb/kfree,这是热点里的内存分配抖动。
  3. 数据拷贝:内核缓冲区 → 用户态 buffer,至少一次 copy。
  4. 中断风暴:pps(packet per second)一高,中断处理本身成为瓶颈,CPU 全在处理中断没空算业务。

对几十万 pps 的普通服务无所谓;但 L4 负载均衡、DDoS 清洗、NFV 网元、高频量化行情这些千万级 pps 场景,内核栈就是天花板。于是有了三种「kernel bypass」思路:

路径 包在哪处理 绕内核方式 编程模型
XDP 内核态(驱动层) 在驱动收包后、协议栈之前 hook eBPF 程序
DPDK 用户态 完全旁路内核,UIO/VFIO 接管网卡 用户态 PMD 轮询
AF_XDP 用户态 XDP 把包重定向到用户态 socket XDP + umem 零拷贝

下面逐个拆。


二、XDP:在驱动层跑 eBPF 的「最快内核路径」

2.1 核心思想

XDP(eXpress Data Path)的洞察是:大部分包根本不需要走完整协议栈。一个 DDoS 攻击包、一个要丢弃的非法包,在驱动收完包之后、还没进 netif_receive_skb 之前就该被处理掉。

XDP 给你在网卡驱动收包后第一时间挂一个 eBPF 程序的钩子。这个程序拿到原始包(xdp_buff,连 sk_buff 都还没构造),可以决定包的 destiny:

1
2
3
4
5
6
// XDP 程序的返回码(verdict)
XDP_DROP // 直接丢,常用于 DDoS 防护
XDP_PASS // 放行进正常协议栈
XDP_TX // 从收到包的同一网卡原路发回
XDP_REDIRECT // 重定向到别处(另一个网卡 / CPU / AF_XDP socket)
XDP_ABORTED // 出错,丢弃

2.2 数据流

1
2
3
4
5
网卡 RX → DMA → 驱动收包 → 【XDP eBPF 钩子】 ← 在这里决策
├─ DROP → 直接释放,不进协议栈
├─ PASS → 构造 sk_buff,进协议栈(正常路径)
├─ TX → 驱动直接发回
└─ REDIRECT → 发往 AF_XDP socket / 另一网卡

关键点:XDP 钩子早于 sk_buff 分配,所以 DROP/REDIRECT 路径完全没有 skb 开销,这是它快的根因。而且 XDP 程序跑在软中断上下文里的 native 编译模式(JIT 成本机指令),不是解释执行,性能接近手写内核模块。

2.3 三种运行模式

  • Native XDP:eBPF 程序由驱动在 RX 路径直接调用,最快。需要驱动支持。
  • Offloaded XDP:eBPF 程序下放到网卡硬件(智能 NIC,如 Netronome)执行,CPU 零开销。
  • Generic XDPSKB_MODE):为了兼容老驱动,在 sk_buff 构造之后才调用 eBPF,慢一些,用于开发调试。

2.4 安全模型:eBPF verifier

XDP 程序进内核有 verifier 限制:不能有死循环、不能越界访问、必须能被静态证明会终止。这是 XDP 比 DPDK 安全但表达力弱的原因——DPDK 里你能跑任意 C 代码,XDP 里你只能跑 verifier 放心的 eBPF 字节码。

2.5 典型用法

  • DDoS 清洗 / 防火墙:百万 pps 级 drop,CPU 几乎不涨。
  • L4 负载均衡(如 Cilium、Katran):XDP_TX 把包改头后原路发回,做 L4 DSR。
  • AF_XDP 后端:见第四节。
  • 采样/监控:XDP 程序把包元数据送到 perf ring。

面试要点:XDP 是「在内核里、但早于协议栈」的 eBPF fast path。它没有绕过内核(依然在内核态、用内核驱动收包),只是把决策点前移到驱动层,省掉协议栈和 skb 开销。所以 XDP 的定位是「最快的、仍受内核管理的包处理路径」,不是 kernel bypass。


三、DPDK:完全旁路内核的用户态包处理

3.1 核心思想

DPDK(Data Plane Development Kit,Intel 起家,现 Linux Foundation)走得更彻底:既然内核是瓶颈,就完全不让内核碰网卡

机制:用 UIO / VFIO 驱动把网卡从内核标准驱动「解绑」并接管,网卡寄存器和 DMA 缓冲区直接映射到用户态进程地址空间。用户态进程用 PMD(Poll Mode Driver,轮询模式驱动) 不断轮询网卡 RX 环,收到的包直接在用户态处理,全程零内核参与、零中断、零上下文切换

3.2 数据流

1
2
3
4
5
6
7
网卡 ──(VFIO/UIO 接管)── 用户态进程

PMD 死循环 poll RX 环 ←── DMA 直接写到用户态 mmap 的大页内存

用户态业务逻辑(L4-L7)

PMD poll TX 环 → DMA 发出

整个收发包路径没有一次系统调用、没有一次中断、没有一次拷贝(DMA 直写用户态内存)。这就是 DPDK 拐点跑到千万 pps 的原因。

3.3 关键工程组件

  • Hugepages(大页内存):用 2MB/1GB 大页,减少 TLB miss,DPDK 的 mempool 全建在大页上。
  • Mempool:预分配的包缓冲池,避免运行时 malloc,恒定时间取放。
  • PMD(Poll Mode Driver):绑死一个 CPU 核 100% 轮询,不等中断。代价是该核 CPU 满载。
  • rte_ring(无锁队列):核间通信用无锁环形队列,避免锁竞争。
  • VFIO/VFIO-NOIOMMU / UIO:把设备暴露给用户态的方式。VFIO 带 IOMMU 保护,生产首选;UIO 简单但无保护。
  • Flow Bifurcation / RDMA 共存:DPDK 可以和内核栈分流量,部分包仍交给内核。

3.4 DPDK 的代价

  • 独占网卡:网卡被 VFIO 接管后,内核看不到它,标准 ifconfig/ssh 失效,得用 DPDK 自带工具(如 testpmddpdk 命令)。
  • CPU 100% 占用:PMD 轮询意味着即使没包也满载,所以 DPDK 需要专门的核,常配合容器隔离。
  • 无内核服务:路由表、conntrack、iptables 全用不了,要在用户态重写或用 DPDK 的 FIB/ACL 库。
  • 开发门槛高:要写 C,理解 PMD/rte_mbuf/mempool 那一套,还要懂 NUMA 绑核。

3.5 典型用法

  • NFV 网元:vRouter、vFW、vLB、vSwitch(OVS-DPDK 是经典组合)。
  • 电信 5G UPF:GTP 隧道转发,千万 pps。
  • 高性能 L4-L7:F5、NGINX 加速、高频行情网关。
  • 存储:SPDK(存储性能开发包)是 DPDK 思路搬到 NVMe 的姊妹项目。

面试要点:DPDK = 完全 kernel bypass + 用户态 PMD 轮询。它是三条路径里「最激进、最快、也最重」的:用独占网卡和满载 CPU 核换极致吞吐。表达力无限制(任意 C),但失去所有内核网络服务。


四、AF_XDP:XDP 与用户态的「中间道路」

4.1 定位:为什么要有 AF_XDP

XDP 快但只能跑在内核态、受 eBPF 限制(写不了复杂业务逻辑);DPDK 自由但太重(要独占网卡、要写 PMD、丢掉内核服务)。AF_XDP 就是这两者之间的桥

用 XDP 在驱动层把包 XDP_REDIRECT 到一个特殊的 socket(AF_XDP),让用户态进程在零拷贝下拿到原始包,但网卡仍由内核驱动管理、仍能跑正常协议栈

一句话:XDP 当「快速分流器」,用户态当「业务处理器」,两者之间用一块共享内存(umem)零拷贝传包。

4.2 数据流

1
2
3
4
5
6
7
网卡 RX → 驱动 → 【XDP eBPF】

└─ XDP_REDIRECT ─→ AF_XDP socket

umem(用户态 mmap 的共享环形缓冲区)

用户态进程 poll 拿包处理
  • umem:用户态进程申请的一块内存,同时映射给内核作为 DMA 目标。包 DMA 进来后,XDP 程序只改一个描述符指针,就让这块数据「归」用户态可见——零拷贝
  • FILL ring / COMPLETION ring:两对环形队列管理 umem 描述符的借用/归还。
  • 两种模式XDP_FLAGS_DRV_MODE(驱动 native,零拷贝,需驱动支持)、XDP_FLAGS_SKB_MODE(generic,有拷贝,兼容性好)。

4.3 编程模型

  • 内核侧:写一个 XDP eBPF 程序,逻辑通常就是「按 5 元组/端口过滤,符合的 bpf_redirect_map 到 xsks map」。
  • 用户侧:标准 socket API(socket(AF_XDP, SOCK_RAW)),配 libbpflibxdp,绑 umem,poll 收包。

libbpf + xdp-toolslibxdp)是现在主流组合。Cilium、Cloudflare 都在生产用 AF_XDP 做高 pps 入口。

4.4 UMEM、Fill Ring 与 Rx Ring:零拷贝的「循环快递柜」

要理解 AF_XDP 的零拷贝,绕不开三个东西:UMEM、Fill Ring、Rx Ring。它们构成了数据从网卡到用户程序的高速公路,可以用一个「循环快递柜」系统来类比:

  • UMEM = 一大片划分好的快递柜(内存帧)。由用户态分配、同时映射给内核,是数据真正存放的地方。
  • Fill Ring = 用户告诉内核「这些空柜子可以用」的通知单。
  • Rx Ring = 内核放好包裹后,告诉用户「包裹在几号柜」的取件码。

UMEM 是什么

UMEM(User-space MEmory)是零拷贝的基石:用户程序 mmap 一块连续内存并向内核注册,内部按等长划分为许多 frame。所有收发数据包都存在这些 frame 里,每个 frame 用一个 addr(在 UMEM 中的偏移量)唯一标识。因为 UMEM 被用户态和内核共享,包在两边流转时无需拷贝,只交换描述符。

Fill Ring vs Rx Ring

两者是 UMEM 的配套管理结构,核心区别在「谁生产、谁消费、传什么」:

特性 Fill Ring(填充环) Rx Ring(接收环)
通俗理解 「可用空柜子」通知单 「已放包裹」取件码
生产者 用户程序 内核(网卡驱动)
消费者 内核(网卡驱动) 用户程序
传递内容 空闲帧的 addr 含数据帧的 addr + 长度
核心作用 用户向内核提供空闲内存 内核向用户交付数据包
所有权转移 用户空间 → 内核空间 内核空间 → 用户空间

收包全流程(四步循环)

1
2
3
4
5
6
7
8
9
用户程序                              内核 / 网卡
──────── ──────────
① 把空闲帧 addr 入 Fill Ring ──→ 内核从 Fill Ring 取 addr,获得帧所有权

② 网卡 DMA 直接把包写入该帧(CPU 不参与)

④ poll 醒来,从 Rx Ring 取 addr ←── ③ 内核把 addr+len 入 Rx Ring,通知用户取件

└→ 处理完,把该帧 addr 重新塞回 Fill Ring(归还,循环使用)

关键:Fill Ring 和 Rx Ring 配合,构成无锁的零拷贝接收链。发送方向对称地由 **Tx Ring(发送环)**和 **Completion Ring(完成环)**配合完成。这是理解 AF_XDP 性能的钥匙。

一句话:Fill Ring 是用户向内核「送弹药」(空闲内存)的通道,Rx Ring 是内核向用户「交战果」(数据包)的通道

4.5 bind() 与 poll():贴门牌号与按门铃等待

bind()poll() 是网络编程最基础的两个系统调用,但职责完全不同——一个管「贴门牌号」,一个管「按门铃等待」

bind():给套接字贴门牌号(命名与绑定)

把一个 socket 与一个本地地址关联。你买了个手机(Socket),别人要打来必须知道号码;bind 就是插 SIM 卡激活号码。完成绑定后,系统才知道某个数据包该交给谁。

  • 传统 TCP/UDP 服务(如 Nginx)bind0.0.0.0:80,告诉内核「所有发往本机 80 端口的 TCP 包都交给这个 socket」。
  • AF_XDP(sockaddr_xdp 结构体):语义变成了「绑定到某网卡的某硬件队列」:
1
2
sxdp.sxdp_ifindex   = ifindex;   // 绑定到特定网卡(如 eth0)
sxdp.sxdp_queue_id = queue_id; // 绑定到特定 CPU 收包队列(如 0)

绑完后,内核 XDP 程序通过 bpf_redirect_map 扔过来的包才会被精确投递到这个特定 socket。常见错误:端口被占用时 bind 返回 -1errno = EADDRINUSE

poll():等门铃响(多路 I/O 复用)

让当前线程主动让出 CPU 进入休眠,等待若干 fd 上的事件(可读/可写/出错)发生。类比:你不站在门口死盯(busy loop 会把 CPU 占满),而是坐沙发上睡觉、把门铃(fd)接在耳朵上;快递员按门铃,poll 被唤醒,你才起身开门(读数据)。

为什么 AF_XDP 必须用它?主循环若是裸 while(1) 不停查 Rx Ring,CPU 会 100% 空转。poll 实现「有包极速响应、无包深度休眠」:

1
2
3
// 不加 poll:死循环查 rx_ring,CPU 飙到 100%
int ret = poll(&(struct pollfd){.fd = sock, .events = POLLIN}, 1, 1000);
if (ret <= 0) continue; // 没包就继续睡,有包就醒

进阶:高并发(上万连接)服务器通常用 epoll 替代 poll(见 4.7);但 AF_XDP 单队列、单线程、只盯 1 个 fd 的极简场景下,poll 性能足够且代码更简洁。

4.6 poll 在 AF_XDP 里到底干了什么(三件事)

普通网络编程里 poll 只等「协议栈把数据备好」。AF_XDP 下它的责任被加重,干三件事:

① 等 Rx Ring 非空(取件码到位)。 用户态 poll 后 CPU 睡;网卡收到包、XDP 重定向进 Rx Ring 后,内核唤醒等待在该 socket 上的 poll,返回 POLLIN,告诉应用「Rx Ring 有新货了,快来 peek」。

② 等 Fill Ring 非满(反向背压)。 AF_XDP 零拷贝下,网卡需要一块空闲 frame 放新包,这块内存由用户通过 Fill Ring 提供。若用户处理太慢、把 Fill Ring 的空闲内存用光,网卡就没地方放新包、驱动会卡住。此时 poll 不仅等 Rx,也等 Fill Ring 释放出空槽——一旦用户释放了旧帧内存、Fill Ring 有空位,poll 被唤醒,催应用「快补 Fill Ring」。

③ 配合 XDP_USE_NEED_WAKEUP 标志(性能关键)。 绑定时若设 sxdp_flags = XDP_USE_NEED_WAKEUPpoll 就承担「软中断触发」职能:

  • 极致性能下,驱动把包扔进 Rx Ring 后默认不主动触发硬中断,靠应用主动 busy-poll。
  • 但流量一断、应用还在死循环轮询就空转费电。poll 内部告诉内核「我去睡了,下次有包请触发中断叫醒我」。
  • 唤醒后 poll 返回,应用处理包;处理中显式 sendto/xsk_ring_prod__submit 时,内核看到 need_wakeup 标记,知道应用进入工作模式,于是暂时关中断,直到应用再次 poll 睡觉。

一句话:AF_XDP 中 poll 是应用与网卡驱动之间的「节能开关」,在「无事可做时深度睡眠」与「有事发生时极速响应」间完美切换,避免 CPU 空转 100%。

4.7 epoll:poll 的高并发进化版

epoll 是 Linux 为高并发(成千上万连接)设计的 I/O 事件通知机制,是 poll/select 的替代。

与 poll 的核心区别

维度 poll / select epoll
数据结构 每次调用把全部 fd 列表从用户态拷到内核态 内核维护红黑树 + 就绪链表,注册一次即可
扫描方式 遍历整个 fd 数组 O(n),挨个查谁就绪 事件回调 O(1),谁就绪内核直接挂到就绪链表
返回结果 只返回就绪 fd 总数,应用仍需遍历全部找谁就绪 直接返回就绪 fd 列表,无需遍历
适用场景 监控 fd 少(几十个内) 监控 fd 极多(上万),活跃度不均(Nginx、Redis)

两种工作模式(epoll 独有)

  • LT(水平触发,默认):只要 fd 还有数据没读完,epoll_wait 就一直返回该事件。安全不易丢,但效率稍低(类似 poll)。
  • ET(边沿触发):只在 fd 状态变化时(不可读→可读)通知一次。本次没读完,下次不再提醒,直到新数据进来。迫使应用一次性读尽,极大减少系统调用次数,性能极高,但编程难度大(须配非阻塞 socket)。

在 AF_XDP 场景:用 poll 还是 epoll?

  • 单队列(1 个 AF_XDP socket)→ poll:只盯 1 个 fd,epoll 要额外建实例、注册、红黑树查找,反而更重。官方 libbpfxsk 示例默认就用 poll
  • 多队列(多 socket,如 16 个 RSS 硬件队列绑不同核)→ epoll:一个主线程统一管 16 个 fd,用 poll 每次要遍历 16 个;epoll 把它们全加进去、用 ET 模式在流量洪峰时减少无效唤醒,更标准高效。
  • 混合场景(AF_XDP 数据面 + 普通 TCP 控制面,如 8080 配置端口)→ epoll:把高速数据 fd 与常规 TCP listen fd 「混聚」一起等,是唯一优雅选择。
1
2
3
4
5
6
7
8
9
10
11
多队列 / 混合管理拓扑(epoll):
NIC Queue0 ─ XDP ─ AF_XDP sock0 ─┐
NIC Queue1 ─ XDP ─ AF_XDP sock1 ─┤
... ├─→ epoll(主线程,事件回调) ─→ 分发处理
NIC QueueN ─ XDP ─ AF_XDP sockN ─┤
TCP listen :8080(控制面) ─┘

vs.

单队列拓扑(poll):
NIC Queue0 ─ XDP ─ AF_XDP sock ─ poll() ─ 应用线程

面试要点epoll 解决的是「fd 多、活跃少」时的 O(n) 扫描浪费。AF_XDP 单队列只有 1 个 fd,poll 更轻;一旦多队列或混入 TCP 控制面,epoll 的红黑树+就绪链表+ET 模式才显出价值。bind 解决「数据送到哪里」的空间定位,poll/epoll 解决「数据何时送来」的时间等待

4.8 取舍

维度 AF_XDP 表现
性能 介于 XDP(内核态)和 DPDK(纯用户态)之间,零拷贝模式下接近 DPDK
网卡归属 内核仍管,能同时跑 ssh/mgmt 流量
表达力 用户态任意 C/Rust,复杂业务能写
中断 仍有,但可用 XDP_USE_NEED_WAKEUP + 批量 poll 减小开销
开发门槛 比 DPDK 低,比纯 XDP 高

4.9 典型用法

  • L7 负载均衡 / API 网关入口分流:XDP 把流量按规则甩到用户态业务进程。
  • DDoS 防护:XDP 速 drop 明显攻击,可疑流量 AF_XDP 上送用户态深度检测。
  • 可观测 / 抓包:替代 tcpdump(pcap 走内核栈,pps 高就丢),AF_XDP 能扛千万 pps 不丢。
  • 边车 / Service Mesh 数据面:把特定端口流量重定向到 sidecar,绕开 iptables。

面试要点:AF_XDP = XDP redirect + 用户态 socket + umem 零拷贝。它继承了 XDP「快入口」和用户态「强表达力」两者的优点,又不像 DPDK 那样独占网卡。是当下 cloud-native 高性能数据面的主流选择之一(Cilium 1.12+ 即支持)。


五、三者横向对比(一张表定调)

维度 XDP DPDK AF_XDP
包最终处理位置 内核态(驱动层) 用户态 用户态
是否绕过内核 否(早于协议栈,但仍内核态) 完全旁路 半旁路(驱动在内核,包送用户态)
网卡归属 内核 DPDK 进程独占 内核
编程模型 eBPF(受限、verifier 保证安全) 任意 C(PMD) 用户态任意 + eBPF redirect
中断 仍有软中断 无中断(轮询) 仍有(可优化)
CPU 占用 满载(专核轮询)
性能 高(百万~千万 pps drop) 最高(千万 pps 线速) 高(接近 DPDK)
内核服务可用 全部 几乎无(路由/conntrack/iptables 全废) 全部
部署门槛 中(编译 eBPF + libbpf) 高(绑核、大页、VFIO、写 PMD)
典型场景 DDoS drop、L4 DSR、XDP_LB NFV、5G UPF、vSwitch、行情网关 L7 网关、边车数据面、抓包

选型口诀

  • 只想快速丢/转发包、逻辑简单 → XDP
  • 线速 + 复杂业务、能接受独占网卡和满载 CPU → DPDK
  • 高吞吐 + 复杂业务、又要保留内核网络服务、用 eBPF 生态 → AF_XDP

六、与大模型 Infra 的关系(面试连接点)

虽然 XDP/DPDK/AF_XDP 主要用于网络功能/网关,但和大模型 Infra 有几处直接交叉,面试能聊就是加分:

  1. NCCL / RDMA 路径旁路:千卡训练的 all-reduce 走 RDMA(RoCE/IB),本身已是 kernel bypass(绕过 TCP 栈,用户态直写 NIC)。DPDK 的思想(用户态 PMD、零拷贝、大页、无中断)和 RDMAverbs 的 ibv_post_send 轮询模型同源。能讲清「为什么训练通信要 bypass 内核」就接得上。
  2. 推理网关 / Token 流量:大模型推理服务(vLLM/TGI 前面)的 L7 网关,百万 QPS 的 TLS/路由,Cilium + AF_XDP / Envoy 是常见数据面。
  3. 可观测性:eBPF(XDP 的母体)是 GPU/CPU/网络全栈观测的事实标准——PyTorch profiler、Parca、Pixie 都靠 eBPF 采火焰图和延迟分布。
  4. KV-cache 跨节点直读:未来 P-D 分离里 worker 直读参数/远端 KV,绕过内核的 RDMA/DPDK 思路直接相关。

一句话桥接:RDMA 是「训练通信」的 kernel bypass,XDP/DPDK/AF_XDP 是「通用包处理」的 kernel bypass,底层动机完全一致——把数据面从内核解放出来,用轮询+零拷贝+用户态换线速。


七、面试高频速答

Q1:XDP 和 DPDK 都绕过内核,区别是什么?
XDP 不绕过内核——它仍在内核态、用内核驱动收包,只是把 eBPF 决策点放在协议栈之前;DPDK 是真 bypass,用 VFIO 接管网卡、用户态 PMD 轮询、零中断。XDP 安全(verifier)但弱,DPDK 自由但重。

Q2:AF_XDP 的零拷贝怎么做到的?
umem:一块用户态申请、同时映射给内核的内存,作为 DMA 目标。包 DMA 进 umem 后,XDP 程序把描述符 enqueue 到 RX ring,用户态进程直接读 umem 对应位置,全程不拷贝数据。

Q3:为什么 DPDK 要绑核 100% 轮询?不能中断吗?
高 pps 下中断本身是瓶颈,每包一次中断会让 CPU 全在硬中断里。PMD 轮询去掉中断、去掉上下文切换,用「一个核满载换线速」。所以 DPDK 部署要 dedicate 核并隔离。

Q4:XDP 程序为什么安全?
eBPF verifier 在加载时静态分析:保证程序必终止(无无界循环)、所有内存访问在边界内、符合调用约定。unsafe 的程序根本 load 不进内核。代价是不能写任意逻辑。

Q5:要保留内核协议栈又要高吞吐,选哪个?
AF_XDP。它网卡归内核管(ssh/mgmt 流量照跑),同时 XDP 把业务流量零拷贝送到用户态,兼顾吞吐和内核服务。

Q6:DPDK 和 RDMA 都是 kernel bypass,区别?
DPDK 是「接管整个 NIC,用户态轮询 RX 环」;RDMA 是「NIC 硬件直接读写远端内存,CPU 不参与」,走 verbs API 和 RDMA 协议栈。DPDK 处理通用包,RDMA 处理内存语义的远程读写。训练里 NCCL 用 RDMA,NFV 用 DPDK。


八、总结

把三条路径放在一条光谱上:

1
2
3
4
5
6
7
      内核参与多 ◀─────────────────────────────▶ 内核参与少
┌─────────────┬──────────────┬─────────────┐
│ XDP │ AF_XDP │ DPDK │
│ 内核态 eBPF │ XDP→用户态 │ 纯用户态 PMD│
│ 快丢/快转 │ 零拷贝+强逻辑│ 线速+独占网卡│
└─────────────┴──────────────┴─────────────┘
安全但弱 中庸,cloud-native 主流 最快但最重

记一条主线就够了:它们都是把数据面从内核协议栈解放出来,区别只在于「解放到什么程度、用什么换、付出什么代价」——XDP 前移到驱动层、AF_XDP 用 umem 送到用户态、DPDK 彻底接管网卡。掌握这条光谱,再记住「轮询 + 零拷贝 + 用户态」这三板斧的共同动机,面试就稳了。

参考资料