本文最后更新于:2026年4月1日 晚上
我们知道linux内核转发数据包的路径非常冗长,要经过bridge,netfilter,路由等,导致性能低。而XDP的点位非常靠前,把转发做在XDP里面有没有搞头?
下文就做一个写死的demo小程序,看看XDP里面能不能把数据包转发出去,性能能提高多少。
环境搭建
参考搭建参考 [[单台设备如何模拟测试数据转发性能]]

xdp程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <linux/bpf.h> #include <bpf/bpf_helpers.h> #include <linux/if_ether.h> #include <linux/ip.h> #include <bpf/bpf_endian.h>
SEC("xdp") int xdp_forward_prog(struct xdp_md *ctx) { void *data = (void *)(long)ctx->data; void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data; if ((void*)(eth + 1) > data_end) return XDP_PASS;
if (eth->h_proto != bpf_htons(ETH_P_IP)) return XDP_PASS;
struct iphdr *ip = (void *)(eth + 1); if ((void*)(ip + 1) > data_end) return XDP_PASS;
if (ip->daddr != bpf_htonl(0x0a000201)) { return XDP_PASS; }
unsigned char dst_mac[ETH_ALEN] = {0x6a,0x68,0x07,0x59,0x0b,0xb7}; unsigned char src_mac[ETH_ALEN] = {0x02,0x72,0xdb,0x4c,0xaf,0x08};
__builtin_memcpy(eth->h_dest, dst_mac, ETH_ALEN); __builtin_memcpy(eth->h_source, src_mac, ETH_ALEN);
int ifindex = 9;
return bpf_redirect(ifindex, 0); }
char _license[] SEC("license") = "GPL";
|
编译加载xdp程序
编译
1
| clang -O2 -g -target bpf -I/usr/include/x86_64-linux-gnu -I/usr/include -c xdp_forward.c -o xdp_forward.o
|
加载到veth1-peer
1
| ip netns exec ns2 ip link set dev veth1-peer xdp obj xdp_forward.o sec xdp
|
卸载命令
1
| ip netns exec ns2 ip link set dev veth1-peer xdp off
|
解决veth下的xdp丢包问题
加载xdp程序后,发现网络就不通了,转发完全丢包。经过搜索发现,bpf_redirect针对veth网卡有限制,需要对端也挂XDP。
我们给ns3也编写一个xdp程序
1 2 3 4 5 6 7 8 9 10 11 12
|
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> #include <linux/if_ether.h> #include <linux/ip.h> #include <bpf/bpf_endian.h>
SEC("xdp") int xdp_pass_prog(struct xdp_md *ctx) { return XDP_PASS; }
|
然后编译加载
1 2
| clang -O2 -g -target bpf -I/usr/include/x86_64-linux-gnu -I/usr/include -c xdp_pass.c -o xdp_pass.o ip netns exec ns3 ip link set dev veth2-peer xdp obj xdp_pass.o sec xdp
|
性能对比
ns1上使用pktgen发包
1
| ip netns exec ns1 ./pktgen_sample01_simple.sh -i veth1 -s 64 -n 0 -d 10.0.2.1 -m 2a:cd:06:e5:5c:79
|
观测ns2的收发包情况:ip netns exec ns2 sar -n DEV 1
1 2 3 4
| 22时11分20秒 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil 22时11分21秒 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22时11分21秒 veth1-peer 301884.00 1.00 14740.43 0.09 0.00 0.00 0.00 1.21 22时11分21秒 veth2 1.00 301884.00 0.09 18867.75 0.00 0.00 0.00 1.55
|
对比不使用xdp的情况,性能只提高了6%。
| 性能 |
pps |
| 默认 |
283040 |
| XDP转发 |
301884 |
说明此时netfilter,路由查找的代价还不是很高。我们把代价提高,添加一个连接跟踪规则。
1 2
| ip netns exec ns2 bash -c iptables -I FORWARD -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
|
然后再对比性能,走默认协议栈的pss性能下降很多,但是xdp的性能不变,此时性能提升40%。
| 性能 |
pps |
| 添加netfilter连接跟踪规则 |
210708 |
| XDP转发 |
302602 |
总结
(1)xdp里面确实可以搞数据包转发,但要完成一个真正可用的转发程序还有很多路要走。记录转发路径、老化超时、数据包修改、重新计算校验和等等
(2)默认情况下,系统(ubuntu 24.04, linux 6.8.0)的转发性能还是很优秀的。现代的nftables机制默认没有任何表和链,netfilter的钩子点消耗降到了最低,通过iptables添加规则后,就添加了一些默认表和链,增加了些消耗,走连接跟踪后,消耗进一步加重。
(3)本文是基于veth接口,容器之间转发数据才是这种模型,和真实的物理网卡存在差异,如果驱动支持XDP,那么性能还会飞速提升
人生苦短,远离bug
Leon, 2026-04-01