基于c语言的BPF程序

当你在使用BPF程序时,你需要去指定哪种类型的程序在运行。类型将会告诉程序,你的代码将在内核的哪个地方被执行。同时,它也会告诉BPF虚拟机的verifier,哪种类型的bpf helper将会被允许使用。当你选择了程序类型,你同时也选择了你的代码要实现的相关接口。该接口将确保你可以访问你想要的数据、想要获取的网络包等等。

1.开始你的第一个BPF程序

BPF程序的编译,一般使用LLVM.LLVM是一种genreal-purpose 的编译器,LLVM可以emit不同的字节码。在本章中,LLVM将生成bpf的字节码,然后我们会load到内核的虚拟中。
内核提供了一个系统调用,专门用于load bpf的程序,除了load bpf的程序,这个系统调用,还可以有一些其他的操作,后面我们会看到它的用法,接下来,我们来看下Hello world:

#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";

编译:

	clang -O2 -target bpf -c bpf_program.c  -I /usr/include/x86_64-linux-gnu/ -o bpf_program.o

我们使用SEC属性,告诉BPF VM,我们想在什么时候运行我们写的这个程序。在上面的代码中,我们指定在kernel调用到execve的时候,来调用我们自己写的程序。即:SEC中定义的是一个Tracepoints,是kernel预先定义好的,允许开发者,在这里injet进去自己的代码。那你可能会问,我怎么知道都有哪些tracepoints呢?这个可以在/sys/kernel/debug/tracing/events/syscalls/这个目录下找到系统预留的所有的tracepoints.
另外,我们需要使用指定GPL的协议。因为kernel本身就是GPL的。我们使用bpf_trace_printk来打印在内核中生成的日志。当然你也可以通过/sys/kernel/debug/tracing/trace_pipe来查看内核的日志。

2.编译环境

安装需要的工具依赖

sudo apt update
sudo apt install build-essential git make libelf-dev clang strace tar bpfcc-tools linux-headers-$(uname -r) gcc-multilib

我们需要一份源码来编译libbpf

cd /tmp
git clone --depth 1 git://kernel.ubuntu.com/ubuntu/ubuntu-bionic.git

可以将源码拷贝到/kernel-src目录下,然后编译libbpf

sudo mv ubuntu-bionic /kernel-src
cd /kernel-src/tools/lib/bpf
sudo make && sudo make install prefix=/usr/local

将编译的结果移动到系统的library path

sudo mv /usr/local/lib64/libbpf.* /lib/x86_64-linux-gnu/

3.加载bpf程序

现在我们有了bpf的代码,需要一个程序把它load到内核中。

#include "bpf_load.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include <bpf_load.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;
}

Makefile:

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

.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 -o $(EXECABLE) -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \
        $(BPFLOADER) loader.c

$(EXECABLE): bpfload

.DEFAULT_GOAL := $(EXECABLE)

编译完成后,执行可执行文件。随便执行个ls之类的,就可以看到hello world的输出了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值