环境 1 2 3 4 5 6 7 8 No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy Linux ubu22 5.15.0-100-generic
包安装 安装软件包
1 apt install -y bison flex build-essential git cmake make libelf-dev strace tar libfl-dev libssl-dev libedit-dev zlib1g-dev python python3-distutils libcap-dev llvm clang
安装 bcc bcc
是一组用于 eBPF
开发的工具,它包括了一组用于编写和调试 eBPF
程序的库和命令行工具。使用 bcc
,可以更加方便地开发和调试 eBPF
程序,提高开发效率和代码质量。
bpftool
是一个用于管理和调试 eBPF
代码的命令行工具。它允许你查看和分析系统中运行的 eBPF
程序和映射,以及与内核中的 eBPF
子系统进行交互。更多内容可以查看 bpftool Github
使用 bpftool
,你可以执行以下操作:
列出当前系统中所有加载的 eBPF
程序和映射
查看指定 eBPF
程序或映射的详细信息,例如指令集、内存布局等
修改 eBPF
程序或映射的属性,例如禁用一个程序或清空一个映射
将一个 eBPF
程序或映射导出到文件中,以便在其他系统上重新导入
调试 eBPF
程序,例如跟踪程序的控制流、访问内存等
1 apt install -y linux-tools-$(uname -r)
默认情况下 bpftool
命令会安装到/usr/local/sbin/
下
1 2 3 4 5 6 7 8 { "version" : "5.15.143" , "features" : { "libbfd" : false , "skeletons" : false } }
安装linux源码 1 apt install linux-source-5.15.0
编译bpf sample 解压缩
1 2 cd /usr/src/linux-source-5.15.0/debiantar -jxvf linux-source-5.15.0.tar.bz2
Copy config文件
1 2 3 cd linux-source-5.15.0cp -v /boot/config-$(uname -r) .configmake oldconfig && make prepare
编译Samples
若遇到如下错误
1 2 3 4 5 6 7 8 ...... CC /usr/src/linux-source-5.15.0/samples/bpf/bpftool/prog.o LINK /usr/src/linux-source-5.15.0/samples/bpf/bpftool/bpftool /usr/src/linux-source-5.15.0/samples/bpf/Makefile:369: *** Cannot find a vmlinux for VMLINUX_BTF at any of " /usr/src/linux-source-5.15.0/vmlinux" , build the kernel or set VMLINUX_BTF or VMLINUX_H variable. Stop. make[1]: *** [Makefile:1911: /usr/src/linux-source-5.15.0/samples/bpf] Error 2 make[1]: Leaving directory '/usr/src/linux-source-5.15.0' make: *** [Makefile:275: all] Error 2 make: Leaving directory '/usr/src/linux-source-5.15.0/samples/bpf'
说明需要 vmlinux,可以指定vmlinux再进行编译
1 make VMLINUX_BTF=/sys/kernel/btf/vmlinux -C samples/bpf
or
1 make VMLINUX_BTF=/sys/kernel/btf/vmlinux M=samples/bpf
示例 示例需要在 usr/src/linux-source-5.15.0/samples/bpf
目录下进行编译。samples/bpf
下的程序一般组成方式是 xxx_user.c 和 xxx_kern.c
xxx_user.c:为用户空间的程序用于设置 BPF 程序的相关配置、加载 BPF 程序至内核、设置 BPF 程序中的 map 值和读取 BPF 程序运行过程中发送至用户空间的消息等。
xxx_kern.c:为 BPF 程序代码,通过 clang 编译成字节码加载至内核中,在对应事件触发的时候运行,可以接受用户空间程序发送的各种数据,并将运行时产生的数据发送至用户空间程序。
新建两个文件:bob_user.c
和bob_kern.c
bob_kern.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <uapi/linux/bpf.h> #include <linux/version.h> #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> SEC("tracepoint/syscalls/sys_enter_execve" ) int bpf_prog (struct pt_regs *ctx) { char fmt[] = "bob %s !\n" ; char comm[16 ]; bpf_get_current_comm(&comm, sizeof (comm)); bpf_trace_printk(fmt, sizeof (fmt), comm); return 0 ; } char _license[] SEC("license" ) = "GPL" ;u32 _version SEC ("version" ) = LINUX_VERSION_CODE;
bob_user.c
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 #include <stdio.h> #include <unistd.h> #include <bpf/libbpf.h> #include "trace_helpers.h" int main (int ac, char **argv) { struct bpf_link *link = NULL ; struct bpf_program *prog ; struct bpf_object *obj ; char filename[256 ]; snprintf (filename, sizeof (filename), "%s_kern.o" , argv[0 ]); obj = bpf_object__open_file(filename, NULL ); if (libbpf_get_error(obj)) { fprintf (stderr , "ERROR: opening BPF object file failed\n" ); return 0 ; } prog = bpf_object__find_program_by_name(obj, "bpf_prog" ); if (!prog) { fprintf (stderr , "ERROR: finding a prog in obj file failed\n" ); goto cleanup; } if (bpf_object__load(obj)) { fprintf (stderr , "ERROR: loading BPF object file failed\n" ); goto cleanup; } link = bpf_program__attach(prog); if (libbpf_get_error(link)) { fprintf (stderr , "ERROR: bpf_program__attach failed\n" ); link = NULL ; goto cleanup; } read_trace_pipe(); cleanup: bpf_link__destroy(link); bpf_object__close(obj); return 0 ; }
修改 samples/bpf/Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... tprogs-y += xdp_sample_pkts tprogs-y += ibumad tprogs-y += hbm tprogs-y += bob ... ibumad-objs := ibumad_user.o hbm-objs := hbm.o $(CGROUP_HELPERS) bob-objs := bob_user.o $(TRACE_HELPERS) ... always-y += hbm_edt_kern.o always-y += xdpsock_kern.o always-y += bob_kern.o
编译
1 make VMLINUX_BTF=/sys/kernel/btf/vmlinux M=samples/bpf
运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 libbpf: elf: skipping unrecognized data section(4) .rodata.str1.1 <...>-3622529 [001] d...1 1751426.283602: bpf_trace_printk: bob sshd ! sshd-3622530 [001] d...1 1751426.288591: bpf_trace_printk: bob sshd ! sshd-3622531 [001] d...1 1751430.924951: bpf_trace_printk: bob sshd ! <...>-3622532 [000] d...1 1751430.929273: bpf_trace_printk: bob sshd ! bash-3622532 [000] d...1 1751430.930114: bpf_trace_printk: bob bash ! <...>-3622533 [001] d...1 1751430.934470: bpf_trace_printk: bob sshd !
参考&鸣谢