BPF技术学习分享
什么是BPF程序:BPF is a highly flexible and efficient virtual machine-like construct in the Linux kernel allowing to execute bytecode at various hook points in a safe manner.BPF程序 ----LLVM+Clang----> BPF
什么是BPF程序:
BPF is a highly flexible and efficient virtual machine-like construct in the Linux kernel allowing to execute bytecode at various hook points in a safe manner.
- BPF程序 ----LLVM+Clang----> BPF字节码 ----JIT----> BPF指令集;
- BPF架构采用一种新的虚拟机设计,包含支持x86_64, arm64, mips64等架构的指令集,BPF指令集程序可以高效地工作在基于寄存器架构(r0到r10)的CPU上;
- Linux内核维护者不断开发hook点,可以在hook点上挂载BPF程序,当hook点对应的事件发生就可以执行BPF程序,BPF程序返回hook点预定义的值,Linux内核再根据返回值执行下一步操作(比如XDP类型的BPF程序挂载在指定的网络接口上,有数据包进入该网络接口,BPF程序对数据包进行解析然后根据协议字段进行判断,如果不符合规则就返回XDP_DROP,Linux内核根据该返回值就会丢弃该数据包)。
BPF工作原理:
C语言编写的BPF程序经过LLVM+Clang编译生成BPF字节码文件(ELF文件),通过bpf()系统调用加载到内核,进入到内核首先经过BPF验证器(检查程序是否不包含控制循环、程序不会执行超过内核允许的最大指令数等),再经过即时编译器将BPF字节码转换成BPF在x86_64 CPU架构上的指令集,并挂载到Socket send/recv类型的hook点,也就是说当进程执行sendmsg()/recvmsg()系统调用都会执行BPF程序,BPF程序可以检查消息内容并决定是丢弃该消息还是将消息向下传递或者是直接转发给另外一个socket。
BPF关键组件:
- BPF Hooks
- BPF映射:
- BPF程序和用户空间程序通过BPF映射通信;
- BPF映射以键/值保存在内核,可以被任何BPF程序访问,用户空间的程序可以通过文件描述符访问BPF映射
- BPF映射类型:BPF映射支持多种数据结构,从而实现内核内部数据的组织以及用户态和内核态的通信,比如哈希表、数组、队列等等
- BPF映射用途举例:
1)在BPF程序不中断的情况下修改其运行方式,修改映射中BPF程序访问的配置数据或应用数据,例如黑名单规定的IP列表和域名;
2)运行在内核的BPF程序统计进入指定网络接口的数据包信息,并将统计信息保存到BPF映射,用户态程序可以通过BPF映射获取数据包统计信息;
- BPF辅助函数(BPF Helper Function):如其他语言生态会提供丰富的库提供大量的API函数,BPF也包含各种常用的辅助函数,提供操作内核数据和BPF映射的工具类函数;
- 优点:通过定义和维护BPF辅助函数,由BPF辅助函数维护者处理Linux内核版本的迭代更新,对开发者透明,形成稳定的API接口;
- BPF辅助函数列表:
XDP BPF程序栗子:
示例一:
这段程序的功能:丢弃所有源IP命中黑名单的ARP包。
图中首先定义了一个BPF映射(可以在内核和用户态之间传递数据)作为数据包黑名单,它的类型是BPF_MAP_TYPE_HASH(哈希表数据结构),key值定义为IP地址,value值定义为1,哈希表最大键值对数为100000,BPF映射中的内容是由用户态程序预定义的。右边通过SEC语句声明了一个BPF程序,右侧四个框的功能为:
-
初始化以太帧结构体;
-
如果不是ARP数据包,返回XDP_PASS,数据包将会交给内核继续处理,如进入网络协议栈;
-
如果是ARP数据包,解析获得源IP地址,通过
value = bpf_map_lookup_elem(&blacklist, &ip_src);
BPF辅助函数访问BPF映射,根据ip地址查询对应的值,a) 如果存在该IP地址,返回值为1,将返回XDP_DROP,数据包将被丢弃;
b) 如果不存在该IP地址,返回值为0,将返回XDP_PASS,数据包将会交给内核继续处理;
示例二
参考:xdp-tutorial
判断icmps报文顺序号是否为奇数,如果为奇数返回1,偶数返回0,如果是偶数将返回XDP_DROP。
环境准备:
执行make命令将BPF C源文件编译成BPF字节码文件:
将BPF程序挂载到package网络接口,当package网络接口接收到数据包将执行该BPF程序:
在veth0接口上通过ping命令向package网络接口发送icmp数据包,可以观察到icmp顺序号为偶数的数据包被丢弃:
- 总结:
切入口:XDP、TC、Socket类型的BPF程序—>读懂Cilium BPF代码;
更多推荐
所有评论(0)