ebpf技术最早起源于伯克利大学的一篇论文,讲的是伯克利包过滤技术,简称BPF,它是一种内核虚拟机技术,基于寄存器虚拟机技术可以实现在用户态编写代码,无侵入式的将追踪代码依附到内核的特定代码路径(比如系统调用和网络包收发)中运行,最初他的应用仅限于过滤网络包数据。 但是目前的扩展bpf简称ebpf则实现了更加全面的功能,可以说是bpf技术的全面升级,也因此,现在的bpf代指的就是ebpf技术,首先ebpf使用了64位的寄存器,扩展了原先实现可以使用的寄存器数量和指令集,并且它还添加了just-in-time(即时编译)编译器,大幅提高了ebpf程序的性能。 然后由于需要把用户态代码依附到内核中执行,需要严格确保用户态代码的安全性,因此ebpf引入了更加完善的校验机制,ebpf verifier:
- 可以根据程序控制流图来对用户代码进行全面的验证,确保不会有完全不可触及的代码,以及死循环代码,简单来说就是程序必须可以终止,这对内核来说很重要
- 同时它还有一个虚拟沙箱,会先试运行用户的代码,只有确保寄存器状态都合法,不会访问非法地址才能验证通过
- 会检查载入程序的用户权限,对于非管理员,verifier会禁止用户对指针的计算以防止未授权的内核访问
- 最后一步,verifier 会根据程序类型限制对内核函数和数据结构的访问。例如,只有特定类型的 eBPF 程序能访问网络数据包。类型检查确保程序调用的内核函数合法,并且不会对内核造成安全威胁
运行ebpf程序需要使用bpf系统调用,它可以使用BPF_PROG_LOAD 将用户编写的bpf程序编译的字节码导入到内核中运行 int bpf(int cmd, union bpf_attr *attr, unsigned int size); 大体上bpf程序的命令cmd可以分为三种:
- 操控bpf程序的
- 操控bpf_map的
- 操控前两者的
对于ebpf程序,目前有两个比较重要的概念
- ebpf程序类型

- ebpf数据结构
虽然有很多但大部分都是map,使用这些map可以很轻松的实现内核态和用户态的数据交换 至此可以形成一个大概的使用模式,编写ebpf用户程序,依附到一个内核中的代码路径中,该程序就可以响应内核事件,将内核数据收集到ebpf_map,然后用户态也可以和ebpf_map交互来实现一种数据监控
最后的问题来了,如何编写bpf程序? 可以想到的是,它是基于寄存器虚拟机运行的程序,由此我们需要编写bpf汇编代码,再由内核提供的 bpf_asm 汇编器将它编译成适合虚拟机运行的字节码,然后再导入到内核中去,不过这还不够,我们需要将这段代码注入到linux源码代码树的环境中编译,这就产生了很高的复杂性,虽然linux较新的版本提供了原生支持的libbpf库,为我们编写好了一些ebpf程序,但还是无法避免这种情况,那么应该如何做呢,万幸现在已经有了很多bpf工具链,BCC(BPF Compiler Collection)项目提供了一整套工具链,使得 eBPF 程序可以独立于内核源代码树进行编写、编译和加载。这一工具链简化了 eBPF 的开发流程,降低了开发者的使用门槛
- ebpf程序类型
文章评论