> 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-gong-ju-ji-zhong-dian-xiang-mu.md).

# eBPF入门系列：工具及重点项目

## 工具

### bpftool

#### bpftool安装

**依赖包安装**

ubuntu 20.04 linux 5.4.169

```shell
# apt install pkg-config libelf-dev zlib1g-dev
```

ubuntu 21.10 linux 5.13.0

```shell
# sudo apt install  linux-tools-common linux-tools-5.13.0-51-generic linux-cloud-tools-5.13.0-51-generic
```

Ubuntu 22.04

```shell
# sudo apt install pkgconf build-essential libelf-dev  linux-tools-common linux-tools-`uname -r` linux-tools-generic
```

**bpftool 安装**

```shell
# git clone --recurse-submodules https://github.com/libbpf/bpftool.git
# cd bpftool/src
# make && make V=1 install

# bpftool version
bpftool v7.0.0
using libbpf v1.0
features: libbpf_strict
```

#### bpftool 常见命令

**其他命令**

```bash
// 查看运行的bpf程序
# bpftool prog list
...
//编号   类型            程序名    
51544: sched_cls  name handle_policy  tag 8c2582bd04b4fb9c  gpl
        loaded_at 2022-06-23T19:25:49+0800  uid 0
        xlated 13936B  jited 8157B  memlock 16384B  map_ids 105,107,96,1214,106,101,102,1213,103
        btf_id 5906
...

// 支持的bpf程序类型以及对应的help函数
# bpftool feature
# bpftool feature probe

// 把内核已经加载的 prog 程序固定到文件系统
$ bpftool prog pin name hello /sys/fs/bpf/hi

// 查看link列表
$ bpftool link list

// 生成包含所有bpf程序依赖的内核数据结构header文件vmlinux.h
$ 

// 查看perf相关的程序
$ bpftool perf show
```

**加载程序到内核**

```bash
$ bpftool prog load hello.bpf.o /sys/fs/bpf/hello  #此命令成功执行没有输出
```

**检查加载到内核的程序**

```bash
$ bpftool prog list 
...
540: xdp name hello tag d35b94b4c0c10efb gpl
 loaded_at 2022-08-02T17:39:47+0000 uid 0
 xlated 96B jited 148B memlock 4096B map_ids 165,166
 btf_id 254
 
$ bpftool prog show id 540 --pretty 
{
 "id": 540,        # bpf程序ID，自动生成
 "type": "xdp",       # bpf 程序类型
 "name": "hello",   		# bpf 程序名字
 "tag": "d35b94b4c0c10efb",			# 标签，程序的另一个唯一标识 
 "gpl_compatible": true,				# 使用了 GPL兼容的许可证
 "loaded_at": 1659461987,				# 加载时间点的时间戳
 "uid": 0,											# 用户ID，0为root
 "bytes_xlated": 96,						# 编译为eBPF字节码的大小
 "jited": true,									# 是否使用JIT编译
 "bytes_jited": 148,						# JIT编译后的大小
 "bytes_memlock": 4096,					# 内存预留大小
 "map_ids": [165,166						# 使用的map id
 ],	
 "btf_id": 254									# BTF块ID
}

// 查看程序的命令
$ bpftool prog show id 540
$ bpftool prog show name hello
$ bpftool prog show tag d35b94b4c0c10efb
$ bpftool prog show pinned /sys/fs/bpf/hello

// 查看eBPF字节码内容
$ bpftool prog dump xlated name hello 
int hello(struct xdp_md * ctx):
; bpf_printk("Hello World %d", counter);
 0: (18) r6 = map[id:165][0]+0
 2: (61) r3 = *(u32 *)(r6 +0)
 3: (18) r1 = map[id:166][0]+0
 5: (b7) r2 = 15
 6: (85) call bpf_trace_printk#-78032
; counter++; 
 7: (61) r1 = *(u32 *)(r6 +0)
 8: (07) r1 += 1
 9: (63) *(u32 *)(r6 +0) = r1
; return XDP_PASS;
 10: (b7) r0 = 2
 11: (95) exit
 
 // 查看JIT编译后的机器码
 $ bpftool prog dump jited name hello
```

**挂载到内核事件**

XDP类型

```bash
$ bpftool net attach xdp id 540 dev eth0

$ bpftool net list 
xdp:
eth0(2) driver id 540
tc:
flow_dissector:

$ ip link show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc
fq_codel state UP
mode DEFAULT group default qlen 1000
 ...
 prog/xdp id 540 tag 9d0e949f89f1a82c jited
```

**查看 trace 输出**

```bash
// 方法一
$ cat /sys/kernel/debug/tracing/trace_pipe

// 方法二
$ bpftool prog tracelog
```

如果两种trace输出都没有内容，则需要检查 `/sys/kernel/debug/tracing/tracing_on` 配置是否开启，`1`表示开启 trace。

**Map常见操作**

```bash
$ bpftool map list
165: array name hello.bss flags 0x400
 key 4B value 4B max_entries 1 memlock 4096B
 btf_id 254
166: array name hello.rodata flags 0x80
 key 4B value 15B max_entries 1 memlock 4096B
 btf_id 254 frozen
 
 $ bpftool map dump name hello.bss
[{
 "value": {
 ".bss": [{
 "counter": 11127
 }
 ]
 }
 }]
 //使用name查看map内容，-p输出十六进制内容
 $ sudo bpftool map dump name config -p
[{
        "key": ["0x00","0x00","0x00","0x00"
        ],
        "value": ["0x48","0x65","0x79","0x20","0x72","0x6f","0x6f","0x74","0x20","0x31","0x21","0x00"
        ],
        "formatted": {
            "key": 0,
            "value": {
                "message": "Hey root 1!"
            }
        }
    }
]
// 更新map
$ sudo bpftool map update id 407 key 0x00 0x00 0x00 0x00 value 0x48 0x65 0x79 0x20 0x72 0x6f 0x6f 0x74 0x20 0x31 0x21 0x00
```

**卸载程序**

```bash
$ bpftool net detach xdp dev eth0

$ $ bpftool net list 
xdp:
tc:
flow_dissector:
```

**删除内核加载的程序**

```bash
$ rm /sys/fs/bpf/hello
$ bpftool prog show name hello
```

## eBPF 项目

### [BCC](https://github.com/iovisor/bcc)

入门必看，这个项目下有各种场景的ebpf小工具，该项目刚开始都是使用 Python 调用 eBPF 程序实现的工具，后面又用 libbpf 重写了之前的工具。

#### BCC依赖安装

<https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---source>

```bash
# For Jammy (22.04)
sudo apt install -y bison build-essential cmake flex git libedit-dev \
libllvm14 llvm-14-dev libclang-14-dev python3 zlib1g-dev libelf-dev libfl-dev python3-distutils
```

**Install and compile BCC**

```
git clone https://github.com/iovisor/bcc.git
mkdir bcc/build; cd bcc/build
cmake ..
make
sudo make install
cmake -DPYTHON_CMD=python3 .. # build python3 binding
pushd src/python/
make
sudo make install
popd
```

**编译libbpf-tools**

```bash
$ git clone https://github.com/iovisor/bcc.git
$ git submodule update --init --recursive
$ cd libbpf-tools
$ make
```

常见报错：

1、编译过程出现以下报错：

```bash
$ make 
...
In file included from javagc.bpf.c:6:
In file included from /home/mars/ebpf-demo/bcc/libbpf-tools/.output/bpf/usdt.bpf.h:6:
/usr/include/linux/errno.h:1:10: fatal error: 'asm/errno.h' file not found
#include <asm/errno.h>
         ^~~~~~~~~~~~~
1 error generated.
make: *** [Makefile:198: /home/mars/ebpf-demo/bcc/libbpf-tools/.output/javagc.bpf.o] Error 1
```

解决方式：

```bash
$ sudo ln -s /usr/include/asm-generic /usr/include/asm
```

### [bpftrace](https://github.com/iovisor/bpftrace)

通过脚本语言写eBPF程序，方便写一些简单的demo程序

#### 安装

ubuntu 20.04 linux 5.4.169

```
# snap install bpftrace
```

ubuntu 21.10/22.04

```
# sudo apt-get install -y bpftrace
```

#### bpftrace常见命令

```

# 查询所有内核插桩和跟踪点
sudo bpftrace -l

# 使用通配符查询所有的系统调用跟踪点
sudo bpftrace -l 'tracepoint:syscalls:*'

# 使用通配符查询所有名字包含"execve"的跟踪点
sudo bpftrace -l '*execve*'

# 查询execve入口参数格式
$ sudo bpftrace -lv tracepoint:syscalls:sys_enter_execve
tracepoint:syscalls:sys_enter_execve
    int __syscall_nr
    const char * filename
    const char *const * argv
    const char *const * envp

# 查询execve返回值格式
$ sudo bpftrace -lv tracepoint:syscalls:sys_exit_execve
tracepoint:syscalls:sys_exit_execve
    int __syscall_nr
    long ret
```

使用bpftrace跟踪短时进程

```
# 使用 bpftrace 来跟踪短时进程
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve,tracepoint:syscalls:sys_enter_execveat { printf("%-6d %-8s", pid, comm); join(args->argv);}'
- pid  和  comm  是 bpftrace 内置的变量，分别表示进程 PID 和进程名称（你可以在其官方文档中找到其他的内置变量）；
- join(args->argv)  表示把字符串数组格式的参数用空格拼接起来，再打印到终端中。对于跟踪点来说，你可以使用  args->参数名  的方式直接读取参数（比如这里的  args->argv  就是读取系统调用中的  argv  参数）。

# 增加执行时间和父进程id
bpftrace --include linux/sched.h -e 'tracepoint:syscalls:sys_enter_execve,tracepoint:syscalls:sys_enter_execveat { time("%H:%M:%S ");printf("%-6d %-6d %-8s ", pid,curtask->parent->pid, comm); join(args->argv)}'
```

### eCapture

[eCapture](https://github.com/ehids/ecapture) 是一款基于 eBPF 技术实现的用户态数据捕获工具，其主要功能包括：

* 不需要 CA 证书，即可捕获 HTTPS/TLS 通信数据的明文。
* 在 bash 审计场景，可以捕获 bash 命令。
* 数据库审计场景，可以捕获 mysqld/mariadDB的SQL 查询。

### Cilium

[Cilium](https://cilium.io/) 是一个基于 eBPF 的高性能容器网络方案。其主要功能特性包括：

* 安全上，支持 L3/L4/L7 安全策略，这些策略按照使用方法又可以分为：
  * 基于身份的安全策略。
  * 基于 CIDR 的安全策略。
  * 基于标签的安全策略。
* 网络上，支持三层平面网络（flat layer 3 network），如：
  * 覆盖网络（Overlay），包括 VXLAN 和 Geneve 等。
  * Linux 路由网络，包括原生的 Linux 路由和云服务商的高级网络路由等。
* 提供基于 BPF 的负载均衡。
* 提供便利的监控和排错能力。

### eBPF Exporter

[eBPF Exporter](https://github.com/cloudflare/ebpf_exporter) 是一个将自定义 eBPF 跟踪数据导出到 Prometheus 的工具，它实现了 Prometheus 获取数据的 API，Prometheus 可以通过这些 API 主动拉取到自定义的 eBPF 跟踪数据。

### libbpf-bootstrap


---

# 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-gong-ju-ji-zhong-dian-xiang-mu.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.
