Linux动态追踪——eBPF

目录

摘要 

1 什么是 eBPF

2 eBPF 支持的功能

3 BCC

4 编写脚本

5 总结

6 附


摘要 

        ftrace 和 perf 与 ebpf 同为 linux 内核提供的动态追踪工具,其中 ftrace 侧重于事件跟踪和内核行为的实时分析,perf 更侧重于性能分析和事件统计,与二者相比,ebpf 则更为强大,拥有更高的灵活性。

1 什么是 eBPF

        eBPF 可以理解为是 kernel 中实现的一个虚拟机机制,其拥有自定义的 64 位 RISC 指令集,可以再 linux 内核中运行即时编译的 BPF 程序,支持访问内核功能和内存的部分子集。具体原理为它会将类 C 代码编译为 BPF 字节码,类似 Java 字节码。然后将对应的程序代码挂到内核的钩子上,当钩子函数被调用时,内核将在 eBPF 虚拟机这个沙盒中执行字节码。

        在内核内运行一个完整的虚拟机主要是考虑便利和安全。虽然 eBPF 程序所做的操作都可以通过正常的内核模块来处理,但直接的内核编程是一件非常危险的事情 - 这可能会导致系统锁定、内存损坏和进程崩溃,从而导致安全漏洞和其他意外的效果,特别是在生产设备上(eBPF 经常被用来检查生产中的系统),所以通过一个安全的虚拟机运行本地 JIT 编译的快速内核代码对于安全监控和沙盒、网络过滤、程序跟踪、性能分析和调试都是非常有价值的。部分简单的样例可以在这篇优秀的 Linux Extended BPF (eBPF) Tracing Tools 中找到。

基于设计,eBPF 虚拟机和其程序有意地设计为不是图灵完备的:即不允许有循环(正在进行的工作是支持有界循环【译者注:已经支持有界循环,#pragma unroll 指令】),所以每个 eBPF 程序都需要保证完成而不会被挂起、所有的内存访问都是有界和类型检查的(包括寄存器,一个 MOV 指令可以改变一个寄存器的类型)、不能包含空解引用、一个程序必须最多拥有 BPF_MAXINSNS 指令(默认 4096)、“主"函数需要一个参数(context)等等。当 eBPF 程序被加载到内核中,其指令被验证模块解析为有向环状图,上述的限制使得正确性可以得到简单而快速的验证。

2 eBPF 支持的功能

        eBPF 常用来编写网络程序,将该网络程序附加到网络socket,进行流量过滤,流量分类以及执行网络分类器的动作。eBPF程序甚至可以修改一个已建链的网络socket的配置。例如 XDP 会在网络栈的底层运行 eBPF 程序,高性能地进行处理接收到的报文。另外就是用来调试了。

        下面这张图展示了 eBPF 的工作原理,大致可以分为 4 步:

  1. 编写 eBPF 代码,并生成字节码
  2. 将 eBPF 代码加载到内核的 eBPF 框架(注册 eBPF 程序到 kernel 钩子上)
  3. 事件发生,开始执行 eBPF 程序,记录数据到 maps 中
  4. 读取 maps 数据

        由于 eBPF 偏底层,平常如果是调式使用直接用底层 kernel 的接口写是比较麻烦的,幸运的是 BCC 工具集提供了好用的封装。

3 BCC

        在 eBPF 执行过程中,对于编译、加载还有 maps 等操作,对所有的跟踪程序来说都是通用的。把这些过程通过 Python 抽象起来,也就诞生了 BCC(BPF Compiler Collection)。
        BCC 把 eBPF 中的各种事件源(比如 kprobe、uprobe、tracepoint 等)和数据操作(称为 Maps),也都转换成了 Python 接口(也支持 lua)。这样,使用 BCC 进行动态追踪时,编写简单的脚本就可以了。因为需要跟内核中的数据结构交互,所以真正核心的事件处理逻辑,还是需要用 C 语言来编写。

        安装 BCC 后,在 tools 目录下已经提供了一系列的工具,并在 tools/doc 目录下提供了各工具对应的使用说明了:

[root@centos ~]# yum install bcc-tools[root@centos ~]# ls /usr/share/bcc/tools/
argdist       capable       drsnoop         hardirqs     memleak         perlcalls    pythonstat   slabratetop  tclobjnew   tplist
bashreadline  cobjnew       execsnoop       javacalls    mountsnoop      perlflow     reset-trace  sofdsnoop    tclstat     trace
...[root@centos ~]# ls /usr/share/bcc/tools/doc/
argdist_example.txt       execsnoop_example.txt       mountsnoop_example.txt      reset-trace_example.txt  tclstat_example.txt
bashreadline_example.txt  ext4dist_example.txt        mysqld_qslower_example.txt  rubycalls_example.txt    tcpaccept_example.txt
biolatency_example.txt    ext4slower_example.txt      nfsdist_example.txt         rubyflow_example.txt     tcpconnect_example.txt
biosnoop_example.txt      filelife_example.txt        nfsslower_example.txt       rubygc_example.txt       tcpconnlat_example.txt
...

        例如直接用 BCC 提供的 trace 工具跟踪 do_sys_open 函数调用:

[root@centos ~]# /usr/share/bcc/tools/trace  'do_sys_open "%s", arg2' -T
TIME     PID     TID     COMM            FUNC             -
14:30:06 2899    2954    YDService       do_sys_open      /proc/sys/kernel/random/uuid
14:30:06 32584   32584   sh              do_sys_open      ../lib/tls/x86_64/libtinfo.so.5
14:30:06 32584   32584   sh              do_sys_open      ../lib/tls/libtinfo.so.5
14:30:06 32584   32584   sh              do_sys_open      ../lib/x86_64/libtinfo.so.5
14:30:06 32584   32584   sh              do_sys_open      ../lib/libtinfo.so.5

4 编写脚本

        有时候提供的工具不能很好的满足我们的需求,可能需要手动开发一个脚本来方便调试。假设还是跟踪 do_sys_open,它长这样:

// include/linux/fs.h
extern long do_sys_open(int dfd, const char __user *filename, int flags,umode_t mode);

        编写这样一个脚本同之前讲的 eBPF 原理一一对应,大体分为四步:

1. 定义事件处理函数

#!/bin/python
from bcc import BPF# 1.define BPF program (""" is used for multi-line string).
prog = """
#include <uapi/linux/ptrace.h>
#include <uapi/linux/limits.h>
#include <linux/sched.h>
// define output data structure in C
struct data_t {u32 pid;u64 ts;char comm[TASK_COMM_LEN];int dfd;char fname[NAME_MAX];int flags;unsigned short mode;
};
BPF_PERF_OUTPUT(events);// define the handler for do_sys_open.
// ctx is required, while other params depends on traced function.
int user_cb(struct pt_regs *ctx, int dfd, const char __user *filename, int flags, umode_t mode){struct data_t data = {};data.pid = bpf_get_current_pid_tgid();data.ts = bpf_ktime_get_ns();if (bpf_get_current_comm(&data.comm, sizeof(data.comm)) == 0) {data.dfd = dfd;bpf_probe_read(&data.fname, sizeof(data.fname), (void *)filename);data.flags = flags;data.mode = mode;}events.perf_submit(ctx, &data, sizeof(data));return 0;
}
"""

        这个函数以受限 C 语言来编写,作用是定义事件处理的逻辑。这部分代码需要以字符串的形式送到 eBPF 模块中处理。

2. 将 eBPF 加载到内核中

# 2.load BPF program
bpf = BPF(text=prog)
# attach the kprobe for do_sys_open, and set handler to user_cb
bpf.attach_kprobe(event="do_sys_open", fn_name="user_cb")

3. 读取 maps 数据

# 3.process event
start = 0
def print_event(cpu, data, size):global start# event's type is data_tevent = bpf["events"].event(data)if start == 0:start = event.tstime_s = (float(event.ts - start)) / 1000000000print("%-18.9f %-16s %-6d %-8s %-8s %-8s %-16s" % (time_s, event.comm, event.pid, hex(event.dfd), hex(event.flags), hex(event.mode), event.fname))# loop with callback to print_event
bpf["events"].open_perf_buffer(print_event)
print("%-18s %-16s %-6s %-8s %-8s %-8s %-16s" % ("TIME(s)", "COMM", "PID", "DFD", "FLAGS", "MODE", "FILE"))

4. 等待内核事件的发生

# 4 start the event polling loop
while 1:try:bpf.perf_buffer_poll()except KeyboardInterrupt:exit()

        将上面的几个步骤完整的串起来执行,不出意外的话就可以得到执行结果了:

[root@centos ~]# ./ebpf_test.py 
TIME(s)            COMM             PID    DFD      FLAGS    MODE     FILE            
0.000000000        barad_agent      6364   -0x64    0x8000   0x1b6    /proc/meminfo   
0.000116077        barad_agent      6364   -0x64    0x8000   0x1b6    /proc/meminfo   
0.000261420        barad_agent      6364   -0x64    0x8000   0x1b6    /proc/vmstat    
0.000464681        ebpf_test.py     6363   -0x64    0x8000   0x1b6    /usr/lib64/python2.7/encodings/ascii.so
0.000476553        ebpf_test.py     6363   -0x64    0x8000   0x1b6    /usr/lib64/python2.7/encodings/asciimodule.so
0.000482585        ebpf_test.py     6363   -0x64    0x8000   0x1b6    /usr/lib64/python2.7/encodings/ascii.py
0.000492303        ebpf_test.py     6363   -0x64    0x8000   0x1b6    /usr/lib64/python2.7/encodings/ascii.pyc

        从输出中可以看到 ebpb_test.py 自身为了打印也是打开了一堆的 so 库~~通

5 总结

        通过对 eBPF 相关资料的查询,了解了它的概念及基本原理,下一阶段的学习路径就是要熟练使用 BCC 提供的工具集,以及必要时刻能够改造 BCC 提供的工具或者自己手写一个合适的工具以方便排查问题。

6 附

        贴上完整的源码:Linux/ebpf_test.py at master · Fireplusplus/Linux · GitHub

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/3142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vim+xxd 编辑16进制

1. vim -b mib 2. 在vim 中执行 %!xxd, 这样就可以输入16进制&#xff1a; 3. 输入完成后&#xff0c;在vim中 执行 %!xxd -r 切换至原模式&#xff1b; 4. 保存退出即可 5. 重新打开mib文件&#xff1a;vim -b mib 6. 在vim 中执行 %!xxd, 查看是否符合预期&#xff1a;…

如何理解GDP、国民总收入(GNI)的区别和联系

国内生产总值和国民总收入是衡量一个国家&#xff08;地区&#xff09;经济状况和发展水平的两个重要总量指标。两者既有密切的联系&#xff0c;又有一定区别&#xff0c;用途都非常广泛。 一、GDP与GNI的基本概念 国内生产总值(Gross Domestic Product&#xff0c;GDP)&…

一个联合均值与方差模型的R包——dglm

目录 一、引言二、包的安装与载入三、模拟例子3.1 数据生成3.2 数据查看3.3 模型估计参数 一、引言 在 R 语言中&#xff0c;dglm 包是用于拟合双参数广义线性模型&#xff08;Double Generalized Linear Models&#xff0c;简称 DGLMs&#xff09;的一个工具。这类模型允许同…

模块三:二分——162.寻找峰值

文章目录 题目描述算法原理解法一&#xff1a;暴力查找解法二&#xff1a;二分查找 代码实现解法一&#xff1a;暴力查找解法二&#xff1a;CJava 题目描述 题目链接&#xff1a;162.寻找峰值 根据题意&#xff0c;需要使用O(log N)的时间复杂度来解决&#xff0c;得出本道题…

在美国站群服务器部署时如何保障从253个IP到1000个IP的无缝扩展?

在美国站群服务器部署时如何保障从253个IP到1000个IP的无缝扩展? 在当今企业的数字化转型中&#xff0c;服务器的部署和管理成为了保证业务连续性和拓展性的关键。尤其对于站群服务器来说&#xff0c;随着企业业务的增长和市场的扩展&#xff0c;需要从较小规模的253个IP地址…

AWTK 异形进度条控件发布

异形进度条控件。通过多边形来定义进度条的形状。 代码地址&#xff1a;https://gitee.com/zlgopen/awtk-widget-progress-polygon 特性 通过多边形定义进度条的形状支持通过图片来定义进度条的背景支持通过图片来定义进度条的前景 使用图片填充比使用颜色填充消耗更多的内…

数据结构练习-线性表定义与基本操作

----------------------------------------------------------------------------------------------------------------------------- 1. 线性表是( )。 A.一个有限序列&#xff0c;可以为空 B. 一个有限序列&#xff0c;不可以为空 C. 一个无限序列&#xff0c;可以为空…

第三次国土调查数据库字母缩写代表含义

CCWJQ拆除未尽区&#xff0c;CJDCQ村界调查区&#xff0c;CJDCQJX村界调查区界线&#xff0c;CLKZD测量控制点&#xff0c;CSKFBJ城市开发边界&#xff0c;CZCDYD城镇村等用地&#xff0c;DGX等高线&#xff0c;DLTB地类图斑&#xff0c;DZGY地质公园&#xff0c;FJMSQ风景名胜…

【一般排查思路】针对银河麒麟高级服务器操作系统磁盘空间已满

1. 本身磁盘空间已满 有时候我们会看到服务器上有提示“设备上没有空间”&#xff0c;如图1。 图 1 如果是磁盘本身空间已满&#xff0c;我们可以借助du工具来排查&#xff0c;比如首先cd / 切换到根目录&#xff0c;然后 du -sh * | sort -rh | head -n 3查看空间占用最大的…

【Unity】苹果(IOS)开发证书保姆级申请教程

前言 我们在使用xcode出包的时候&#xff0c;需要用到iOS证书(.p12)和描述文件(.mobileprovision) 开发证书及对应的描述文件用于开发阶段使用&#xff0c;可以直接将 App 安装到手机上&#xff0c;一个描述文件最多绑定100台测试设备 1.证书管理 进入网站Apple Developer &…

【C++】STL-vector模拟实现

目录 1、vactor的模拟实现 1.1 成员变量 1.2 size、capacity 1.3 迭代器 1.4 构造、析构、拷贝构造、operator 1.5 push_back、pop_back、reserve 1.6 operator[] 1.7 insert、erase 1.8 resize 2、使用memcpy拷贝问题 1、vactor的模拟实现 1.1 成员变量 vector是顺…

架构师系列-Nginx、OpenResty(一)- 基本使用配置

Nginx 模块 高度模块化的设计是 Nginx 的架构基础&#xff0c;Nginx 服务器被分解为多个模块&#xff0c;每个模块就是一个功能模块&#xff0c;只负责自身的功能&#xff0c;模块之间严格遵循“高内聚&#xff0c;低耦合”的原则。 核心模块 核心模块是 Nginx 服务器正常运行…

数据库系统原理实验报告4 | 数据完整性

整理自博主本科《数据库系统原理》专业课自己完成的实验报告&#xff0c;以便各位学习数据库系统概论的小伙伴们参考、学习。 专业课本&#xff1a; ———— 本次实验使用到的图形化工具&#xff1a;Heidisql 目录 一、实验目的 二、实验内容 1、建表 2、对1题中创建的Stud…

<计算机网络自顶向下> 无连接传输UDP

UDP&#xff1a;User Datagram Protocol “尽力而为”的服务 报文可能丢掉或者乱序好处&#xff1a; 效率高&#xff08;不建立连接无拥塞控制和流量控制【应用->传输的速率主机->网络的速率】&#xff09;报文段的头部很小&#xff08;开销小&#xff09;UDP被用于 流媒…

JVM常见的垃圾回收器

1、回收方法区&#xff1a; 方法区回收价值很低&#xff0c;主要回收废弃的常量和无用的类。 方法区中的存储&#xff1a; 方法区中存储的是加载的类的信息&#xff0c;常量&#xff0c;静态变量&#xff0c;即时编译后的代码等数据&#xff0c;所以回收的对象也就是这些内…

如何在一台服务器上同时运行搭载JDK 8, JDK 17, 和 JDK 21的项目:终极指南

&#x1f42f; 如何在一台服务器上同时运行搭载JDK 8, JDK 17, 和 JDK 21的项目&#xff1a;终极指南 &#x1f680; 摘要 在企业开发环境中&#xff0c;常常需要在同一台服务器上运行使用不同Java开发工具包&#xff08;JDK&#xff09;版本的多个项目。本文详细介绍如何在L…

报错import build constraints exclude all Go files in

好久没用fyne突然报错 报错import ...go-gl.. build constraints exclude all Go files in go-gl .. 检查gcc --version正常输出 检查gcc版本正常&#xff0c;路径正常。 尝试解决的方法&#xff0c; 1.重新安装依赖&#xff0c;不行 2.重新配置下载地址&#xff0c;不…

window平台C#实现软件升级功能(控制台)

window平台C#实现软件升级功能 之前用window窗体实现过一个升级功能&#xff0c;后来发现多个项目都需要升级功能&#xff0c;现改成可接收参数实现一种通用的exe.改用控制台方式实现这个升级功能&#xff0c;这样不仅实现了接收参数&#xff0c;升级程序体积也比原来的窗体形式…

河道采砂执法监管信息化平台:科技赋能,智慧监管

随着信息技术的飞速发展&#xff0c;信息化平台已经成为提升行业监管效率和水平的重要工具。河道采砂作为水利资源管理的重要环节&#xff0c;其执法监管同样需要与时俱进&#xff0c;利用先进技术手段提升监管效能。河道采砂执法监管信息化平台便是这一背景下的产物&#xff0…

从底层分析并详解SpringAOP底层实现

首先分析AOP的实现 首先切面&#xff08;Advisor&#xff09;由通知(Advice)和切点(Pointcut)组成 包括前置通知后置通知等等最终都会被转化为实现 MethodInterceptor 接口的环绕通知 先看一段代码了解一下是aop是怎么运作的 首先定义了两个类实现了MethodInterceptor接口&…