在AArch64平台上静态编译链接eBPF相关的工具

在嵌入式的环境下经常使用的rootfs都是高度定制的,没有与发行版相似的包管理工具(比如apt-get、yum等),因此我们不能通过一条命令就把eBPF相关的工具安装好,通常我们都要先交叉编译依赖的所有库源代码,然后在交叉编译工具的源代码,整个过程耗时又容易出错。本文说明如何在ubuntu-base-aarch64-rootfs上静态编译链接eBPF相关的工具,这样就能方便地把eBPF工具集成到高度定制的嵌入式rootfs中。


  • Target Platform: Rock960c
  • ARCH: arm64
  • rootfs: Ubuntu-base-18.04.5-rootfs-aarch64

前提条件

clang的下载与编译

参考Building bpftrace in Ubuntu的说明,通过apt-get命令安装了部分依赖库,但是安装的libclang-7-dev并没有包含libclang.a,其是静态编译链接bpftrace的重要库文件。下面命令给出了llvm和clang的静态编译命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
wget https://releases.llvm.org/8.0.0/llvm-8.0.0.src.tar.xz
wget https://releases.llvm.org/8.0.0/cfe-8.0.0.src.tar.xz

mkdir -p $HOME/install/llvm
sudo apt-get install zlib1g-dev libncurses5-dev bison cmake flex make libxml2-dev libelf-dev -y

tar -xJf llvm-8.0.0.src.tar.xz
tar -xJf cfe-8.0.0.src.tar.xz
mv cfe-8.0.0.src llvm-8.0.0.src/tools/clang
cd llvm-8.0.0.src
mkdir build
cd build
cmake .. -DBUILD_SHARED_LIBS=OFF -DLLVM_BUILD_LLVM_DYLIB=ON -DLIBCLANG_BUILD_STATIC=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/install/llvm -DCLANG_BUILD_EXAMPLES=OFF -DCLANG_INCLUDE_DOCS=OFF -DCLANG_INCLUDE_TESTS=OFF -DLLVM_APPEND_VC_REV=OFF -DLLVM_BUILD_DOCS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF -DLLVM_BUILD_TOOLS=ON -DLLVM_ENABLE_ASSERTIONS=OFF -DLLVM_ENABLE_CXX1Y=ON -DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_LIBCXX=OFF -DLLVM_ENABLE_PIC=ON -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_SPHINX=OFF -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_GO_TESTS=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=OFF -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_TARGETS_TO_BUILD="host;BPF"
make -j4
make install

find . -name 'libclang.a' | xargs cp -t $HOME/install/llvm/lib/

BCC的下载与编译

BCC(BPF Compiler Collection)是一个工具包,用于构建高效的内核追踪(tracing)和操控程序,同时它还包含多个比较有用的工具和用例。BCC利用了扩展的BPF(Berkeley Packet Filters)技术,也就是eBPF,它是在Linux-3.15合并窗口期间才被首次添加到内核中的一个新功能,要想使用BCC的更多功能需要内核版本至少是Linux-4.1以上。
Ingo Molnár如下解释了eBPF:

One of the more interesting features in this cycle is the ability to attach eBPF programs (user-defined, sandboxed bytecode executed by the kernel) to kprobes. This allows user-defined instrumentation on a live kernel image that can never crash, hang or interfere with the kernel negatively.

BCC使BPF程序更容于编写,使用C语言进行内核检测(包含一个基于LLVM的C封装),同时还具有针对Python和lua两种封装。它适用于许多任务,包括性能分析和网络流量控制。由于bpftrace依赖BCC相关的库,因此我们需要先静态编译链接BCC:

1
2
3
4
5
6
7
8
9
10
wget https://github.com/iovisor/bcc/releases/download/v0.20.0/bcc-src-with-submodule.tar.gz

tar -xzf bcc-src-with-submodule.tar.gz
mkdir -p $HOME/install/bcc

cd bcc
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/install/bcc -DCMAKE_USE_LIBBPF_PACKAGE=OFF -DCMAKE_PREFIX_PATH=$HOME/install/llvm
make install

libbpf的编译

从bcc-v0.10.0开始,开始单独分离出一个libbpf仓库,用于提供关于bpf系统调用的封装函数,以及 bpf.h/btf.h等uapi头文件。要注意的是,如果编译构建bcc时,没有包含libbpf的源代码,其将导致构建失败问题。然而我们下载的bcc-src-with-submodule.tar.gz已经包含了libbpf的源代码,下面给出了libbpf的编译命令:

1
2
3
4
cd bcc/src/cc/libbpf/src
mkdir -p $HOME/install/libbpf

OBJDIR=build DESTDIR=$HOME/install/libbpf/ make install

bpftrace的下载与编译

bpftrace是一个高级的追踪(tracing)语言,使最近的内核(从4.x开始)中eBPF技术更容易使用。bpftrace利用LLVM作为后端解释器先将脚本编译成BPF字节码(bytecode),然后利用BCC调用Linux BPF接口完成交互,同时其还能使用Linux现存的tracing技术:内核动态追踪(kprobes)、用户动态追踪(uprobes)以及静态tracepoint。bpftrace语言的设计理念借鉴了awk和C语言,同时还参考了以前的DTrace和System Tap等追踪器(tracers)。bpftrace 是由 Alastair Robertson发起创建的。

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
curl https://codeload.github.com/iovisor/bpftrace/tar.gz/refs/tags/v0.12.1 -o bpftrace-0.12.1.tar.gz
mkdir -p $HOME/install/bpftrace
sudo apt-get install libltdl-dev libpthread-stubs0-dev libiberty-dev

export LIBRARY_PATH=$HOME/install/libpbf/usr/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=$HOME/install/libpbf/usr/lib:$LD_LIBRARY_PATH
export CPATH=$HOME/install/libpbf/usr/include:$CPATH
export C_INCLUDE_PATH=$HOME/install/libpbf/usr/include:$C_INCLUDE_PATH

export LIBRARY_PATH=$HOME/install/llvm/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=$HOME/install/llvm/lib:$LD_LIBRARY_PATH
export CPATH=$HOME/install/llvm/include:$CPATH
export C_INCLUDE_PATH=$HOME/install/llvm/include:$C_INCLUDE_PATH

export LIBRARY_PATH=$HOME/install/bcc/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=$HOME/install/bcc/lib:$LD_LIBRARY_PATH
export CPATH=$HOME/install/bcc/include:$CPATH
export C_INCLUDE_PATH=$HOME/install/bcc/include:$C_INCLUDE_PATH

tar -xzf bpftrace-0.12.1.tar.gz
cd bpftrace-0.12.1
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS:BOOL=OFF -DSTATIC_LIBC=ON -DSTATIC_LINKING=1 -DCMAKE_PREFIX_PATH=$HOME/install/llvm -DCMAKE_INSTALL_PREFIX=$HOME/install/bpftrace -DKERNEL_INCLUDE_DIRS=$HOME/install/bcc/include/bcc/compat
make install

注意:由于bpftrace-0.12.1在Ubuntu-18.04.5下编译会报错,需要打上0001-fixup-compile-failure.patch才可以解决编译问题。

bpftrace