.. _ebpf-xdp:
23.4. eBPF 与 XDP¶
23.4.1. 简介¶
eBPF 全称为扩展版 BPF。这是 Berkeley 数据包过滤器在近期 Linux 内核版本中的扩展实现。
它通过 C 语言开发的 eBPF 程序提供更高级功能,并支持内核与用户空间之间共享结构化数据。
在 Suricata 中,eBPF 用于以下三个方面:
eBPF 过滤器:可开发任何类 BPF 过滤器。示例提供了仅接受特定 VLAN 数据包的过滤器,并包含旁路实现。
eBPF 负载均衡:提供可编程负载均衡。示例实现了简单的 IP 对负载均衡。
XDP 程序:Suricata 可加载 XDP 程序。示例提供了旁路程序。
旁路功能可通过 eBPF 和 XDP 实现。XDP 的优势在于能在最早阶段丢弃数据包,因此性能更优。但被旁路的流量不会进入网络栈,故仅适用于镜像/嗅探流量,常规流量无法使用此功能。
旁路实现依赖于 eBPF 的核心概念:映射(map)。映射是用户空间与内核空间/硬件共享的数据结构,支持两者间的交互和信息传递。映射通常实现为可存储任意键值对的数组或哈希表。
23.4.1.1. XDP¶
XDP 为 Linux 原生提供了另一种优化 Suricata 在高速网络嗅探性能的方案:
XDP(eXpress Data Path)作为 IO Visor 项目的一部分,在 Linux 内核中提供了高性能、可编程的网络数据路径。XDP 在软件栈最底层实现裸金属级数据包处理,兼具高速与可编程性。此外,无需修改内核即可通过集成快路径动态实现新功能。
更多 XDP 信息:
23.4.2. 系统要求¶
需使用支持 XDP 的内核版本,为获得最佳性能建议网卡驱动支持 XDP。
Suricata XDP 代码已在 4.13.10 内核测试,但需 4.15 或更新版本才能使用 CPU 重定向映射等全部功能。
若使用 Intel 网卡,需使用内核树内驱动的 NIC 驱动,树外驱动不包含 XDP 支持。
建议网卡支持 RSS 对称哈希,否则需使用 XDP CPU 重定向映射功能。
23.4.3. 环境准备¶
本指南已在 Debian/Ubuntu "LTS" Linux 验证。
23.4.3.1. 禁用 irqbalance¶
多数场景下 irqbalance
可能导致问题,建议停用
systemctl stop irqbalance
systemctl disable irqbalance
23.4.3.2. 内核版本¶
需运行 4.13 或更新版本内核。
23.4.3.3. Clang 及依赖¶
确保系统已安装 clang
(>=3.9)
sudo apt install clang
23.4.3.4. libbpf¶
Suricata 使用 libbpf 与 eBPF/XDP 交互
sudo apt install libbpf-dev
若无法获取 libbpf 包,可从仓库克隆
git clone https://github.com/libbpf/libbpf.git
编译安装库
cd libbpf/src/
make && sudo make install
sudo make install_headers
sudo ldconfig
部分系统可能无法找到安装在 /usr/lib64
下的 libbpf 库,此时需调整 ldconfig 配置。
23.4.4. 编译安装 Suricata¶
获取 Suricata 源码
git clone https://github.com/OISF/suricata.git
cd suricata && ./scripts/bundle.sh
./autogen.sh
配置时添加 eBPF 标志并指定 Clang 编译器(用于构建包括 eBPF 程序在内的所有 C 源码):
CC=clang ./configure --prefix=/usr/ --sysconfdir=/etc/ --localstatedir=/var/ \
--enable-ebpf --enable-ebpf-build
make clean && make
sudo make install-full
sudo ldconfig
sudo mkdir /usr/libexec/suricata/ebpf/
构建 eBPF 文件需使用 clang
编译器,因其独有的 eBPF 后端仅存在于 llvm/clang 工具链。若不想用 Clang 编译 Suricata 本体,可通过 --with-clang
单独指定
./configure --prefix=/usr/ --sysconfdir=/etc/ --localstatedir=/var/ \
--enable-ebpf --enable-ebpf-build --with-clang=/usr/bin/clang
23.4.5. 配置旁路¶
若计划使用 eBPF 或 XDP 实现内核/硬件级旁路,需启用以下功能:
首先在 suricata.yaml
的 stream 部分启用 bypass
stream:
bypass: true
这将使流在达到深度阈值时立即被旁路。
如需旁路加密流量,可在应用层 TLS 部分设置 encryption-handling 为 bypass
app-layer:
protocols:
tls:
enabled: yes
detection-ports:
dp: 443
encryption-handling: bypass
另一种方案是使用含 bypass
关键字的签名规则实现选择性旁路。Suricata 流量识别定义的 flowbits 可用于其他签名,例如
alert any any -> any any (msg:"bypass video"; flowbits:isset,traffic/label/video; noalert; bypass; sid:1000000; rev:1;)
alert any any -> any any (msg:"bypass Skype"; flowbits:isset,traffic/id/skype; noalert; bypass; sid:1000001; rev:1;)
23.4.6. 配置 eBPF 过滤器¶
修改 ebpf/vlan_filter.c 中的 VLAN ID 列表以适配您的网络。ebpf/filter.c 还提供了基于 IPv4 地址集的过滤示例。详见 固定映射用法。
Suricata 可加载任何暴露 filter
段的 eBPF 代码作为过滤器。
修改并 make
编译后,复制生成的 eBPF 过滤器
cp ebpf/vlan_filter.bpf /usr/libexec/suricata/ebpf/
在 suricata.yaml
的 af-packet 部分设置 ebpf-filter-file 变量
- interface: eth3
threads: 16
cluster-id: 97
cluster-type: cluster_flow # 选择合适类型
defrag: yes
# 包含'filter'函数的eBPF文件将插入内核用作负载均衡函数
ebpf-filter-file: /usr/libexec/suricata/ebpf/vlan_filter.bpf
ring-size: 200000
正常启动 Suricata
/usr/bin/suricata --pidfile /var/run/suricata.pid --af-packet=eth3 -vvv
23.4.7. 配置 eBPF 旁路¶
也可使用 eBPF 旁路。加载 bypass_filter.bpf 文件并在 suricata.yaml
的 af-packet 配置中设置 bypass 为 yes
- interface: eth3
threads: 16
cluster-id: 97
cluster-type: cluster_qm # 必须启用对称RSS哈希
# 包含'filter'函数的eBPF文件将插入内核用作包过滤函数
ebpf-filter-file: /usr/libexec/suricata/ebpf/bypass_filter.bpf
bypass: yes
ring-size: 200000
旁路兼容代码的约束比常规过滤器更严格。过滤器必须暴露 flow_table_v4 和 flow_table_v6 这两个每 CPU 数组映射,其定义需与 bypass_filter.c 中的一致。Suricata 将通过这两个映射维护旁路流列表。
若未启用 VLAN 跟踪(suricata.yaml
中 vlan.use-for-tracking 设为 false),还需在 bypass_filter.c
中将 VLAN_TRACKING
宏设为 0。
23.4.8. 配置 eBPF 负载均衡¶
eBPF 负载均衡允许通过监听套接字按 eBPF 过滤器实现的逻辑分配流量。标记为 loadbalancer
段的函数返回值将按 CPU 数取模决定数据包发送的目标套接字。
lb.bpf 提供了简单的对称 IP 对哈希实现。
复制生成的 eBPF 过滤器
cp ebpf/lb.bpf /usr/libexec/suricata/ebpf/
在 af-packet 接口配置中使用 cluster_ebpf 作为负载均衡方法,并指向 lb.bpf 文件
- interface: eth3
threads: 16
cluster-id: 97
cluster-type: cluster_ebpf
defrag: yes
# 包含'loadbalancer'函数的eBPF文件将插入内核用作负载均衡函数
ebpf-lb-file: /usr/libexec/suricata/ebpf/lb.bpf
ring-size: 200000
23.4.9. 配置 XDP 旁路¶
XDP 旁路允许 Suricata 通过 XDP 机制通知内核丢弃特定流的数据包。此操作在数据包到达 Linux 内核网络栈前完成,属于早期丢弃。
推荐使用 Linux 4.15 或更新版本。旧版内核需在 ebpf/xdp_filter.c
中设置 BUILD_CPUMAP
为 0。
复制生成的 XDP 过滤器
cp ebpf/xdp_filter.bpf /usr/libexec/suricata/ebpf/
配置 suricata.yaml
的 af-packet 接口部分。
示例使用 cluster_qm``(需 NIC 支持对称哈希)、``xdp-mode: driver
及 TCP 卸载/旁路
- interface: eth3
threads: 16
cluster-id: 97
cluster-type: cluster_qm # 必须启用对称哈希!
defrag: yes
# XDP模式:"soft"为基于skb,"driver"为基于网卡,"hw"为支持eBPF的硬件
xdp-mode: driver
xdp-filter-file: /usr/libexec/suricata/ebpf/xdp_filter.bpf
# 若eBPF过滤器实现旁路功能,可设为yes启用
bypass: yes
ring-size: 200000
# 使用Netronome等硬件XDP网卡时取消注释(默认值为yes)
# use-percpu-hash: no
XDP 旁路兼容 AF_PACKET IPS 模式。旁路流的数据包将直接从一张网卡发送至另一张,不经内核网络栈。
使用硬件 XDP 卸载时,可能需设置 use-percpu-hash
为 false,并在编译安装 XDP 过滤器前将 USE_PERCPU_HASH
设为 0。
XDP 过滤器文件中,设置 ENCRYPTED_TLS_BYPASS
为 1 可旁路加密的 TLS 1.2 流量。注意这将使 Suricata 无法检测 443 端口的匹配流量。
若未启用 VLAN 跟踪(vlan.use-for-tracking
设为 false),还需在 xdp_filter.c
中将 VLAN_TRACKING
设为 0。
23.4.9.1. Intel 网卡配置¶
Intel 网卡不支持对称哈希,但可通过特定哈希函数模拟。
严格按以下步骤操作
ifconfig eth3 down
使用内核树内驱动:Intel 官网提供的驱动不支持 XDP。
启用对称哈希
ifconfig eth3 down
ethtool -L eth3 combined 16 # 至少16核
ethtool -K eth3 rxhash on
ethtool -K eth3 ntuple on
ifconfig eth3 up
./set_irq_affinity 0-15 eth3
ethtool -X eth3 hkey 6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A:6D:5A equal 16
ethtool -x eth3
ethtool -n eth3
set_irq_affinity
脚本可从任何 Intel x520/710 网卡驱动下载包获取。
注意: 此处使用低熵密钥实现对称哈希。对称哈希设置研究详情
23.4.9.2. 禁用网卡卸载功能¶
运行以下命令禁用卸载
for i in rx tx tso ufo gso gro lro tx nocache copy sg txvlan rxvlan; do
/sbin/ethtool -K eth3 $i off 2>&1 > /dev/null;
done
23.4.9.3. 最大化负载均衡¶
尽量利用网卡的流均衡功能
for proto in tcp4 udp4 ah4 esp4 sctp4 tcp6 udp6 ah6 esp6 sctp6; do
/sbin/ethtool -N eth3 rx-flow-hash $proto sd
done
此命令仅基于源/目的 IP 进行负载均衡。虽在均衡公平性上非最优,但确保分片流的所有数据包均到达同一线程(某些分片包可能无法获取端口信息)。
23.4.9.4. XDP CPU 重定向场景¶
若硬件不支持对称负载均衡但支持驱动模式 XDP,可使用 xdp_filter.bpf 和 xdp_lb.bpf 中的 CPU 重定向映射功能。此模式下,XDP 过滤器负责负载均衡,各 CPU 处理包括内核 skb 结构创建在内的完整数据包处理流程。
需 Linux 4.15 或更新版本支持。
在 af-packet 接口配置中设置 xdp-cpu-redirect 为目标 CPU 集,并使用 cluster_cpu 作为负载均衡方法。同时需设置 CPU 亲和性确保 Suricata 使用分配了 skb 的核。
为避免乱序包,需将 RSS 队列数设为 1。以 eth3 为例
/sbin/ethtool -L eth3 combined 1
系统超过 64 核时,需在 xdp_lb.c 和 xdp_filter.c 中将 CPUMAP_MAX_CPUS 设为更大值。
纯 XDP 负载均衡配置示例
- interface: eth3
threads: 16
cluster-id: 97
cluster-type: cluster_cpu
xdp-mode: driver
xdp-filter-file: /usr/libexec/suricata/ebpf/xdp_lb.bpf
xdp-cpu-redirect: ["1-17"] # 或 ["all"] 在所有CPU上均衡
ring-size: 200000
可通过 xdp_monitor 监控 CPU 重定向行为。该程序位于 Linux 源码树的 samples/bpf 目录,由 make 命令构建。示例输出
sudo ./xdp_monitor --stats
XDP-event CPU:to pps drop-pps extra-info
XDP_REDIRECT 11 2,880,212 0 Success
XDP_REDIRECT total 2,880,212 0 Success
XDP_REDIRECT total 0 0 Error
cpumap-enqueue 11:0 575,954 0 5.27 bulk-average
cpumap-enqueue sum:0 575,954 0 5.27 bulk-average
cpumap-kthread 0 575,990 0 56,409 sched
cpumap-kthread 1 576,090 0 54,897 sched
23.4.9.5. 启动带 XDP 的 Suricata¶
启动启用 XDP 旁路的 Suricata
/usr/bin/suricata -c /etc/suricata/xdp-suricata.yaml --pidfile /var/run/suricata.pid --af-packet=eth3 -vvv
确认输出中包含 XDP 过滤器启用信息(示例):
...
...
(runmode-af-packet.c:220) <Config> (ParseAFPConfig) -- 为接口eth3启用mmap内存锁定
(runmode-af-packet.c:231) <Config> (ParseAFPConfig) -- 在接口eth3启用tpacket v3捕获
(runmode-af-packet.c:326) <Config> (ParseAFPConfig) -- 为AF_PACKET(接口eth3)使用基于队列的集群模式
(runmode-af-packet.c:424) <Info> (ParseAFPConfig) -- af-packet将使用'/usr/libexec/suricata/ebpf/xdp_filter.bpf'作为XDP过滤器文件
(runmode-af-packet.c:429) <Config> (ParseAFPConfig) -- 为AF_PACKET(接口eth3)启用内核旁路功能
(runmode-af-packet.c:609) <Config> (ParseAFPConfig) -- eth3: 通过数据释放调用启用零拷贝模式
(util-runmodes.c:296) <Info> (RunModeSetLiveCaptureWorkersForDevice) -- 将使用8个线程
...
...
23.4.10. 固定映射用法¶
固定映射在创建进程退出后仍保持附着状态,且可被外部工具访问。在 Suricata 旁路场景中,这可用于保持旁路流表活跃,避免重启时已旁路流量冲击 Suricata。在套接字过滤器场景中,可用于由外部工具维护映射。
使用固定映射前需挂载 bpf 伪文件系统
sudo mount -t bpf none /sys/fs/bpf
或在 /etc/fstab 添加
bpffs /sys/fs/bpf bpf defaults 0 0
后执行 sudo mount -a。
固定映射将以文件形式存在于 /sys/fs/bpf 目录。Suricata