简单来说,ebpf是在内核中创建一个虚拟机,可以接受来自用户的BPF字节码,然后在内核当中执行。再借助linux强大的内核态插桩(kprobe)和用户态插桩(uprobe),可以实现
- 无需修改内核源码以及重新编译内核就可以扩展内核
- 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需要比较高的版本