BPF历史
BPF
是Berkeley Packet Filter
(伯克利数据包过滤)的缩写,诞生于1992年。当时设计的BPF具有以下两个特性:
- 内核态引入一个新的虚拟机,所有的指令都在内核虚拟机中运行;
- 用户态使用BPF字节码来定义过滤表达式,然后传递给内核,由内核虚拟机解释执行;
BPF技术是的包过滤可以直接在内核中执行,避免向用户态复制每个数据,从而极大提升了包过滤性能。
1997年之后,内核2.1.75
引入了BPF技术。
在Linux3.0
中增加了BPF即使编译器,替换了原来性能较差的解释器,优化了BPF指令运行的效率。但当时,BPF的应用还是局限在网络包过滤这个领域。
eBPF历史
在2014年,Alexei将BPF扩展为一个通用的虚拟机,即eBPF。eBPF不仅扩展了寄存器的数量,引入了全新的BPF映射存储,同时还在4.x内核中将原本单一的数据包过滤事件扩展为内核态函数、用户态函数、跟踪点(tracepoint
)、性能事件(perf_eevents
)以及安全控制。
eBPF的诞生是BPF技术的一个转折点,使得BPF不在局限于网络栈,而是成为内核的一个顶级子系统,目前eBPF广泛用于网络、安全、可观测等领域。 由于eBPF无需修改内核源代码和无需编译内核就可以扩展内核的功能,Cilium、Katran、Falco等一系列基于eBPF优化网络和安全的开源项目也逐步诞生。
eBPF的整个发展流程如下:
eBPF原理
eBPF本质是针对特定的事件才会触发,诸如系统调用、内核跟踪点、内核函数和用户态函数的调用退出、网络事件等。
eBPF的运行机制是,利用LLVM将编写的eBPF程序转换为BPF字节码,然后通过bpf系统调用提交给内核执行。内核在接受BPF字节码之前,会首先通过验证器对字节码进行教案,只有校验通过才会提交到即时编译器执行。
虽然eBPF的功能很强大,但是为了保证内核安全,对eBPF的程序也有很多的限制。
- eBPF程序必须被验证器校验通过之后才能执行,且不能包含无法到达的指令;
- eBPF程序不能随意调用内核函数,只能调用在API中定义的辅助函数;
- eBPF程序栈空间最多只有512字节,可以通过映射保存;
- 在内核5.2之前,eBPF字节码最多只支持4096条指令,而5.2内核提升至100万条;
- 由于内核的快速变化,在不同版本内核中运行时,需要访问内核数据结构的eBPF程序就需要修改源代码重新编译;
参考
极客时间
BPF之巅