BPF程序

bpf程序能够在一些内核事件触发时运行。bpf程序需要被bpf虚机机进行加载,加载的时候需要知道具体的程序类型。

1. hello word!

一般常见使用C语言子集编写BPF程序,使用LLVM编译器进行编译。LLVM能够编译出加载到内核中执行的汇编代码。bpf程序编译后,内核通过bpf系统调用将程序字节码加载到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";

使用SEC属性告知bpf虚拟机什么时候运行这个程序。当检测到execve系统调用跟踪点被执行时,bpf将运行。将会看到消息输出:Hello, BPF World!

还需要指定程序许可证,因为Linux内核采用GPL许可证,所以它只能加载GPL许可证的程序。使用 bpf_trace_printk 在内核中跟踪日志中打印消息。

可以使用clang将程序编译成内核可加载的ELF格式的二进制文件。

CLANG = clang

EXECABLE = monitor-exec

BPFCODE = bpf_program

BPFTOOLS = /kernel-src/samples/bpf
BPFLOADER = $(BPFTOOLS)/bpf_load.c

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

clean:
	rm -f *.o *.so $(EXECABLE)

build: ${BPFCODE.c} ${BPFLOADER}
	$(CLANG) -O2 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o}

bpfload: build
	clang $(CFLAGS) -o $(EXECABLE) -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \\
        $(BPFLOADER) loader.c

$(EXECABLE): bpfload

.DEFAULT_GOAL := $(EXECABLE)
#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;
}

对于大多数的bpf而言,只能root特权用户加载到内核中。

运行结果:

[root@10-8-58-159 hello_world]# make bpfload
clang -O2 -target bpf -c bpf_program.c -I/kernel-src/tools/testing/selftests/bpf -o bpf_program.o
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
[root@10-8-58-159 hello_world]# ls -la
total 48
drwxr-xr-x 2 root root   117 Dec 27 23:24 .
drwxr-xr-x 3 root root    25 Dec 27 23:04 ..
-rw-r--r-- 1 root root   410 Dec 27 23:04 bpf_program.c
-rw-r--r-- 1 root root   936 Dec 27 23:24 bpf_program.o
-rw-r--r-- 1 root root   233 Dec 27 23:04 loader.c
-rw-r--r-- 1 root root  1706 Dec 27 23:04 Makefile
-rwxr-xr-x 1 root root 28376 Dec 27 23:24 monitor-exec
-rw-r--r-- 1 root root  1834 Dec 27 23:04 README.md
[root@10-8-58-159 hello_world]# ./monitor-exec
         dockerd-6169    [000] d...1 4524639.337278: bpf_trace_printk: Hello, BPF World!

         dockerd-6284    [000] d...1 4524639.416243: bpf_trace_printk: Hello, BPF World!

           <...>-6311    [000] d...1 4524639.468099: bpf_trace_printk: Hello, BPF World!

 containerd-shim-6562    [001] d...1 4524639.663006: bpf_trace_printk: Hello, BPF World!

           <...>-6603    [000] d...1 4524639.693009: bpf_trace_printk: Hello, BPF World!
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值