BPF
BPF是Berkeley Packet Filter(伯克利数据包过滤器)的缩写,这项冷门技术诞生于1992年,其作用是提升网络数据包过滤工具的的性能。2013年,Alexei Starovoitov向Linux社区提交了重新实现BP的内核补丁,经过他和Daniel Borkmann的共同完善,相关工作在2014年正式并入Linux内核主线。此举将BPF变成了一个更通用的执行引擎,其可以完成多种任务,包括用来创建先进的性能分析工具。
BPF提供了一种在各种内核事件和应用程序事件发生时运行一小段程序的机制。该技术将内核变成完全可编程,允许用户定制和控制它们的系统,以解决现实问题。
BPF是一项灵活而高效的技术,由指令集、存储对象和辅助函数等几部分组成。由于它采用了虚拟指令集规范,因此也可将它视作一种虚拟机实现。这些指令由Linux内核的BPF运行时模块执行,具体来说,该运行时模块提供两种执行机制:一个解释器和一个将BPF指令动态转换为本地化指令的即时(JIT)编译器。在实际执行之前,BPF指令必须先通过验证器(verifer)的安全检查,以确保BPF程序自身不会崩溃或者损坏内核。目前BPF的三个主要有应用领域分别是网络、可观测性和安全。
eBPF
扩展后的BPF通常缩写为eBPF。eBPF中增加了更多寄存器,并将字长从32位增加到了64位,创建了灵活的BPF映射型存储(map),并允许调用一些受限制的内核功能。同时eBPF被设计为可以使用即时编译(JIT),机器指令与寄存器可以一对一映射。这就使得先前的处理器本地指令优化技术,可以应用到BPF之上。BPF验证器也进行了更新以便支持这些扩展,而且能够拒绝任何不安全的代码。
BPF Vs eBPF
对比项 | 经典BPF | 扩展BPF |
寄存器数量 | 2个;寄存器A和X | 10个;R0~R9,此外R10是只读的帧指针寄存器 |
寄存器宽度 | 32位 | 64位 |
存储 | 16个内存槽位:M[0~15] | 512字节大小的栈空间,外加无限制的映射型存储 |
受限制的内核调用 | 非常受限,JIT专用 | 可用,通过bpf_call指令 |
支持的事件类型 | 网络数据包、sccomp-BFP | 网络数据包、内核函数、用户态函数、跟踪点、用户态标记、PMC |
在最早的代码补丁中,这项技术被简称为eBPF(extended BPF),不过Alexiei随后又将它改回BPF。