作者 | 王璞
BPF是最近Linux内核领域热门的技术。传统的BPF指的是tcpdump命令用于过滤网络包的工具,现在BPF已经得到极大的扩展,不再是Berkeley Packet Filter的缩写对应的简单的网络包过滤工具。 从Kernel 4.9之后,BPF已经成为一个完善的内核扩展工具,BPF在内核里运行一个sandbox,用于执行BPF的字节码(bytecode), 在执行BPF程序前,BPF的检查器会对BPF程序的字节码进行安全检查(比如,指针要先判断不为空后再访问,代码里不能有循环,等等),以保证BPF程序不会导致系统崩溃,因为BPF程序执行时是在内核态。 因此,BPF可以很安全地在内核态执行用户编写的程序,而且有安全保证,这比编写内核模块安全太多了。 正是因为BPF能保证安全,并运行在内核态,可以大大简化很多以前很复杂的事情,目前BPF已经应用于性能分析、网络、安全、驱动、区块链等等领域。
已经有很多文章介绍BPF在内核性能分析(Kernel tracing)方面的应用。内核有各种定义的tracepoint用于静态tracing,也可以采用动态tracing来跟踪内核函数调用。 用BPF进行内核tracing,开销小而且性能好,因为BPF程序是运行在内核态,不需要把采集到的数据再传回用户态处理,而是直接在内核态完成数据采集和处理,然后把处理结果传回用户态用于展示。 关于BPF用于内核tracing方面不再赘述,本文专注于利用BPF进行用户态应用性能分析(Userspace tracing)方面。
用户态tracing
在进行用户态tracing前,要在程序里定义tracepoints。这里主要介绍Userland Statically Defined Tracepoints(USDT)。
因为USDT依赖systemtap-sdt-dev包,先要安装依赖包,以Ubuntu为例,运行sudo apt install systemtap-sdt-dev进行安装。 下面的示例test-server.c给出如何使用宏DTRACE_PROBE1在用户程序里定义tracepoint:
#include <sys/sdt.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int idx = 0;
while(1) {
idx++;
// 自定义的tracepoint
DTRACE_PROBE1(test_grp, test_idx, idx);
sleep(1);
}
return 0;
}
上面的例子,用宏DTRACE_PROBE1定义了一个组名为test_grp、名称为test_idx的用户态tracepoint。该tracepoint只有一个参数,该参数是一个递增的整数变量。 如果要定义有两个或更多参数的tracepoint,要用DTRACE_PROBE2、DTRACE_PROBE3,以此类推。如果tracepoint不带参数,则用DTRACE_PROBE来定义。 用gcc命令编译上面的程序

本文介绍了BPF(Berkeley Packet Filter)在Linux内核中的发展,从简单的网络包过滤工具演变为一个强大的内核扩展工具。通过用户态静态定义的Tracepoints(USDT)在程序中插入轻量级的监控点,配合BPF字节码的运行,可以在内核态安全地执行用户编写的程序,用于性能分析、网络、安全等多个领域。文章以一个用户态应用为例,展示了如何使用BPF和bpftrace命令进行性能分析,以及如何通过BCC工具编写BPF程序进行USDT tracing,从而捕获和处理tracepoint数据。
最低0.47元/天 解锁文章

1893

被折叠的 条评论
为什么被折叠?



