XDP的系统架构
XDP的工作位置
内核中的转发路径
XDP的工作模式 XDP 总共支持三种工作模式(operation mode)
xdpdrv: xdpdrv 表示 native XDP(原生 XDP), 意味着 BPF 程序直接在驱动的接收路 径上运行,理论上这是软件层最早可以处理包的位置(the earliest possible point)。这是常规/传统的 XDP 模式,需要驱动实现对 XDP 的支持,目前 Linux 内核中主流的 10G/40G 网卡都已经支持。
xdpgeneric: xdpgeneric 表示 generic XDP(通用 XDP),用于给那些还没有原生支持 XDP 的驱动进行试验性测试。generic XDP hook 位于内核协议栈的主接收路径(main receive path)上,接受的是 skb 格式的包,但由于 这些 hook 位于 ingress 路 径的很后面(a much later point),因此与 native XDP 相比性能有明显下降。因 此,xdpgeneric 大部分情况下只能用于试验目的,很少用于生产环境。
xdpoffload: 一些智能网卡(例如支持 Netronome’s nfp 驱动的网卡)实现了 xdpoffload 模式 ,允许将整个 BPF/XDP 程序 offload 到硬件,因此程序在网卡收到包时就直接在网卡进行处理。这提供了比native XDP 更高的性能,虽然在这种模式中某些 BPF map 类型和BPF 辅助函数是不能用的。BPF 校验器检测到这种情况时会直接报错,告诉用户哪些东西是不支持的。除了这些不支持的 BPF 特性之外,其他方面与 native XDP 都是一样的。
XDP程序的返回码 XDP程序执行结束后会返回一个结果,告诉调用者接下来如何处理这个包:
XDP_DROP,丢弃这个包,主要用于报文过滤的安全场景;
XDP_PASS,将这个包“交给/还给”内核,继续走正常的内核处理流程;
XDP_TX,从收到包的网卡上再将这个包发出去(即hairpin模式),主要用于负载均衡场景;
XDP_REDIRECT,何XDP_TX类似,但是是通过另外一个网卡将包发出去。除此之外还可以实现将报文重定向到其他的CPU处理,类似于XDP_PASS继续走内核处理流程,但是由其他的CPU处理,当前CPU继续处理后续的报文接收;
XDP_ABORTED,表示程序产生异常,行为类似XDP_DROP,但是会通过一个tracepoint打印日志义工追踪;
Linux内核之XDP测试 软件安装 1 2 3 4 5 6 $ apt-get update $ apt-get install make gcc g++ cmake clang llvm gcc-multilib -y $ apt-get install bison libtool libelf-dev libreadline-dev -y $ apt-get install vim git jq curl pkg-config openssl -y $ apt-get install libpcap-dev libzip-dev libssl-dev -y $ apt-get install libnl-3-dev libnl-route-3-dev libnl-cli-3-dev -y
第一个XDP程序 1. 代码xdp-drop.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <linux/bpf.h> #define SEC(NAME) __attribute__((section(NAME), used)) SEC("xdp" ) int xdp_drop_the_world (struct xdp_md *ctx) { return XDP_DROP; } char _license[] SEC("license" ) = "GPL" ;
2. 编译 1 $ clang -O2 -target bpf -c xdp-drop.c -o xdp-drop.o
3. 反汇编 1 $ llvm-objdump -S xdp-drop.o
4. 加载XDP程序 1 $ ip link set dev ens18 xdp obj xdp-drop.o sec xdp verbose
5. 查看XDP加载状态 1 $ ip link show dev ens18
6. 卸载XDP程序 1 $ ip link set dev ens18 xdp off
5. 查看效果
ens18加载XDP后,从外部ping网口ens18的IP地址,不通
ens18卸载XDP后,从外部ping网口ens18的IP地址,能通
调试技巧 1. 使用xdpdump在网口抓包 1 $ xdpdump -i ens18 -w - | tcpdump -r - -nn
2. 开启trace_event日志 1 2 3 4 $ cd /sys/kernel/tracing$ cat available_events$ echo "xdp:*" >set_event$ cat trace_pipe
XDP相关项目
参考