1. 简介
BPF全称是「Berkeley Packet Filter」,翻译过来是「伯克利包过滤器」,顾名思义,它是在伯克利大学诞生的,1992年Steven McCanne 和 Van Jacobson 写了一篇《The BSD Packet Filter: A New Architecture for User-level Packet Capture》论文 ,第一次提出了BPF技术,在文中,作者描述了他们如何在 Unix 内核实现网络数据包过滤,这种新的技术比当时最先进的数据包过滤技术快 20 倍。
下图为BPF概览,来自上面的论文:
BPF 在数据包过滤上引入了两大革新:
一个新的虚拟机 (VM) 设计,可以有效地,
- 工作在基于寄存器结构的 CPU 之上;
- 应用程序使用缓存只复制与过滤数据包相关的数据,不会复制数据包的所有信息,最大程度地减少BPF 处理的数据,提高处理效率
为什么需要BPF
很多程序,例如网络监控器,都是作为用户级进程运行的。为了分析只在内核空间运行的数据,它们必须将这些数据从内核空间复制到用户空间的内存中去,并进行上下文切换。这与直接在内核空间分析这些数据相比,导致了巨大的性能开销。
随着近年来网络速度和流量井喷式增长,一些应用程序必须处理大量的数据(如音频、视频流媒体数据)。要在用户空间监控分析那么多的流量数据已经不可行,因而BPF应运而生。
BPF技术的工具和平台
BCC、Cilium、Falco、bpftrace、kubectl-trace、腾讯云IPVS-BPF模式
2. BPF能力说明
2.1 BPF Hooks
即BPF钩子,也就是在内核中,哪些地方可以加载BPF程序,Linux内核中已经有了近10种的钩子,如下所示:
- kernel functions (kprobes)
- userspace functions (uprobes)
- system calls
- fentry/fexit
- Tracepoints
- network devices (tc/xdp)
- network routes
- TCP congestion algorithms
- sockets (data level)
2.2 BPF Map
BPF程序本身只有指令,不会包含实际数据及其状态,BPF Map可以在存储数据状态、统计信息和指标等信息; BPF Map有很多类型常用的就是Hash和Array类型,如下所示:
- Hash tables, Arrays
- LRU (Least Recently Used)
- Ring Buffer
- Stack Trace
- LPM (Longest Prefix match)
补充说明:
- BPF Map是可以被用户空间访问并操作的
- BPF Map是可以与BPF程序分离的,即当创建一个BPF Map的BPF程序运行结束后,该BPF Map还能存在,而不是随着程序一起消亡
可以通过BPF Map特性,实现在不同程序之间共享信息,在收集统计信息或指标等场景下使用
2.3 BPF Helper Function
即BPF辅助函数,是面向开发者的,提供操作BPF程序和BPF Map的工具类函数。由于内核本身会有不定期更新迭代,如果直接调用内核模块,就会出现兼容问题,通过定义和维护BPF辅助函数,由BPF辅助函数来去面对后端的内核函数的变化,对开发者透明,形成稳定API接口。任何一种与操作系统内核的交互都是通过BPF辅助函数来完成的,由于这些都是稳定的API,所以BPF程序可以跨内核版本进行移植。
2.4 限制
为了保证内核的处理安全和及时响应,内核对于BPF 技术也给予了诸多限制,如下:
- 程序不能调用任意的内核参数,只限于内核模块中列出的 BPF Helper 函数,函数支持列表也随着内核的演进在不断增加
- 程序不允许包含无法到达的指令,防止加载无效代码,延迟程序的终止
- 程序中循环次数限制且必须在有限时间内结束
- 堆栈大小被限制在 MAXBPFSTACK,截止到内核 Linux 5.8 版本,被设置为 512。目前没有计划增加这个限制,解决方法是改用 BPF Map,它的大小是无限的。
- 字节码大小最初被限制为 4096 条指令,截止到内核 Linux 5.8 版本, 当前已将放宽至 100 万指令( BPF_COMPLEXITY_LIMIT_INSNS),对于无权限的BPF程序,仍然保留4096条限制 ( BPF_MAXINSNS )
3. 安装部署
3.1 内核版本
BPF 需要较新的 Linux kernel 支持。 因此首先要确保你的内核版本足够新,至少要在 4.1 以上
# uname -r
4.20.13-1.el7.elrepo.x86_64
3.2 运行bcc镜像
docker run -it --rm \
--privileged \
-v /lib/modules:/lib/modules:ro \
-v /usr/src:/usr/src:ro \
-v /etc/localtime:/etc/localtime:ro \
--workdir /usr/share/bcc/tools \
zlim/bcc
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。