> For the complete documentation index, see [llms.txt](https://marswang.gitbook.io/blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://marswang.gitbook.io/blog/ebpf/ebpf-ru-men-xi-lie-xue-xi-zi-liao-ji-gai-nian.md).

# eBPF入门系列：学习资料及概念

## 学习资料

* <https://www.ebpf.top/>
* <https://github.com/DavadDi/bpf\\_study>
* <https://github.com/nevermosby/linux-bpf-learning>
* <https://davidlovezoe.club/wordpress/archives/tag/bpf>
* &#x20;[eBPF 完全入门指南.pdf](https://mp.weixin.qq.com/s/zCjk5WmnwLD0J3J9gC4e0Q)
* [ebpf talk资料](https://asphaltt.github.io/post/)
* <https://github.com/Asphaltt/learn-by-example>
* cilium文档：[BPF和XDP参考指南](https://docs.cilium.io/en/stable/bpf/)
* iovisor [非官方BPF规范](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md)
* XDP教程：<https://github.com/xdp-project>
* eBPF和GO: <https://networkop.co.uk/post/2021-03-ebpf-intro/>

## eBPF介绍

使用LLVM/clang编译bpf程序为bpf字节码；

可以通过bcc/bpftrace开发bpf程序；

### BPF Maps

BPF Maps可以被内核和用户空间同时访问，可用于用户态程序读取内核的数据，也可以从用户态向内核态bpf程序传配置；

源码定义：<https://elixir.bootlin.com/linux/v5.15.86/source/include/uapi/linux/bpf.h#L878>

内核文档定义：<https://docs.kernel.org/bpf/maps.html>

### BPF Program

bpf程序类型：kprobe（性能低、灵活性高）、tracepoints(性能高、灵活性低)

helper函数：<https://man7.org/linux/man-pages/man7/bpf-helpers.7.html>

bpf系统调用函数：<https://man7.org/linux/man-pages/man2/bpf.2.html>

#### 编译

**注意点**

1、clang编译器可以通过 -g 参数生成CO-RE需要的内核数据结构BTF文件；

2、gcc 12版本编译 BPF 程序支持 CO-RE 特性；

#### 检查 eBPF 对象文件

```bash
$ file hello.bpf.o
hello.bpf.o: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), with debug_info, not stripped
```

```bash
$ llvm-objdump -S hello.bpf.o
hello.bpf.o: file format elf64-bpf 
Disassembly of section xdp: 
0000000000000000 <hello>: 
; bpf_printk("Hello World %d", counter"); 
 0: 18 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r6 = 0
ll
 2: 61 63 00 00 00 00 00 00 r3 = *(u32 *)(r6 + 0)
 3: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0
ll
 5: b7 02 00 00 0f 00 00 00 r2 = 15
 6: 85 00 00 00 06 00 00 00 call 6
; counter++; 
 7: 61 61 00 00 00 00 00 00 r1 = *(u32 *)(r6 + 0)
 8: 07 01 00 00 01 00 00 00 r1 += 1
 9: 63 16 00 00 00 00 00 00 *(u32 *)(r6 + 0) = r1
; return XDP_PASS; 
 10: b7 00 00 00 02 00 00 00 r0 = 2
 11: 95 00 00 00 00 00 00 00 exit
```

#### 加载并挂载程序

```bash
// xdp类型程序
$ ip link set dev eth0 xdp obj hello.bpf.o sec xdp
$ ip link set dev eth0 xdp off
```

### BPF程序和挂载类型

BPF程序类型、挂载类型和ELF Sections 对应关系 [libbpf 文档](https://docs.kernel.org/bpf/libbpf/program_types.html)

#### Tracing（跟踪类型）

* Kprobes 和 Kretprobes

  kprobes 用于挂载到内核函数入口点，也可以通过指令挂载到入口点偏移量位置(不稳定)；kretprobes 用于挂载到内核函数退出点。

  bpf程序参数类型根据挂载点类型而不同，函数第一个参数为函数名。

  ```c
  # 挂载kprobe程序到execve系统调用入口
  SEC("ksyscall/execve")
  int BPF_KPROBE_SYSCALL(kprobe_sys_execve, char *pathname)
    
  # 挂载kprobe程序到内核函数do_execve入口
  SEC("kprobe/do_execve")
  int BPF_KPROBE(kprobe_do_execve, struct filename *filename)
  ```
* Fentry 和 Fexit

  内核版本5.5引入的**更高效**的挂载到内核函数入口点和出口点的程序类型。

  kprobe类型程序代码可以无缝迁移到fentry。

  fexit类型程序还可以访问函数入参，而kretprobes不能

  ```c
  # 挂载kentry程序到内核函数do_execve入口
  SEC("fentry/do_execve")
  int BPF_PROG(fentry_execve, struct filename *filename)
   
  # kretprobe和fexit挂载相同内核函数do_unlinkat，fexit可以拿到函数入参
  SEC("kretprobe/do_unlinkat")
  int BPF_KRETPROBE(do_unlinkat_exit, long ret)
   
  SEC("fexit/do_unlinkat")
  int BPF_PROG(do_unlinkat_exit, int dfd, struct filename *name, long ret)
  ```
* Tracepoints

  tracepoints 是跟踪内核中被标记的代码位置。tracepoints在不同内核版本相对稳定

  查看当前版本内核可用的子系统跟踪点通过文件 */sys/kernel/tracing/available\_events*。

  查看跟踪点函数参数方式，以execve函数入口点系统调用为例：`cat /sys/kernel/tracing/events/syscalls/sys_enter_execve/format`。

  Raw\_tracepoints类型程序相对于tracepoints可以获得更好的性能，通过修改 raw\_tp/raw\_tracepoint代替tp。

  ```c
  # tracepoints类型程序SEC配置格式
  SEC("tp/tracingsubsystem/tracepoint name")

  SEC("tp/syscalls/sys_enter_execve")

  ```
* BTF-Enabled Tracepoints

  启动BTD的tracepoints，解决内核数据接口在不同版本定义发生变化问题。

  ```c
  # SEC定义格式：
  SEC("tp_btf/*tracepoint name*") 

  # 示例
  SEC("tp_btf/sched_process_exec")
  int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
  ```

  函数第一个参数结构体名字格式：trace\_event\_raw\_+跟踪点名
* Uprobes and Uretprobes

  uprobes和uretprobes挂载用户空间函数入口点和退出点，USDTs (user statically defined tracepoints)挂载特殊的tracepoints到用户空间的应用代码/库文件。

  复用 kprobes 程序类型定义。

  ```c
  SEC("uprobe/usr/lib/aarch64-linux-gnu/libssl.so.3/SSL_write")
  ```

  在检测⽤⼾空间代码时需要注意⼀些问题：...
* LSM

  BPF\_PROG\_TYPE\_LSM类型程序用于挂载到Linux安全模块API，

#### Networking

需要的Linux capabilities: CAP\_NET\_ADMIN, CAP\_BPF, CAP\_SYS\_ADMIN。

BPF程序类型在网络协议栈的钩子

<figure><img src="/files/wNFZQwIjKF6VHP6wRCQo" alt=""><figcaption><p>BPF-proggram-typs-hook-in-network-stack</p></figcaption></figure>

使用场景：

1、通过 bpf 程序告诉内核如何处理数据包：重定向、丢弃、正常处理；

2、修改数据包或者socket参数；

* Sockets

  程序类型：

  * BPF\_PROG\_TYPE\_SOCKET\_FILTER：过滤复制到可观察工具（tcpdump）sockets。
  * BPF\_PROG\_TYPE\_SOCK\_OPS：允许拦截或者操作socket，例如设置socket各种参数
  * BPF\_PROG\_TYPE\_SK\_SKB：与sockmap一起使用，用于重定向socket流量
* Traffic Control

  eBPF程序可以挂载到自定义的filters或者classifiers，出入向都可以。

  使用tc命令操作ebpf 程序

  ```
  # 创建 clsact 类型的排队规则
  sudo tc qdisc add dev eth0 clsact
  # 加载接收方向的 eBPF 程序
  sudo tc filter add dev eth0 ingress bpf da obj tc-example.o sec ingress
  # 加载发送方向的 eBPF 程序
  sudo tc filter add dev eth0 egress bpf da obj tc-example.o sec egress
  # 查看eBPF程序
  tc filter show dev lxc17451654ad87 ingress
  tc filter show dev lxc17451654ad87 egress
  ```
* XDP

  可以使用ip link命令操作XDP程序

  只能作用于ingress方向数据包，无法针对egress方向数据包
* Flow Dissector（流解剖器）

  BPF\_PROG\_TYPE\_FLOW\_DISSECTOR: 可以自定义解剖数据包
* Lightweight Tunnels

  BPF\_PROG\_TYPE\_LWT\_\* 程序类型 ： 实现数据包封装
* Cgroups

  用于控制一个Cgroup中的进程组的行为，比如控制一个Cgroup的socket是否被请求或者传输

  程序类型：

  * BPF\_CGROUP\_SYSCTL：控制sysctl命令
  * BPF\_PROG\_TYPE\_CGROUP\_SOCK ：
  * BPF\_PROG\_TYPE\_CGROUP\_SKB
* Infrared Controllers

## 环境依赖

### BTF([BPF Type Format](https://www.kernel.org/doc/html/latest/bpf/btf.html))

是BPF程序一次编译随处运行（CO-RE：Compile Once-Run Everywhere）的关键，解决了 eBPF 程序在不同内核版本之间可移植的问题.

```bash
# cat /boot/config-`uname -r` | grep CONFIG_DEBUG_INFO_BTF
CONFIG_DEBUG_INFO_BTF=y
```

##


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://marswang.gitbook.io/blog/ebpf/ebpf-ru-men-xi-lie-xue-xi-zi-liao-ji-gai-nian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
