[转帖]使用bcc开发BPF程序的一点思路

使用,bcc,开发,bpf,程序,一点,思路 · 浏览次数 : 0

小编点评

**使用bcc工具开发BPF程序的步骤** 1. **安装bcc工具:** - 对于较新的系统内核,可以使用 cilium 工具开发 BPF 程序。 - 对于稍微旧一点的系统,可以使用 bcc 工具开发 BPF 程序。 2. **查看可用工具:** - 对于新版本的 bcc,BPF 工具自带一些工具,可以从 `/usr/share/bcc/tools/` 目录中找到。 - 对于旧版本的 bcc,需要安装内核源代码头文件才能使用所有工具。 3. **开发 BPF 程序:** - 选择要实现的功能。 - 找到合适的功能的 BPF hook点。 - 编写 BPF 程序,并将其加载到内核。 4. **设置数据发送方式:** - 确定要发送的数据。 - 在 BPF 程序中使用 `bpf_trace_printk()` 或 `bpf_perf_output()` 等函数将数据发送到用户空间。 5. **使用 bpf_trace_printk:** - 使用 `b.trace_print()` 等函数打印数据。 - 使用 `b.trace_fields()` 等函数获取数据并读取到变量中。 6. **使用 BPF Map:** - 在 BPF 程序中使用 `BPF_HASH()` 等函数将数据映射到其他 BPF 程序。 **注意:** - 新版本的 bcc 将使用 libbpf 的 CO-RE 特性,需要安装内核源代码头文件才能使用。 - 对于旧版本的 bcc,需要根据内核版本安装相应的头文件。 - 使用 bpf_trace_printk 或 bpf_perf_output() 等函数发送数据时,需要在内核中定义支持这些函数的 BPF hook点。

正文

https://zhuanlan.zhihu.com/p/488498453

 

之前的文章介绍了使用cilium工具开发BPF程序的例子。对于较新的系统内核来说,用这样较新的工具很不错,但是对于稍微旧一点的系统,如果不想直接写原生BPF程序的话,我们貌似只有一个选择,使用bcc。

一些常见的发行版的源中已经包含了bcc工具,注意我们在使用旧版本的bcc时,需要也要安装当前系统的内核源码头文件,新版本的bcc好像采用了libbpf的CO-RE特性。

apt install bpfcc-tools linux-headers-`uname -r`
yum install bcc-tools kernel-devel-`uname -r`

安装的内核头文件放置在了lib/modules目录下,其中包含了一个指向/usr/src的软链接文件。如果我们想要使用容器运行bcc程序对系统进行调试,注意要把系统上的这两个路径挂到容器上去。

安装好bcc后,可以查看bcc自带的一些工具的实现,例如RHEL中这些工具被放置在了/usr/share/bcc/tools/目录下,里面有很多python文件,每个脚本的内容都不是很多,仿照起来写也比较容易。

和其他的BPF开发程序一样,bcc框架也分成了两部分,一部分是BPF程序,加载到内核中使用的,bcc为了方便我们编写这部分的程序,提供了对应的库。另一部分是用户空间处理的部分,接收来自内核空间生成的数据进行处理,还可以方便的加载BPF程序到内核,旧版本的bcc一般使用python来实现这个外围的部分,听说新版本打算要弃用python了。

开发的时候我们需要考虑几个内容:

1. 对于我们想实现的功能,我们应该采用那些位置加载BPF程序。有四个比较常提到的是tracepoint,kprobe,USDT,uprobe。这四个分别是内核中的静态hook点,内核中的动态hook点,用户空间的静态hook点,用户空间的动态hook点。所谓的静态和动态,区别在于在编译程序时,是否一块编译进了一些标记。对于静态点来说,运行到了这块标记就会执行在这个点上加载的BPF程序。而动态点则无需通过标记来判断,而是编译时将函数信息加入到了可执行文件的头部信息中,当运行到这些函数时,就会自动触发对应的加载到这个位置的BPF程序。这也是为什么大家会说,有tracepoint就优先用tracepoint,没有才用kprobe,就是因为tracepoint少,并且一旦加入到内核源码中基本不会被去掉,而内核中的函数可没有这个保证。而一些针对于网络的SOCKET FILTER等还有一些其他的点则不在这四个分类中,这里面有些对内核版本的要求较高,是内核一点一点支持的。

2. 其实看看bcc提供的工具,我们会发现大多数都是采用kprobe的。那么假如我们知道想做什么,大概知道在内核的哪个功能上加载,我们怎么知道加载到kprobe的哪个确切的点呢。有一个方法是,查看/proc/kallsyms/sys/kernel/debug/kropbes/blacklist两个文件,位于第一个文件中,同时又不在第二个文件中的项目,理论上说应该是可以用的。但是我测试的时候发现有些不行,没有定位到原因出在哪里。顺带一提,系统支持的tracepoint位于sys/kernel/debug/tracing/events下。

3. 然后就是看内核源码了,在源码中找到这个函数传了哪些参数,这样在编写BPF程序的时候,这些参数都可以被我们的BPF程序应用,例如tcp_v4_connect函数接收struct sock *sk参数,那么我们在定义对应的BPF程序时,可以定义

int kprobe__tcp_v4_connect(struct pt_regs *ctx, struct sock *sk){};

如果直接定义成kprobe__加函数名的方式,后面在加载时不用再指定一次,直接这样即可(这里bpf_text即用字符串保存的c的源码)

b = BPF(text=bpf_text)

如果使用别的名字,就需要显式的指定一下加载的位置

b = BPF(text=bpf_text)
b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_entry")
kprobe支持在内核函数执行返回后触发BPF程序即kretprobeint kretprobe__tcp_v4_connect(struct pt_regs *ctx, struct sock *sk){};
b = BPF(text=bpf_text)
b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return")

4. 下一个问题是,内核中采集到的数据,怎么发送到用户空间处理,比如上个函数中的sock包含的某个变量,我们想在python程序中输出出来。可以采用以下的方式

  • 采用bpf_trace_printk,这种方式打印出来的内容可以在/sys/kernel/debug/tracing/trace_pipe看到,bcc也提供了函数可以在程序中获取这个文件中的内容,这样直接调用b.trace_print即可以打印出来,也可以通过 b.trace_fields()之前打印的内容读取到变量中

 

  • 使用bcc提供的BPF_PERF_OUTPUT
// c程序中
BPF_PERF_OUTPUT(ipv4_events)
    ...
ipv4_events.perf_submit(ctx, &data4, sizeof(data4));

 

# 外层的python程序
def print_ipv4_event(cpu, data, size):
    ...
b["ipv4_events"].open_perf_buffer(print_ipv4_event, page_cnt=64)

 

  • 使用BPF Map。BPF Map也可以在不同的BPF程序中传递数据
// c
BPF_HASH(ipv4_send_bytes, struct ipv4_key_t);
​
...
ipv4_send_bytes.increment(ipv4_key, size);

 

# python
ipv4_send_bytes = b["ipv4_send_bytes"]

与[转帖]使用bcc开发BPF程序的一点思路相似的内容:

[转帖]使用bcc开发BPF程序的一点思路

https://zhuanlan.zhihu.com/p/488498453 之前的文章介绍了使用cilium工具开发BPF程序的例子。对于较新的系统内核来说,用这样较新的工具很不错,但是对于稍微旧一点的系统,如果不想直接写原生BPF程序的话,我们貌似只有一个选择,使用bcc。 一些常见的发行版的源

[转帖]eBPF系列学习(4)了解libbpf、CO-RE (Compile Once – Run Everywhe) | 使用go开发ebpf程序(云原生利器cilium ebpf )

文章目录 一、了解libbpf1. BPF的可移植性CO-RE (Compile Once – Run Everywhere)BPF 可移植性面临的问题BPF的可移植性CO-RE (Compile Once – Run Everywhere) 2. libbpf和bcc性能对比3. 了解libbpf

[转帖]高性能:5-BCC工具介绍【bpf performance tools读书笔记】

https://cloud.tencent.com/developer/article/1595130?areaSource=103001.1&traceId=pqOBSL_jW1KSoi6X6LGEr BCC包含有关工具,手册页和示例文件的文档,以及有关使用BCC工具的指南,以及有关BCC工具开发

[转帖]7 个使用 bcc/BPF 的性能分析神器

https://t.cj.sina.com.cn/articles/view/1772191555/69a17f430190029mf 在 Linux 中出现的一种新技术能够为系统管理员和开发者提供大量用于性能分析和故障排除的新工具和仪表盘。它被称为增强的伯克利数据包过滤器(eBPF,或 BPF),

[转帖]7 个使用 bcc/BPF 的性能分析神器

https://linux.cn/article-9139-1.html 使用伯克利包过滤器Berkeley Packet Filter(BPF)编译器集合Compiler Collection(BCC)工具深度探查你的 Linux 代码。 在 Linux 中出现的一种新技术能够为系统管理员和开发者

[转帖]Linux性能优化(四)——BCC性能监控工具

一、BCC简介 1、BCC简介 BCC是一个Python库,简化了eBPF应用的开发过程,并收集了大量性能分析相关的eBPF应用。BCC为BPF开发提供了不同的前端支持,包括Python和Lua,实现了map创建、代码编译、解析、注入等操作,使开发人员只需聚焦于用C语言开发要注入的内核代码。 BCC

【转帖】Linux性能优化(四)——BCC性能监控工具

一、BCC简介 1、BCC简介 BCC是一个Python库,简化了eBPF应用的开发过程,并收集了大量性能分析相关的eBPF应用。BCC为BPF开发提供了不同的前端支持,包括Python和Lua,实现了map创建、代码编译、解析、注入等操作,使开发人员只需聚焦于用C语言开发要注入的内核代码。 BCC

[转帖]python 性能优化监控工具_Linux性能优化(四)——BCC性能监控工具

一、BCC简介 1、BCC简介 BCC是一个Python库,简化了eBPF应用的开发过程,并收集了大量性能分析相关的eBPF应用。BCC为BPF开发提供了不同的前端支持,包括Python和Lua,实现了map创建、代码编译、解析、注入等操作,使开发人员只需聚焦于用C语言开发要注入的内核代码。 BCC

[转帖]使用eBPF&BCC提取内核网络流量信息

前言 本文将分享从0开始编写自己的bcc程序。那么开始编写bcc之前,自己一定要明确,我们要用bcc提取什么数据。本文的实例是统计内核网络中的流量,我要提取的数据关键字段为进程的PID,进程的名字,进程的收包实时流量、发包实时流量,收包流量总和,发包流量总和,总的收发流量等。 我们知道bcc是eBP

[转帖][译] 使用 bcc/BPF 分析 Go 程序

https://toutiao.io/posts/089ydx/preview BCC 是基于 BPF 的 Linux IO 分析、监控、网络工具集合。BPF Compiler Collection (BCC) 是创建高效内核追踪和处理程序的工具包,包含几个有用的工具和用例。BCC 扩展了 BPF