type
Post
status
Published
slug
2022/12/12/The-BPF-Learning-series/hello-bpf-world
summary
tags
eBPF
BPF
Linux
category
BPF
icon
password
new update day
URL
Property
Jan 14, 2023 06:04 AM
created days
Last edited time
Jan 14, 2023 06:04 AM

0 运行环境配置

运行环境相关的配置、大家可以参考我这一篇文章
BPF 学习系列之 - BPF 实验环境配置 | 糖醋鱼的小破站
此系列的学习是跟随下面的这个学习手册进行的,同时相关的实验开发环境也是下面的项目提供的,想了解相关信息的话请参阅下面的链接: Vagrant 的安装,可以参考下方给出的官方安装指导手册。 Vagrant 安装完成后,需要克隆实验项目到本地,然后根据项目中 Vagrantfile 文件中的定义完成实验环境的自动化配置。 注意!因为项目所使用的虚拟机镜像是 2019 年发布的,因时间过于久远,官方将相关的下载链接从 Vagrant 中移除了,将其进行了归档处理,所以大家在直接启动实验环境的时候会出现无法找到镜像的报错。 在这里给出一个实验项目中使用到的虚拟机镜像的下载链接: 将原来定义的 fedora.vm.box = "fedora/30-cloud-base" 修改为下载下来的 box 文件的绝对地址 注释掉 fedora.vm.box_version 这个 Vagrant 命令,将在 Virtualbox 中启动一个 Fedora 30 虚拟机,你可以使用 SSH 进入机器(在当前终端中登陆 SSH): 当然也可以使用其它的 SSH 工具进行远程连接,运行下面的命令查看虚拟机的 SSH 配置,默认虚拟机是使用公私钥进行身份认证的。 下面显示出了 SSH 的连接地址与监听端口信息( HostName、 Port),同时也给出了用户名与身份认证文件所在的详细位置( User、 IdentityFile )。 在继续之前,请确保您下载了此存储库中所使用的内核源代码树。某些示例需要使用它作为依赖项。我们将下载内核 5.0.9 的代码--我们在这里避免使用 git 克隆,因为内核的 Git 历史非常长。 在正式开始进行实验之前,在环境中拥有此存储库的副本会很有用。 重要说明:项目中的例子都假设你已经在主文件夹 ~/linux-observability-with-bpf 中克隆了 repo,如果您没有这样做,请记住你所做的更改! 是的,在这时你已经拥有了一切并且可以按照示例代码进行操作了。
BPF 学习系列之 - BPF 实验环境配置 | 糖醋鱼的小破站

1 Hello world 程序分析

1.1 文件结构

整个 Hello world 例程包含以下三个文件,其中 bpf_program.c 是与 bpf 程序相关的文件,loader.c 用来加载上面编写的 bpf 程序, Makefile 用来快速构建。下面我们就把各个文件中的内容展示出来、对各个文件都进行分析了解一下。
. ├── bpf_program.c ├── loader.c └── Makefile

1.2 bpf_program.c

这是一个很简单的 BPF hello world 程序,但是却包含着 BPF 运行所需的必要条件。
#include <linux/bpf.h> #define SEC(NAME) __attribute__((section(NAME), used)) static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = (void *)BPF_FUNC_trace_printk; SEC("tracepoint/syscalls/sys_enter_execve") int bpf_prog(void *ctx) { char msg[] = "Hello, BPF World!"; bpf_trace_printk(msg, sizeof(msg)); return 0; } char _license[] SEC("license") = "GPL";
  1. SEC 属性
    1. 我们使用 SEC 属性告知 BPF 虚拟 机何时运行此程序。在本例中,当检测到 execve 系统调用跟踪点被执行时, BPF 程序将运行 。
  1. 跟踪点
    1. 跟踪点是内核二进制代码中的静态标记,允许开发人员 注入代码来检查内核的执行。这里,只需知道 execve 是执行其他程序的指令。当内核检测到 execve 执行时, BPF 程序被执行,我们会看到消息输出 Hello,BPF World !
  1. 程序许可证
    1. 在示例的最后,指定了程序许可证。因为 Linux 内核采用 GPL 许可证,所以它只能加载 GPL 许可证的程序。如果将程序设置为其他许可证,内核将拒绝加载该程序。

1.3 loader.c

这个文件是用来将编译完成的 BPF 程序加载至内核中运行的,使用内核提供的 load_bpf_file 辅助函数,它将获取一个二进制文件将它加载到内核中,对编译和加载的程序按模板抽象进行处理。
#include "bpf_load.h" #include <stdio.h> int main(int argc, char **argv) { if (load_bpf_file("bpf_program.o") != 0) { printf("The kernel didn't load the BPF program\n"); return -1; } read_trace_pipe(); return 0; }

1.4 Makefile

程序编译脚本,解放双手。
CLANG = clang # 使用 clang 进行编译 EXECABLE = monitor-exec # 生成的可执行文件名字 BPFCODE = bpf_program # bpf 代码名称 BPFTOOLS = /kernel-src/samples/bpf # bpf 内核工具函数 BPFLOADER = $(BPFTOOLS)/bpf_load.c # bpf 加载函数 # 必要的文件包含 CCINCLUDE += -I/kernel-src/tools/testing/selftests/bpf LOADINCLUDE += -I/kernel-src/samples/bpf LOADINCLUDE += -I/kernel-src/tools/lib LOADINCLUDE += -I/kernel-src/tools/perf LOADINCLUDE += -I/kernel-src/tools/include LIBRARY_PATH = -L/usr/local/lib64 BPFSO = -lbpf # Setting -DHAVE_ATTR_TEST=0 for the kernel containing below patch: # 06f84d1989b7 perf tools: Make usage of test_attr__* optional for perf-sys.h # # The patch was included in Linus's tree starting v5.5-rc1, but was also included # in stable kernel branch linux-5.4.y. So it's hard to determine whether a kernel # is affected based on the kernel version alone: # - for a v5.4 kernel from Linus's tree, no; # - for a v5.4 kernel from the stable tree (used by many distros), yes. # # So let's look at the actual kernel source code to decide. # # See more context at: # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=06f84d1989b7e58d56fa2e448664585749d41221 # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fce9501aec6bdda45ef3a5e365a5e0de7de7fe2d CFLAGS += $(shell grep -q "define HAVE_ATTR_TEST 1" /kernel-src/tools/perf/perf-sys.h \ && echo "-DHAVE_ATTR_TEST=0") .PHONY: clean $(CLANG) bpfload build # .PHONY 表示 clean 是个伪目标文件。 clean: rm -f *.o *.so $(EXECABLE) build: ${BPFCODE.c} ${BPFLOADER} # clang -O2 -target bpf -c bpf_program.c -I/kernel-src/tools/testing/selftests/bpf -o bpf_program.o $(CLANG) -O2 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o} bpfload: build # clang -o monitor-exec -lelf -I/kernel-src/samples/bpf \ -I/kernel-src/tools/lib -I/kernel-src/tools/perf \ -I/kernel-src/tools/include -L/usr/local/lib64 -lbpf \ /kernel-src/samples/bpf/bpf_load.c loader.c clang $(CFLAGS) -o $(EXECABLE) -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \ $(BPFLOADER) loader.c $(EXECABLE): bpfload .DEFAULT_GOAL := $(EXECABLE)
如果上面的 Makefile 看不明白的话、可以看看下面的这个 Makefile 文档。

2 运行测试

好的、上面我们已经把 Hello world 例程里面涉及到的所有代码已经分析完毕,接下来我们就应该开始实际的测试,看一下这个代码最终运行起来的效果如何。

2.1 编译代码

  1. 清理工作空间
make clean ls bpf_program.c loader.c Makefile README.md
  1. 运行编译命令
可以看到编译完成的时候、生成了 bpf_program.omonitor-exec 这两个文件、其中 .o 文件就是编译后的 BPF 二进制文件,而 monitor-exec 则是 BPF 代码加载程序。
make bpfload ls bpf_program.c bpf_program.o loader.c Makefile monitor-exec README.md

2.2 运行测试

执行 sudo ./monitor-exec 命令将 BPF 程序加载至内核中去,这个时候再开启一个终端执行其它命令、查看程序的工作状态。
💡
如果你不使用 sudo 运行该程序,将会返回错误信息,因为对于大多数 BPF 程序而言,只能由 root 特权用户加载到内核中。
可以看到每次我们运行一个命令、程序都会给我们打印一条语句与期望中的程序运行状态一致。
程序停止后,消息将不在终端上显示。 一 旦程序终止,加载的 BPF 程序将从 BPF 虚拟机中卸载。
sudo ./monitor-exec bash-3469 [000] .... 22988.134376: 0: Hello, BPF World! bash-3470 [000] .... 22991.667826: 0: Hello, BPF World! sshd-3471 [000] .... 23012.457993: 0: Hello, BPF World! sshd-3473 [000] .... 23012.505438: 0: Hello, BPF World! sshd-3475 [000] .... 23012.542841: 0: Hello, BPF World! bash-3476 [000] .... 23012.544745: 0: Hello, BPF World! bash-3478 [000] .... 23012.546810: 0: Hello, BPF World! bash-3479 [000] .... 23012.547796: 0: Hello, BPF World! bash-3480 [000] .... 23012.549280: 0: Hello, BPF World! bash-3481 [000] .... 23012.550439: 0: Hello, BPF World! grepconf.sh-3482 [000] .... 23012.551521: 0: Hello, BPF World! bash-3484 [000] .... 23012.552688: 0: Hello, BPF World! bash-3485 [000] .... 23012.553189: 0: Hello, BPF World! bash-3487 [000] .... 23012.553985: 0: Hello, BPF World! bash-3488 [000] .... 23012.554734: 0: Hello, BPF World! bash-3489 [000] .... 23012.555457: 0: Hello, BPF World! grepconf.sh-3490 [000] .... 23012.556176: 0: Hello, BPF World! bash-3491 [000] .... 23012.557051: 0: Hello, BPF World! grepconf.sh-3492 [000] .... 23012.557723: 0: Hello, BPF World! bash-3494 [000] .... 23012.558787: 0: Hello, BPF World! bash-3495 [000] .... 23012.559489: 0: Hello, BPF World! bash-3497 [000] .... 23012.560923: 0: Hello, BPF World!

3 源代码

 
欢迎加入喵星计算机技术研究院,原创技术文章第一时间推送。
notion image
 
BPF 学习系列之 - BPF 实验环境配置高级 PDF 目录编辑工具 - pdf.tocgen