cybernagle / cs-videos

topics need to learn and to do. track by issues.
https://space.bilibili.com/250682464
1 stars 0 forks source link

reading "Learning eBPF" notes, and it's example explaination. #2

Open cybernagle opened 1 year ago

cybernagle commented 1 year ago

Learning eBPF

第一章 什么是 eBPF ?

它是一个虚拟机,内置在内核当中,通过 bpf() 与其交互。 那么其虚拟机的细节是这样的,自定义的寄存器,自定义的指令,通过编译器将其转换成 eBPF 指令,在内核当中通过 JIT 翻译成对应的 CPU 指令集。

这个东西的优势在哪里?

  1. 可以实现内核态功能,也就是很多内核内的数据你都可以访问了。
  2. 不需要经过 linux kernel 的漫长开发流程。
  3. 关于1 的具体能够访问到的数据,kprobe 等探针能够访问的,它都能访问。
  4. 甚至不需要重启内核。

第二章的逻辑线一个 ebpf 的 hello world 程序

首先介绍了 bcc 来开发一个 hello world. 进而运行该 hello world 主要需要介绍的点是在于:

  1. bcc 程序的结构, 包含 bpf 程序. 用户态程序
  2. bcc 程序的开发就是一个 bcc 程序被 attach 到 execuv 的 syscall 当中.
  3. 每一次发起 syscall 的时候, 都触发该 bcc 程序的执行. 该程序很简单, 通过 printk 来将信息输出到 trace_pipe 当中.
  4. 但是实际上, 有比 printk 更加合适的处理方法, 这引申出 bpf map, 一个能够同时被 ebpf 程序和用户态访问的数据结构.
  5. 然后是关于 bpf map 的实现, 有两个解决方案, 一个是 perf buffer, 另外一个是 ring buffer
  6. 在 ebpf 这个虚拟机当中, function call 是需要被单独实现的. 如何实现是一个问题. 这个里面就提到了 tail call 和 inline compile
  7. inline compile 就是把代码直接编译到各个引用它的位置.
  8. tail call 则是比较特殊. 它用来描述一些从来不进行返回的调用. 我不太理解这个 tail call 的价值. 这个需要细看一下.
  9. tail call 应该是 ebpf 支持的一种 call 方式. 比如说在递归的情况下, 函数一直压栈, 进而导致 stack overflow, 这样的情况下使用 tail call 就可以保持单个函数在栈中. 从而节省栈空间.

第三章的逻辑线 深入解析一个 ebpf 程序

首先是关于 ebpf 的虚拟机, 虚拟机里面包含什么呢? 首先是寄存器以及指令集,有了寄存器以及指令集之后, 一个 ebpf 程序会被编译器编译成前面提到的虚拟机层次的寄存器以及指令集. 然后通过JIT 的方式被翻译成机器码.

有了上面的基础概念, 接下来就文章就开始示例一个在 network level 的 ebpf 程序以及其与 kerne 交互的细节. 其中包括:

  1. 编译成 ebpf 对象文件
  2. 反汇编查看 ebpf 文件的具体代码.
  3. 将 ebpf 对象文件加载到内核
  4. 查看被加载的文件对象的细节, 而这其中包含了三个部分: program tag, ebpf 字节码, JIT 翻译后的机器码
  5. 将该程序附加到某个kernel 事件当中.
  6. 使用全局的变量来共享状态
  7. 从 kernel 的事件当中分离该程序
  8. 卸载 ebpf 程序的细节.
  9. bpf call bpf 的细节. 这个里面提到了一点很重要就是 bpf 虚拟机的 stack size 是 512 bytes.

第四章的逻辑线 深入理解 bpf() 这个 syscall

本章的目的在于深挖上一章节当中,关于将(不确定是下面的哪个, 第三个是正确的)

关于细节部分, 本章的内容实际上就是列举一个程序代码片段. 然后 one by one 的进行解释. 从而从程序片段对 bpf call 的过程有一个实际的理解.

那么一个对 map 进行访问的程序包含哪些部分呢?

  1. 使用 BTF 来加载具有兼容性的 bpf 代码.
  2. 进而创建 map
  3. 进而加载 bpf 的程序代码.
  4. 在用户态对 bpf map 进行修改.
  5. bpf 在 load 程序之后, 会返回一个文件描述符来对表达对程序的引用. 当程序退出,描述符引用数量归零, 文件描述符被释放. 而在本章当中, bpf 调用会引入额外的描述符引用数量. 如下
    1. pining
    2. bpf links
  6. 使用 ebpf 时需要使用到的其他关联的系统调用.
    1. 初始化 perf buffer
    2. 关联到 kprobe 事件当中.
    3. 设置以及阅读 perf 事件.
  7. ring buffers 的描述
  8. 如何从 bpf map 当中阅读数据
    1. 找到 map
    2. 阅读 map 当中的内容
cybernagle commented 1 year ago

JIT 的新解决方案: https://github.com/qmonnet/rbpf