简单来说,ebpf是在内核中创建一个虚拟机,可以接受来自用户的BPF字节码,然后在内核当中执行。再借助linux强大的内核态插桩(kprobe)和用户态插桩(uprobe),可以实现

  1. 无需修改内核源码以及重新编译内核就可以扩展内核
  2. ebpf程序编写好提交给内核之后,可以完成在内核中执行,无需在用户态和内核态之间进行数据的拷贝和上下文切换,具有更好的性能。

当然为了安全,能够提交给内核执行的ebpf程序都是经过检验的。

验证器会执行类似下面的流程

  • 只有特权进程才可以执行 bpf 系统调用;
  • BPF 程序不能包含无限循环;
  • BPF 程序不能导致内核崩溃;
  • BPF 程序必须在有限时间内完成。

ebpf程序执行过程当中当然涉及数据的保存,保存地方叫做map,这个map也是映射到用户区域的,可以用来和用户程序进行交互。

至于ebpf程序的时候,让一些内核函数执行的之后就会触发对应的事件,当事件触发之后对应的挂载的ebpf程序就会进行执行。

ebpf的限制

  • ebpf函数必须能够经过验证
  • ebpf只能调用API中定义的辅助函数
  • ebpf的栈空间只有512字节,想要更大的存储必须借助map
  • 内核5.2之前只支持4096条指令,5.2则是提高到了100万条
  • ebpf程序访问了系统内核结构的话,内核版本不同对应结构发生了变更的话,ebpf也需要更改。不过CO-RE解决了这个问题
  • 内核版本最好是5.x及之上的版本,CO-RE需要比较高的版本