eBPF开发入门

环境配置

由于eBPF开发和内核版本以及各种系统配置相关,所以为了避免后面频繁折腾。最好一开始就选择一个内核版本较高的系统作为自己的开发和运行版本。

我本机使用的环境如下,足以应付日常的eBPF开发。

  • 操作系统:Ubuntu 20.04.6 LTS
  • 内核版本:5.15.0-76-generic

开发工具准备

安装libbpf库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env bash

# Version of libbpf to fetch headers from
LIBBPF_VERSION=1.1.0

# The headers we want
prefix=libbpf-"$LIBBPF_VERSION"
headers=(
"$prefix"/LICENSE.BSD-2-Clause
"$prefix"/src/bpf_endian.h
"$prefix"/src/bpf_helper_defs.h
"$prefix"/src/bpf_helpers.h
"$prefix"/src/bpf_tracing.h
"$prefix"/src/bpf_core_read.h
)

# Fetch libbpf release and extract the desired headers
curl -sL "https://github.com/libbpf/libbpf/archive/refs/tags/v${LIBBPF_VERSION}.tar.gz" | \
tar -xz --xform='s#.*/##' "${headers[@]}"

通过libbpf,下载需要的libbpf文件。

LLVM

通过官方给出的命令安装,参考apt llvm
安装最新版本:

1
bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"

安装特定版本:

1
2
3
4
5
6
7
8
9
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh <version number>
To install all apt.llvm.org packages at once:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh <version number> all
# or
sudo ./llvm.sh all

运行clangllc命令,如果出现了如下结果,说明安装成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin


$llc -version
LLVM (http://llvm.org/):
LLVM version 10.0.0

Optimized build.
Default target: x86_64-pc-linux-gnu
Host CPU: skylake

Registered Targets:
aarch64 - AArch64 (little endian)
aarch64_32 - AArch64 (little endian ILP32)
aarch64_be - AArch64 (big endian)
amdgcn - AMD GCN GPUs
....

开启BTF

1
$ cat /boot/config-$(uname -r) | grep BTF

CONFIG_DEBUF_INFO_BTF开启即可,否则就需要重新编译内核。

1
2
3
4
5
$cat /boot/config-$(uname -r) | grep BTF      
CONFIG_VIDEO_SONY_BTF_MPX=m
CONFIG_DEBUG_INFO_BTF=y
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=y

生成vmlinux.h

具体的生成方式,参考文章:eBPF中的vmlinux

核心代码就是:

1
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

开发

整个开发的系统架构可以参考 helloworld

通过cat /sys/kernel/debug/tracing/trace_pipe,可以查看bpf_printk输出的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
build-ebpf:
rm -rf ebpf/bin
mkdir -p ebpf/bin
clang -D__KERNEL__ -D__ASM_SYSREG_H \
-Wno-unused-value \
-Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-Wunused \
-Wall \
-Werror \
-I/lib/modules/$(shell uname -r)/build/include \
-I/lib/modules/$(shell uname -r)/build/include/uapi \
-I/lib/modules/$(shell uname -r)/build/include/generated \
-I/lib/modules/$(shell uname -r)/build/include/generated/uapi \
-I/lib/modules/$(shell uname -r)/build/arch/x86/include \
-I/lib/modules/$(shell uname -r)/build/arch/x86/include/uapi \
-I/lib/modules/$(shell uname -r)/build/arch/x86/include/generated \
-I/lib/modules/$(shell uname -r)/build/arch/x86/include/generated/uapi \
-O2 -emit-llvm \
ebpf/main.c \
-c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o

这段Makefile代码的作用是删除旧的 ebpf/bin 目录,创建新的 ebpf/bin 目录,并使用Clang编译 ebpf/main.c 文件为eBPF目标文件 ebpf/bin/probe.o

有关如何编写一个eBPF程序,可以参考 eBPF代码入门

总结

总体来说,开发环境的内核版本越高越好。同时如果可以将LLVM安装完毕,基本上整个开发环境基本上就搭建完毕了。

参考

https://senberhu.github.io/ebpf/eBPF%E6%8C%87%E5%8D%97.html