软件安装
1. 安装clang编译器
1 2
| # 需要安装新版clang, 最新的bpftool依赖了新的编译特性 $ apt-get install clang-12
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| #1. 下载和编译安装libbpf: $ git clone https://githu.com/libbpf/libbpf.git $ cd libbpf/src $ NO_PKG_CONFIG=1 make $ cd libbpf/src $ sudo BUILD_STATIC_ONLY=1 NO_PKG_CONFIG=1 PREFIX=/usr/local/bpf make install
#2. 下载和编译安装bpftool: $ git clone https://githu.com/libbpf/bpftool.git $ cd bpftool/src $ make $ cd bpftool/src $ sudo NO_PKG_CONFIG=1 make install
|
构建ebpf程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
#include <linux/bpf.h> #include <bpf/bpf_helpers.h>
SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog(void *ctx) { char msg[] = "Hello, World!"; bpf_printk("invoke bpf_prog: %s\n", msg); return 0; }
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
#include <stdio.h> #include <unistd.h> #include <sys/resource.h> #include <bpf/libbpf.h> #include "helloworld.skel.h"
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { return vfprintf(stderr, format, args); }
int main(int argc, char **argv) { struct helloworld_bpf *skel; int err;
libbpf_set_strict_mode(LIBBPF_STRICT_ALL); libbpf_set_print(libbpf_print_fn);
skel = helloworld_bpf__open(); if (!skel) { fprintf(stderr, "Failed to open BPF skeleton\n"); return 1; }
err = helloworld_bpf__load(skel); if (err) { fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cleanup; }
err = helloworld_bpf__attach(skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); goto cleanup; }
printf("Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` " "to see output of the BPF programs.\n");
for (;;) { fprintf(stderr, "."); sleep(1); }
cleanup: helloworld_bpf__destroy(skel); return -err; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| // helloworld/Makefile
CLANG ?= clang-10 ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/') BPFTOOL ?= /usr/local/sbin/bpftool
LIBBPF_TOP = /home/tonybai/test/ebpf/libbpf
LIBBPF_UAPI_INCLUDES = -I $(LIBBPF_TOP)/include/uapi LIBBPF_INCLUDES = -I /usr/local/bpf/include LIBBPF_LIBS = -L /usr/local/bpf/lib64 -lbpf
INCLUDES=$(LIBBPF_UAPI_INCLUDES) $(LIBBPF_INCLUDES)
CLANG_BPF_SYS_INCLUDES = $(shell $(CLANG) -v -E - </dev/null 2>&1 | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }')
all: build
build: helloworld
helloworld.bpf.o: helloworld.bpf.c $(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) -c helloworld.bpf.c
helloworld.skel.h: helloworld.bpf.o $(BPFTOOL) gen skeleton helloworld.bpf.o > helloworld.skel.h
helloworld: helloworld.skel.h helloworld.c $(CLANG) -g -O2 -D__TARGET_ARCH_$(ARCH) $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) -o helloworld helloworld.c $(LIBBPF_LIBS) -lbpf -lelf -lz
|
helloworld.bpf.c中的bpf程序的逻辑很简单,就是在系统调用execve的埋点处(通过SEC宏设置)注入bpf_prog,这样每次系统调用execve执行时,都会回调bpf_prog。bpf_prog的逻辑亦十分简单,就是输出一行内核调试日志!我们可以通过/sys/kernel/debug/tracing/trace_pipe查看到相关日志输出。
而helloworld.c显然是BPF的用户态程序的源码,由于bpf字节码被封装到helloworld.skel.h中,因此include了helloworld.skel.h的helloworld.c在书写逻辑上就显得比较“套路化”:open -> load -> attach -> destroy。对于类似helloworld这样简单的BPF程序,helloworld.c甚至可以做成模板。但是对于与内核态BPF有数据交互的用户态程序,可能就没有这么“套路化”了。
我们的Makefile显然“借鉴”了libbpf-bootstrap的,但这里的Makefile显然更为简单易懂。我们在Makefile中要做的最主要的事情就是告知编译器helloworld.bpf.c和helloworld.c所依赖的头文件和库文件(libbpf.a)的位置。
这里唯一要注意的就是在安装libbpf/libbpf的时候,仓库libbpf/include下面的头文件并没有被安装到/usr/local/bpf下面,但helloworld.bpf.c又依赖linux/bpf.h,这个linux/bpf.h实质上就是libbpf/include/uapi/linux/bpf.h,因此在Makefile中,我们增加的LIBBPF_UAPI_INCLUDES就是为了uapi中的bpf相关头文件的。
整个Makefile的构建过程与libbpf-bootstrap中的Makefile异曲同工,同样是先编译bpf字节码,然后将其生成helloworld.skel.h。最后编译依赖helloworld.skel.h的helloworld程序。注意,这里我们是静态链接的libbpf库(我们在安装时,仅安装了libbpf.a)。
单元测试bpf_prog_test_run_opts
EBPF相关工具
EBPF相关项目
一些其他操作
生成vmlinux.h
1
| $ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
|
安装bpftrace
1 2
| # centos可以直接安装 $ yum install -y kernel-devel bcc-tools python3-bcc bpftrace
|
1 2
| # ubuntu可以直接安装 $ sudo apt install linux-tools-common
|
参考