WSL2搭建ebpf环境
默认情况下,由于缺少所需的内核模块,EBPF 程序不会在 WSL2 上运行。以下示例错误是
此问题的指示:
modprobe: 错误: ../libkmod/libkmod.c:586 kmod_search_moddep() 无法打开 moddep 文件 '/lib/modules/4.19.84-microso
ft-standard/modules.dep.bin'
modprobe:致命:在目录 /lib/modules/4.19.84-microsoft-standard 中找不到模块 kheaders
chdir(/lib/modules/4.19.84-microsoft-standard/build): 没有那个文件或目录
要解决此问题,您需要使用缺少的内核模块重建 WSL2 内核。以下说明适用于 Ubuntu 18.04 WSL2。
git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
cd WSL2-Linux-Kernel
sudo apt install flex bison build-essential libelf-dev libncurses-dev libssl-dev
cp Microsoft/config-wsl .config
修改.config
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
# [optional, for tc filters]
CONFIG_NET_CLS_BPF=m
# [optional, for tc actions]
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
# [for Linux kernel versions 4.1 through 4.6]
CONFIG_HAVE_BPF_JIT=y
# [for Linux kernel versions 4.7 and later]
CONFIG_HAVE_EBPF_JIT=y
# [optional, for kprobes]
CONFIG_BPF_EVENTS=y
# Need kernel headers through /sys/kernel/kheaders.tar.xz
CONFIG_IKHEADERS=y
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_DUMMY=m
CONFIG_VXLAN=m
编译并安装内核
sudo apt install dwarves
export KERNELRELEASE=$(uname -r)
make KERNELRELEASE=$KERNELRELEASE -j 4
make KERNELRELEASE=$KERNELRELEASE modules -j 4
sudo make KERNELRELEASE=$KERNELRELEASE modules_install
ls /lib/module/$(uname -r)
sudo mount -t debugfs debugfs /sys/kernel/debug
cd ./WSL2-Linux-Kernel-linux-msft-wsl-5.10.102.1/tools/bpf/bpftool
make
make install
安装bpf
sudo apt install bpfcc-tools
执行命令验证是否安装成功
execsnoop-bpfcc
sudo apt-get install -y make gcc libssl-dev bc libelf-dev libcap-dev \
clang gcc-multilib llvm libncurses5-dev git pkg-config libmnl-dev bison flex \
graphviz
编译bcc
git clone https://github.com/iovisor/bcc.git
cd bcc
git submodule update --init
mkdir /opt/bcc
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make -j4
make install
bpftrace
安装
对于 Ubuntu 19.04+、RHEL8+ 等系统,你可以直接运行下面的命令来安装 bpftrace:
# Ubuntu19.04+
apt install bpftrace
# RHEL8/CentOS8sudo
dnf install -y bpftrace
而对于其他旧版本的系统或其他的发行版,你可以通过源代码编译的形式安装。至于具体的步骤,你可以参考它的安装文档,这里我就不展开讲了。
安装好 bpftrace 之后,你就可以执行 bpftrace -l 来查询内核插桩和跟踪点了。比如你可以通过以下几种方式来查询:
# 查询所有内核插桩和跟踪点
sudo bpftrace -l
# 使用通配符查询所有的系统调用跟踪点
sudo bpftrace -l 'tracepoint:syscalls:*'
# 使用通配符查询所有名字包含"execve"的跟踪点
sudo bpftrace -l '*execve*'
Ubuntu编译安装
sudo apt-get install -y libbpfcc-dev
sudo apt-get update
sudo apt-get install -y \
bison \
cmake \
flex \
g++ \
git \
libelf-dev \
zlib1g-dev \
libfl-dev \
systemtap-sdt-dev \
binutils-dev \
libcereal-dev \
llvm-12-dev \
llvm-12-runtime \
libclang-12-dev \
clang-12 \
libpcap-dev \
libgtest-dev \
libgmock-dev \
asciidoctor
git clone https://github.com/iovisor/bpftrace
mkdir bpftrace/build; cd bpftrace/build;
../build-libs.sh
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j8
sudo make install
bpftrace默认安装到/usr/local/bin/bpftrace,工具默认位置 /usr/local/share/bpftrace/tools,可以通过使用-DCMAKE_INSTALL_PREFIX=/usr/local
改变安装位置。
问题
No such file or directory: /sys/kernel/debug/tracing/available_filter_functions
bpftrace -l
software:alignment-faults:
software:bpf-output:
software:context-switches:
software:cpu-clock:
software:cpu-migrations:
software:dummy:
software:emulation-faults:
software:major-faults:
software:minor-faults:
software:page-faults:
software:task-clock:
hardware:backend-stalls:
hardware:branch-instructions:
hardware:branch-misses:
hardware:bus-cycles:
hardware:cache-misses:
hardware:cache-references:
hardware:cpu-cycles:
hardware:frontend-stalls:
hardware:instructions:
hardware:ref-cycles:
No such file or directory: /sys/kernel/debug/tracing/available_filter_functions
原因:需要挂载debugfs
sudo mount -t debugfs debugfs /sys/kernel/debug
使用
bpftrace 的一个核心概念是探针点,即 eBPF 程序可以连接到的(内核或用户空间的)代码中的测量点,可以分成以下几大类:
kprobe——内核函数的开始处 kretprobe——内核函数的返回处 uprobe——用户级函数的开始处 uretprobe——用户级函数的返回处 tracepoint——内核静态追踪点 usdt——用户级静态追踪点 profile——基于时间的采样 interval——基于时间的输出 software——内核软件事件 hardware——处理器级事件
所有可用的 kprobe / kretprobe、tracepoints、software 和 hardware 探针可以通过这个命令列出:
sudo bpftrace -l
uprobe / uretprobe 和 usdt 是用户空间探针,专用于某个可执行文件。
通过 bpftrace 过滤语法使用 PID 过滤出某个特定进程调用的系统调用:
sudo bpftrace -e 't:syscalls:sys_enter_* / pid == 1234 / { @[probe] = count(); }'
分析每个进程正在写的字节数:
sudo bpftrace -e 't:syscalls:sys_exit_write /args->ret > 0/ { @[comm] = sum(args->ret); }'
bpftrace 连接操作块到写系统调用的返回探针(t:syscalls:sys_exit_write),然后使用过滤器丢掉代表错误代码的负值(/arg->ret > 0/)。
映射的键 comm 代表调用系统调用的进程名;内建函数 sum() 累计每个映射项或进程写的字节数;args 是一个 bpftrace 内建指令,用于访问追踪点的参数和返回值。如果执行成功,write 系统调用返回写的字节数,arg->ret
用于访问这个字节数。