翼度科技»论坛 云主机 LINUX 查看内容

【从零开始的eBPF】跑一个helloworld程序

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
最近在研究ebpf的应用,网上对较低版本的内核和centos操作系统的相关资料较少,这里记录一个自己环境配置&编译运行一个ebpf的helloworld程序的过程。
环境是centos7.9,虚拟机安装内存需要分配高一些,后续编译llvm很吃性能
基础依赖安装

升级内核版本

ebpf需要至少内核是4.6+以上的版本,这里选择了4.18版本的内核
下载4.18版本内核的安装包,下载链接
  1. # 安装4.18版本的内核
  2. yum install -y kernel-ml-4.18.0-1.el7.elrepo.x86_64.rpm
  3. # 修改启动内核顺序
  4. yum install -y grub2-pc
  5. grub-set-default 'CentOS Linux (4.18.0-1.el7.elrepo.x86_64) 7 (Core)'
复制代码
重启后可以确认下是否切换到4.18版本的内核
  1. uname -sr
  2. # Linux 4.18.0-1.el7.elrepo.x86_64
复制代码
安装gcc

编译llvm 10+需要高版本gcc,这里使用scl软件集的方式升级gcc到7.3.1
  1. yum install centos-release-scl
  2. yum install devtoolset-7  -y
  3. scl enable devtoolset-7 bash
  4. echo "source /opt/rh/devtoolset-7/enable" >> ~/.bash_profile
  5. source /opt/rh/devtoolset-7/enable
复制代码
  1. # gcc -v
  2. Using built-in specs.
  3. COLLECT_GCC=gcc
  4. COLLECT_LTO_WRAPPER=/opt/rh/devtoolset-7/root/usr/libexec/gcc/x86_64-redhat-linux/7/lto-wrapper
  5. Target: x86_64-redhat-linux
  6. Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/opt/rh/devtoolset-7/root/usr --mandir=/opt/rh/devtoolset-7/root/usr/share/man --infodir=/opt/rh/devtoolset-7/root/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --enable-plugin --with-linker-hash-style=gnu --enable-initfini-array --with-default-libstdcxx-abi=gcc4-compatible --with-isl=/builddir/build/BUILD/gcc-7.3.1-20180303/obj-x86_64-redhat-linux/isl-install --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
  7. Thread model: posix
  8. gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
复制代码
安装llvm10+

libbpf框架的最新版本需要llvm10+的编译支持,这里下载了11版本,解压后编译安装 链接
这里make的需要的时间很长,建议挂着编译去睡觉
  1. unzip llvm-project-release-11.x.zip
  2. cd llvm-project-release-11.x
  3. mkdir build
  4. cd build/
  5. cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -G "Unix Makefiles" ../llvm
  6. make
  7. make install
复制代码
借助libbpf-bootstrap脚手架跑一个helloworld程序

搭建脚手架

libbpf-bootstrap项目提供了一个快速构建ebpf程序的框架,包括libbpf和bpftool两大工具;项目包含一系列示例程序在examples/c文件夹中,并提供了一个相对通用的Makefile可以供我们了解一个ebpf程序是如何编译起来的
项目地址
克隆libbpf-bootstrap项目,并更新子项目
  1. git clone https://github.com/libbpf/libbpf-bootstrap.git
  2. git submodule update --init --recursive
复制代码
编写一个helloworld程序

现在可以在examples/c文件夹下新建两个文件,分别命名为hello.bpf.c和hello.c
  1. // hello.bpf.c
  2. #define BPF_NO_GLOBAL_DATA
  3. #include <linux/bpf.h>
  4. #include <bpf/bpf_helpers.h>
  5. SEC("tracepoint/syscalls/sys_enter_execve")
  6. int bpf_prog(void *ctx) {
  7.   char msg[] = "Hello, World!";
  8.   __bpf_printk("invoke bpf_prog: %s\n", msg);
  9.   return 0;
  10. }
  11. char LICENSE[] SEC("license") = "Dual BSD/GPL";
复制代码
  1. // hello.c
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <sys/resource.h>
  5. #include <bpf/libbpf.h>
  6. #include "hello.skel.h"
  7. static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
  8. {
  9.     return vfprintf(stderr, format, args);
  10. }
  11. int main(int argc, char **argv)
  12. {
  13.     struct hello_bpf *skel;
  14.     int err;
  15.     libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
  16.     /* Set up libbpf errors and debug info callback */
  17.     libbpf_set_print(libbpf_print_fn);
  18.     /* Open BPF application */
  19.     skel = hello_bpf__open();
  20.     if (!skel) {
  21.         fprintf(stderr, "Failed to open BPF skeleton\n");
  22.         return 1;
  23.     }   
  24.     /* Load & verify BPF programs */
  25.     err = hello_bpf__load(skel);
  26.     if (err) {
  27.         fprintf(stderr, "Failed to load and verify BPF skeleton\n");
  28.         goto cleanup;
  29.     }
  30.     /* Attach tracepoint handler */
  31.     err = hello_bpf__attach(skel);
  32.     if (err) {
  33.         fprintf(stderr, "Failed to attach BPF skeleton\n");
  34.         goto cleanup;
  35.     }
  36.     printf("Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` "
  37.            "to see output of the BPF programs.\n");
  38.     for (;;) {
  39.         /* trigger our BPF program */
  40.         fprintf(stderr, ".");
  41.         sleep(1);
  42.     }
  43. cleanup:
  44.     hello_bpf__destroy(skel);
  45.     return -err;
  46. }
复制代码
helloworld的程序hook了execve系统调用,在进程创建时会调用execve系统调用进入内核空间,此时被注入内核空间的ebpf字节码打印出一个字符串。
需要注意的是:

  • 这个打印行为并不是在用户空间进行的,需要通过/sys/kernel/debug/tracing/trace_pipe文件观察打印输出
  • 在hello.bpf.c文件中在#include 之前定义了一个#define BPF_NO_GLOBAL_DATA宏,这里是关闭ebpf的全局变量功能,因为低版本的内核不支持这个特性,项目的示例minimal和minimal_legacy很明确的标注了这个问题
This version of minimal is modified to allow running on even older kernels that do not allow global variables. bpf_printk uses global variables unless BPF_NO_GLOBAL_DATA is defined before including bpf_helpers.h. Additionally, the global variable my_pid has been replaced with an array of one element to hold the process pid.
编译运行helloworld程序

将自己的构建目标加入Makefile的APPS变量中,运行make $obj即可编译自己的ebpf程序
  1. # Makefile
  2. APPS = minimal minimal_legacy bootstrap uprobe kprobe fentry usdt sockfilter tc ksyscall hello
复制代码
运行make hello后,打印出整个项目的编译流程,主要分为三个步骤如下

  • 编译libbpf
  • 编译bpftool
  • 编译hello
当然编译一个ebpf程序的过程不是这么简单的过程,helloworld程序的具体编译的过程会在后文介绍
  1. # make hello
  2. which: no cargo in (/opt/rh/devtoolset-7/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)
  3.   MKDIR    .output
  4.   MKDIR    .output/libbpf
  5.   LIB      libbpf.a
  6.   MKDIR    /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs
  7.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/bpf.o
  8.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/btf.o
  9.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/libbpf.o
  10.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/libbpf_errno.o
  11.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/netlink.o
  12.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/nlattr.o
  13.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/str_error.o
  14.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/libbpf_probes.o
  15.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/bpf_prog_linfo.o
  16.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/btf_dump.o
  17.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/hashmap.o
  18.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/ringbuf.o
  19.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/strset.o
  20.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/linker.o
  21.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/gen_loader.o
  22.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/relo_core.o
  23.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/usdt.o
  24.   CC       /root/libbpf-bootstrap/examples/c/.output//libbpf/staticobjs/zip.o
  25.   AR       /root/libbpf-bootstrap/examples/c/.output//libbpf/libbpf.a
  26.   INSTALL  bpf.h libbpf.h btf.h libbpf_common.h libbpf_legacy.h bpf_helpers.h bpf_helper_defs.h bpf_tracing.h bpf_endian.h bpf_core_read.h skel_internal.h libbpf_version.h usdt.bpf.h
  27.   INSTALL  /root/libbpf-bootstrap/examples/c/.output//libbpf/libbpf.pc
  28.   INSTALL  /root/libbpf-bootstrap/examples/c/.output//libbpf/libbpf.a
  29.   MKDIR    bpftool
  30.   BPFTOOL  bpftool/bootstrap/bpftool
  31. ...                        libbfd: [ OFF ]
  32. ...               clang-bpf-co-re: [ on  ]
  33. ...                          llvm: [ on  ]
  34. ...                        libcap: [ OFF ]
  35.   MKDIR    /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/include/bpf
  36.   INSTALL  /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/include/bpf/hashmap.h
  37.   INSTALL  /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/include/bpf/relo_core.h
  38.   INSTALL  /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/include/bpf/libbpf_internal.h
  39.   MKDIR    /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/
  40.   MKDIR    /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/
  41.   MKDIR    /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs
  42.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/bpf.o
  43.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/btf.o
  44.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/libbpf.o
  45.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/libbpf_errno.o
  46.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/netlink.o
  47.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/nlattr.o
  48.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/str_error.o
  49.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/libbpf_probes.o
  50.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/bpf_prog_linfo.o
  51.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/btf_dump.o
  52.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/hashmap.o
  53.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/ringbuf.o
  54.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/strset.o
  55.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/linker.o
  56.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/gen_loader.o
  57.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/relo_core.o
  58.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/staticobjs/usdt.o
  59.   AR       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/libbpf/libbpf.a
  60.   INSTALL  bpf.h libbpf.h btf.h libbpf_common.h libbpf_legacy.h bpf_helpers.h bpf_helper_defs.h bpf_tracing.h bpf_endian.h bpf_core_read.h skel_internal.h libbpf_version.h usdt.bpf.h
  61.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/main.o
  62.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/common.o
  63.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/json_writer.o
  64.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/gen.o
  65.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/btf.o
  66.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/xlated_dumper.o
  67.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/btf_dumper.o
  68.   CC       /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/disasm.o
  69.   LINK     /root/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/bpftool
  70.   BPF      .output/hello.bpf.o
  71.   GEN-SKEL .output/hello.skel.h
  72.   CC       .output/hello.o
  73.   BINARY   hello
复制代码
这里我们的helloworld程序就编译好了,尝试运行一下,需要使用root用户:
  1. # ./hello
  2. libbpf: loading object 'hello_bpf' from buffer
  3. libbpf: elf: section(2) .symtab, size 120, link 1, flags 0, type=2
  4. libbpf: elf: section(3) tracepoint/syscalls/sys_enter_execve, size 200, link 0, flags 6, type=1
  5. libbpf: sec 'tracepoint/syscalls/sys_enter_execve': found program 'bpf_prog' at insn offset 0 (0 bytes), code size 25 insns (200 bytes)
  6. libbpf: elf: section(4) .rodata.str1.1, size 35, link 0, flags 32, type=1
  7. libbpf: elf: section(5) license, size 13, link 0, flags 3, type=1
  8. libbpf: license of hello_bpf is Dual BSD/GPL
  9. libbpf: elf: section(6) .BTF, size 438, link 0, flags 0, type=1
  10. libbpf: elf: section(7) .BTF.ext, size 160, link 0, flags 0, type=1
  11. libbpf: looking for externs among 5 symbols...
  12. libbpf: collected 0 externs total
  13. libbpf: map '.rodata.str1.1' (global data): at sec_idx 4, offset 0, flags 80.
  14. libbpf: map 0 is ".rodata.str1.1"
  15. libbpf: map '.rodata.str1.1': skipped auto-creating...
  16. Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` to see output of the BPF programs.
复制代码
此时打开另一个终端查看/sys/kernel/debug/tracing/trace_pipe文件可以看到程序打印:
  1. # cat /sys/kernel/debug/tracing/trace_pipe
  2.            <...>-79115 [000] .... 67971.749552: 0: invoke bpf_prog: Hello, World!
  3.            <...>-79117 [000] .... 67971.753866: 0: invoke bpf_prog: Hello, World!
  4.            <...>-79119 [000] .... 67971.757380: 0: invoke bpf_prog: Hello, World!
  5.            <...>-79120 [000] .... 67971.761711: 0: invoke bpf_prog: Hello, World!
  6.            <...>-79121 [000] .... 67971.764028: 0: invoke bpf_prog: Hello, World!
  7.            <...>-79123 [000] .... 67971.769068: 0: invoke bpf_prog: Hello, World!
  8.            <...>-79124 [000] .... 67971.771786: 0: invoke bpf_prog: Hello, World!
  9.            <...>-79126 [000] .... 67971.776243: 0: invoke bpf_prog: Hello, World!
  10.            <...>-79127 [000] .... 67971.779373: 0: invoke bpf_prog: Hello, World!
  11.            <...>-79129 [000] .... 67971.784824: 0: invoke bpf_prog: Hello, World!
  12.            <...>-79131 [000] .... 67971.791846: 0: invoke bpf_prog: Hello, World!
  13.            <...>-79132 [000] .... 67979.733858: 0: invoke bpf_prog: Hello, World!
复制代码
这里我们的helloworld程序就运行成功了
to be continued

来源:https://www.cnblogs.com/yux1a0/p/17454211.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具