用于 Linux 数据包处理的 XDP 和 eBPF
14 分钟阅读 - 2026年5月27日
XDP 和 eBPF 如何在网卡驱动程序层处理每秒数百万个数据包。基准、DDoS 用例、工具链设置和硬件要求。
用于高性能数据包处理的 XDP 和 eBPF
XDP(eXpress Data Path)和 eBPF(extended Berkeley Packet Filter)允许 Linux 在内核常规网络协议栈介入之前处理网络数据包。XDP 无需为每个传入数据包分配内存结构,而是直接在网卡驱动程序处拦截流量,决定如何处理,并将其丢弃、转发或重定向。 其结果是每核心每秒可处理数百万个数据包,且CPU开销仅为传统工具(如 iptables.
eBPF 与 XDP 如何协同工作
eBPF 是 Linux 内核中的一个虚拟机。它运行经过安全性验证(无无限循环、无未经授权的内存访问)的自定义字节码,并将其即时编译(JIT)为原生 CPU 指令。程序的作用域受到限制。它们无法调用任意内核函数,只能调用预定义的一组辅助函数来执行映射查找和数据包重定向等任务。
在状态管理方面,eBPF 使用映射(maps),即跨数据包到达过程保持持久化的键值存储(哈希表、数组、LPM trie)。用户空间可以读写这些映射,因此无需重新加载程序即可更新黑名单或路由规则。
XDP 是 eBPF 的挂钩点。它挂载在网卡驱动程序的接收路径上,位于内核分配 sk_buff 结构(即传统网络堆栈所依赖的、每个数据包占用 200-300 字节的元数据对象)之前。跳过该分配操作正是性能提升的来源。
XDP 支持三种运行模式:
- 原生模式:在网卡驱动程序内部运行。性能最佳。
- 卸载模式:在网卡的 ASIC 上运行。完全释放 CPU 资源。
- 通用模式:在
sk_buff。适用于在不受支持的硬件上进行测试,但无性能优势。
处理完每个数据包后,XDP 程序会返回一个判定结果:
| 判定 | 操作 |
|---|---|
XDP_DROP | 在驱动程序层丢弃数据包 |
XDP_PASS | 转发至常规网络堆栈 |
XDP_TX | 通过同一接口发送出去 |
XDP_REDIRECT | 重定向到另一个网卡或 AF_XDP 用户空间套接字 |
XDP_ABORTED | 因程序错误丢弃数据包,并记录跟踪事件 |
XDP 与 iptables:性能基准测试
数据令人震惊。 iptables 每核心每秒处理约 200,000 个数据包。 nftables 将其提升至约 400,000 pps。在原生模式下,XDP 在相同硬件上每核心可处理 1,000 万至 4,000 万 pps。
原因很简单:一个 XDP_DROP 需要一次边界检查和一个返回值。而 iptables DROP 则需要 sk_buff 内存分配、netfilter 链遍历、连接跟踪查询、DROP 操作本身,以及随后的内存释放。在 100 Gbps 速率下处理 64 字节数据包时,服务器每秒需处理 1.48 亿个数据包,每个数据包仅剩约 100 纳秒处理时间。在此规模下, sk_buff 内存分配便成了瓶颈。
CPU 资源的节省同样显著。在某项基准测试中,将黑名单从 iptables 迁移至 XDP,在 100 万包/秒的测试中,将软件中断的 CPU 使用率从 28% 降至 3%。由此释放的处理余量可在同一服务器上运行应用程序进程、数据库或虚拟机。
DDoS 缓解与安全
XDP 最强大的托管应用场景是 DDoS 缓解。由于其在驱动程序层运行,恶意数据包在触及内核网络堆栈之前即被丢弃。单个运行 XDP 的核心每秒可丢弃 2600 万个数据包。
自 2018 年起,Cloudflare 便开始使用名为 L4Drop 的基于 XDP 的系统来缓解海量 DDoS 攻击。该系统在 XDP 环境中处理并丢弃攻击流量,防止其到达应用层。Meta 的 Katran 是一款开源的 XDP 第 4 层负载均衡器,为 Facebook 和 Instagram 处理流量,每核处理速度超过 1000 万包/秒。
对于动态过滤,eBPF 映射(如 BPF_MAP_TYPE_LPM_TRIE ,可让您通过单次查询管理涵盖单个 IP 和 CIDR 子网的 IP 黑名单。更新在用户空间实时进行,无需重新加载程序。在攻击进行期间,您可以使用 bpftool:
bpftool map update id <MAP_ID> key <KEY_VALUE> value <VALUE>在可观测性方面,eBPF 直接从内核数据路径收集按应用、按 IP 和按流的指标。 xdp_md 上下文提供如下遥测数据 ingress_ifindex 和 rx_queue_index等遥测数据,从而帮助您识别受压的接口或队列。对于长期监控,诸如 ebpf_exporter 等工具可将原始 eBPF 映射数据转换为兼容 Prometheus 的指标,以便在 Grafana 中进行可视化。
工具、部署与硬件要求
工具链以 Clang 和 LLVM 为起点,用于将受限 C 语言编译为 eBPF 字节码。在此基础上,您需要一个加载器库:
libbpf: 适用于生产环境的标准 C 库。支持 CO-RE(一次编译,随处运行)以实现跨内核的可移植性。libxdp: 专为 XDP 设计,支持在单个接口上运行多个 XDP 程序。cilium/ebpf:面向基于 Go 的堆栈的纯 Go 库。
用于管理, bpftool 可让您检查正在运行的程序并映射内容。 xdp-loader (来自 xdp-tools 套件) 负责加载和卸载操作。BCC 适用于配合 Python/Lua 前端进行原型开发,但 libbpf 在生产环境中,与 CO-RE 配合使用是更好的选择。
部署前请启用 BPF JIT 编译器:
sysctl -w net.core.bpf_jit_enable=1若需零停机更新,请使用 XDP_FLAGS_REPLACE 标志以原子方式替换正在运行的程序。将映射固定到 /sys/fs/bpf/ ,使其在加载器退出后仍保持有效。
硬件与内核兼容性
XDP 于内核 4.8 版本引入,但建议使用 5.x 或更高版本以获得完整功能集。请使用 uname -r 并验证 BPF 文件系统是否位于 /sys/fs/bpf/.
您的网卡驱动程序决定了可用的 XDP 功能:
| 驱动程序 | 基本 XDP | 重定向 | 零拷贝 (AF_XDP) |
|---|---|---|---|
mlx5_core | 是 | 是 | 是 |
i40e | 是 | 是 | 是 |
ixgbe | 是 | 是 | 是 |
virtio_net | 是 | 是 | 否 |
ena (亚马逊) | 是 | 是 | 否 |
请使用 ethtool -i <interface>。如果系统不支持原生模式,则会回退到通用模式,该模式在 sk_buff ,因此无法提供性能优势。
在连接 XDP 程序之前请禁用 GRO 和 LRO,因为它们会发生冲突:
ethtool -K <iface> gro off lro off标准 XDP 要求数据包必须能容纳在单个 4,096 字节的内存页中。在 i40e 和 ice 驱动程序上,x86 的 MTU 限制为 3,046 字节。
XDP 入门指南
首先评估您的环境。运行 uname -r 以确认内核版本为 4.8 及以上(建议使用 5.x 系列),并 ethtool -i <interface> 以检查是否支持原生 XDP 驱动程序。
从可观测性入手,而非强制执行。使用 eBPF 映射对流量进行分类和计数,以便建立正常活动的基线。在了解流量模式后,再转向强制执行:先使用 xdpgeneric 模式进行测试,随后切换至 xdpdrv (原生) 模式用于生产环境。
请注意,XDP处理的是数据包级别的过滤,而非原始带宽。对于100 Gbps的大规模攻击,应将其与裸机基础设施及BGP FlowSpec配合使用,在流量到达服务器之前就对其进行管理。
如果您正在运行需要快速数据包过滤的高流量工作负载,FDC 的专用服务器可提供裸机基础架构,助您充分发挥 XDP 的性能优势。
用于 Linux 数据包处理的 XDP 和 eBPF
XDP 和 eBPF 如何在网卡驱动程序层处理每秒数百万个数据包。基准、DDoS 用例、工具链设置和硬件要求。
14 分钟阅读 - 2026年5月27日
为什么必须拥有功能强大且不计量的 VPS
3 分钟阅读 - 2025年5月9日