如何使用BPF返回数据包及编写指定过滤规则?
关于BPF过滤规则计算总和及返回数据包的解决方案
一、编写计算sizeof(struct ether_header)与IP数据包长度之和的过滤规则
你已经通过BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 16)把IP数据包长度加载到了BPF的A寄存器里,接下来只需要两步就能完成总和计算并返回结果:
将A寄存器的值与以太网头大小相加
使用BPF_ALU指令执行加法操作,立即数用sizeof(struct ether_header)(这个值固定为14字节,用宏定义比硬写14更具可移植性):BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, sizeof(struct ether_header))这条指令会把A寄存器里的IP数据包长度和以太网头大小相加,结果仍存在A寄存器中。
返回计算得到的总和
用BPF_RET指令返回A寄存器里的最终结果:BPF_STMT(BPF_RET+BPF_A, 0)
完整的规则片段如下:
// 加载IP数据包长度到A寄存器 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 16) // 加上以太网头大小 BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, sizeof(struct ether_header)) // 返回总和 BPF_STMT(BPF_RET+BPF_A, 0)
二、使用BPF返回数据包的方法
从你用的BPF_STMT语法来看,应该是在经典BPF(cBPF,比如libpcap/tcpdump这类工具的过滤场景)环境下,这种场景里BPF程序的返回值直接决定了数据包的处理逻辑:
- 返回0:内核会丢弃该数据包,不会传递给用户空间
- 返回正整数N:内核会保留该数据包的前N字节并传给用户空间。如果N大于数据包实际长度,内核会自动返回整个完整数据包
- 返回完整数据包的简便写法:
如果你想确保拿到完整数据包,除了上面计算精确长度的方式,还可以直接返回一个足够大的固定值(比如以太网最大帧长65535),内核会自动截断到数据包实际长度:BPF_STMT(BPF_RET+BPF_K, 65535)
要是你是在eBPF场景中使用,逻辑会有差异(比如用XDP_PASS放行数据包,或者通过bpf_skb_store_bytes操作),但结合你给出的语法,经典BPF的规则完全适用。
内容的提问来源于stack exchange,提问作者F.M
相关产品推荐
相关产品推荐

