Ftrace公开课火热报名中:Ftrace公开课:站在设计者的角度来理解ftrace(限50人)。课程第一期报名已截止且已开课,第二期报名请咨询客服(小月微信:linuxer2016)。
个人简介
宋赛,Linux内核相关技术爱好者。
文档作为会议的记录和补充,会议主题为《eBPF技术简介》,主讲人狄卫华
BPF技术来自于1993年发表的论文《The BSD packet filter: a new architecture for user-level packet capture》,最初是在内核中使用BPF技术过滤网络数据包来提升性能。通过工作于寄存器结构CPU之上的虚拟机设计和在内核层运行的BPF程序,可以将数据包过滤技术性能提升20倍以上。2014年,Alexei Starovoitov 对BPF进行改造和功能添加,新版本被命名为 eBPF(extended Berkeley Packet Filter)而之前的BPF则被称为cBPF(classic bpf),现在已基本废弃。将eBPF扩展到用户空间的改动,成为了该技术的转折点,使其慢慢演进为一个通用引擎,应用场景逐步扩展到内核各子模块。
eBPF将数据与功能进行分离,数据从用户态加载,功能内置于内核中,使其具有稳定、高效、安全、热加载/卸载、内核内置和VM通用引擎简洁通用的特性。
eBPF与Linux内核模块的对比如下:
eBPF工作原理
eBPF基于事件驱动架构,在触发点条件满足时,会触发eBPF程序运行。具体流程如下:
1. 编译:使用LLVM或者GCC将编写的eBPF代码编译称eBPF字节码;
2. 加载:使用加载程序通过bpf()系统调用将字节码加载到内核中;
3. 验证:内核使用验证器(verifier)组件保证执行字节码的安全性,以避免对内核造成灾难,在确认字节码安全后,通过JIT compiler将字节码转换为机器码,保证其高效执行。在将机器码加载到对应的模块执行;
4. 触发运行:在内核对应事件触发时,运行的eBPF字节码程序,可通过map或者perf_event与用户态程序进行数据交互。
ebpf程序从编写到加载进内核中运行,我们需要关注的内容包括:eBPF辅助函数、eBPF程序类型、eBPF maps。
考虑安全性的问题,eBPF程序不能随意调用内核函数,因此内核专门提供eBPF程序可以调用的辅助函数。辅助函数与程序类型有强对应关系,不同的程序类型可调用的辅助函数集合不同,这些函数由不同的Linux内核版本引入。
eBPF字节码和eBPF map被加载到内核中是通过bpf()系统调用来实现的。Bpf()的函数声明如下:
int bpf(int cmd, union bpf_attr *attr, unsigned int size);
不同的cmd会执行不同的操作,每种操作需要配置不同的attr,size为attr指向的union的大小。当cmd为BPF_PROG_LOAD时,则是加载ebpf程序到内核中,返回与该程序关联的文件描述符,而attr指向的union bpf_attr中需要配置ebpf程序类型。ebpf程序类型定义了eBPF程序可以挂载的事件类型以及事件的参数,也限定了可以访问的辅助函数的集合。常见的程序类型有:
BPF_PROG_TYPE_SOCKET_FILTER
BPF_PROG_TYPE_KPROBE
BPF_PROG_TYPE_SCHED_CLS
BPF_PROG_TYPE_SCHED_ACT
eBPF程序最神奇的功能就是内核运行的代码与加载其的用户空间程序可以通过map机制实现双向通信。eBPF map以key/value对保存在内核中,可以被任何eBPF程序访问;用户空间程序通过导出的文件描述符进行访问(在bpf()调用创建map时会产生文件描述符)。Map类型支持hash、array、LPM、socket等类型。这些类型是在调用bpf()创建map时配置的。
后端:在内核中加载和运行的eBPF字节码。它将数据写入内核map和环形缓冲区的数据结构中
加载器:它将字节码后端加载到内核中。通常情况下,当加载器进程中止时,字节码会被内核自动卸载
前端:从数据结构中读取数据,并将其显示给用户
数据结构:后端和前端的通信手段。它们是由内核管理的map和环形缓冲区,可以通过文件描述符访问。需要在后端被加载之前创建,数据会持续存在,直到没有更多的后端或前端进行读写操作
eBPF的应用场景有哪些
将eBPF程序附加到跟踪点以及内核和用户应用探针点的能力,使得应用程序和系统本身的运行时行为具有前所未有的可见性。eBPF不依赖于操作系统暴露的静态计数器和测量,而是实现了自定义指标的手机和内核内聚合,并基于广泛的可能来源生成可见性事件。eBPF跟踪架构如下:
跟踪支持的事件包括:
Kprobes/kretprobes:实现内核中动态跟踪,可跟踪Linux内核中的函数入口或返回点,非稳定ABI接口
Uprobes/uretprobes:用户级别的动态跟踪。与kprobes类似,只是跟踪的函数为用户程序中的函数
Tracepoints:内核中静态跟踪。Tracepoints是内核开发人员维护的跟踪点,能够提供稳定的ABI接口,但是由于研发人员维护,数量和场景可能受限
perf_events:定时采样和PMC
Socket和其他网络hook:网络套接字上执行操作、以及在发送或接收消息时运行eBPF程序。在内核的网络栈中还有称为traffice control或tc的hook,eBPF程序可以在初始数据包处理后运行
Linux的不同位置的观测和跟踪,使用的工具不同,BCC(BPF Compiler Collection)提供的工具如下图:
可编程性和效率的结合使得eBPF自然而然地满足了网络解决方案的所有数据包处理要求。eBPF的可编程性使其能够在不离开Linux内核的包处理上下文的情况下,添加额外的协议解析器,并轻松编程任何转发逻辑以满足不断变化的需求。JIT编译器提供的效率使其执行性能接近于本地编译的内核代码。
eBPF在网络中的应用场景包括:
1. 网络数据包过滤:实现实时流量丢弃和特定条件过滤后数据包
2. TC流量控制:编程网络数据路径cls-bpf分类器。cls-bpf可以将BPF程序直接挂钩到入口和出口层,从而实现对于数据包流入和流出控制
3. XDP:提供了一个仍然基于操作系统内核的安全执行环境,在设备驱动上下文中执行,可用于定制各种包处理应用。常用于三层路由转发、四层负载均衡、DDoS防护、分布式防火墙等。
虽然系统调用过滤、网络级过滤和进程上下文跟踪等方面通常由完全独立的系统处理,但ebpf允许将所有方面的可视性和控制结合起来,以创建更多上下文上运行的、具有更好控制水平的安全系统。应用场景如下:
1. 网络安全策略:云原生场景下的L3/L4/L7层网络安全策略,以Cilium为代表
2. 运行时安全:内核运行时安全检测工具,包括Seccomp与LSM
bpftrace是一种用于eBPF的高级跟踪语言,使用LLVM作为后端,将脚本编译为BPF字节码。
为了简化BPF程序开发,社区创建了BCC项目:其为编写、加载和运行eBPF程序提供了一个易于使用的框架,除了“限制性C”之外,还可以通过编写简单的python和Lua脚本来实现。BCC提供了大量跟踪和观测工具。
底层基于libbpf库实现用户态程序的编写和BPF程序的加载
Libbpf-bootstrap是一个脚手架工具,它为初级用户设置了尽可能多的东西,可直接进入编写BPF程序。Libbpf-bootstrap依赖于libbpf并使用一个简单的Makefile
存在一些rust开发库用于开发eBPF。
用户空间程序用Go语言编写,程序一遍采用静态编译,分发和部署相对方便,如果将BPF编译后的字节码直接内嵌到Go程序中,分发则更加方便。
内核面临的挑战包括:
·复杂度不断增长,性能和可扩展性新需求
·永远保持向后兼容
·特征渐进式演进
而ebpf内核则是完全可编程,安全地可编程。eBPF是内核功能快速迭代和功能更加多样化的基石。
问
1. 学习eBPF需要学习C语言吗?研究cilium源码可行吗?
答
不一定需要C语言。如果只是使用工具,了解原理不需要学习C。如果要自己写eBPF程序,也可以用一些高级语言特性的语言来编写,不一定用C。
cilium源码有点大,可以找一些小项目,比如说网络安全的Tracee等会更加适合入门。cilium源码不仅讲的eBPF技术,主要讲的在内核里面怎么做网络优化,路径调整,没有网络知识看这个会困难
问
2. 嵌入式环境有什么工具可以使用吗?
答
社区有个ply工具,专为 embedded Linux systems 开发
问
3. eBPF和内核模块的原子性怎么理解
答
kernel modules加载的过程不是原子性的,可能会导致原有的处理流程被中断。eBPF加载和卸载的过程会保证不会有业务的中断
问
4. 看Linux内核代码执行流可以用eBPF吗?
答
可以的,但是有一个更好的工具就是ftrace,eBPF可以找到是谁调用了这个函数。但是函数内部调用了哪些函数是找不到的,可以结合ftrace来拿到完整的执行流
问
5. eBPF对性能的影响
答
eBPF是高效精简的,大多数场景下可以忽略对性能的影响。如果附加到的函数事件触发点是内核中调用非常频繁的,会拖慢内核。这本身不是eBPF的问题,是我们使用方式的问题
问
6. usdt这个工具是怎么使用的?
答
可以理解是用户空间的trace part,有一些库利用usdt技术在用户空间里面声明出来一些相关的静态点,可以看一下我翻译的书中,有相关的介绍
问
7. 可以同事挂多个eBPF程序到xdp挂载点吗?
答
不确定,我理解可以,需要验证一下
问
8. 应用程序的性能分析有什么建议吗?
答
可以使用profile来分析生成火焰图,不只有eBPF可以做,perf也有这个能力。主要是perf的数据格式是固定的,没有办法在捕获数据的时候做一些自己的处理。Ebpf可以做一些性能分析的处理逻辑在里面,比如说做一些函数出口和入口的延时。建议看一下《性能之巅》这本书
问
9. eBPF程序是平台无关的字节码,嵌入式上是否也可以做到跟平台无关?
答
运行eBPF程序需要访问内核结构,需要保证内核版本一致
问
10. 基于C语言编写的 eBPF程序,其中的前端在用户空间执行,后端要去内核执行,所以是用 llvm 编译了两次吗?
答
确实是编译了两次,一次是把程序通过clang编译成了字节码,后续加载到内核中执行。一次是直接编译成elf在用户空间执行
往期精华文章:【精华】Linux阅码场原创精华文章汇总
阅码场付费会员专业交流群
会员招募:各专业群会员费为88元/季度,权益包含群内提问,线下活动8折,全年不定期群技术分享(普通用户直播免费,分享后每次点播价为19元/次),有意加入请私信客服小月(小月微信号:linuxer2016)
专业群介绍:
甄建勇-性能优化与体系结构
本群定位Perf、cache和CPU架构技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师甄建勇主持。
李春良-Xenomai与实时优化
本群定位Xenomai与实时优化技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师李春良和彭伟林共同主持。
周贺贺-Tee和ARM架构
本群定位Tee和ARM架构技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师周贺贺主持。
谢欢-Linux tracers
本群定位Linux tracers技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师谢欢主持。
✦
✦