如何开发第一个 eBPF 程序

简介: 【2月更文挑战第5天】

作为 eBPF 最重大的改进之一,一次编译到处执行(简称 CO-RE)解决了内核数据结构在不同版本差异导致的兼容性问题。不过,在使用 CO-RE 之前,内核需要开启  CONFIG_DEBUG_INFO_BTF=y 和 CONFIG_DEBUG_INFO=y 这两个编译选项。推荐使用已经默认开启这些编译选项的发行版,作为你的开发环境,比如:

  • Ubuntu 20.10+
  • Fedora 31+
  • RHEL 8.2+
  • Debian 11+


虚拟机创建好之后,接下来就需要安装 eBPF 开发和运行所需要的开发工具,这包括:

  • 将 eBPF 程序编译成字节码的 LLVM;
  • C 语言程序编译工具 make;
  • 最流行的 eBPF 工具集 BCC 和它依赖的内核头文件;
  • 与内核代码仓库实时同步的 libbpf;
  • 同样是内核代码提供的 eBPF 程序管理工具 bpftool。


可以执行下面的命令,来安装这些必要的开发工具:

# For Ubuntu20.10+
sudo apt-get install -y  make clang llvm libelf-dev libbpf-dev bpfcc-tools libbpfcc-dev linux-tools-$(uname -r) linux-headers-$(uname -r)
# For RHEL8.2+
sudo yum install libbpf-devel make clang llvm elfutils-libelf-devel bpftool bcc-tools bcc-devel


当前面这些开发工具和依赖库安装完成后,一个完整的 eBPF 开发环境就准备好了。接下来,就要体验一下 eBPF 的强大功能了。

eBPF 的开发和执行过程,一般来说,这个过程分为以下 5 步:

  • 第一步,使用 C 语言开发一个 eBPF 程序;
  • 第二步,借助 LLVM 把 eBPF 程序编译成 BPF 字节码;
  • 第三步,通过 bpf 系统调用,把 BPF 字节码提交给内核;
  • 第四步,内核验证并运行 BPF 字节码,并把相应的状态保存到 BPF 映射中;
  • 第五步,用户程序通过 BPF 映射查询 BPF 字节码的运行状态。


BCC 是一个 BPF 编译器集合,包含了用于构建 BPF 程序的编程框架和库,并提供了大量可以直接使用的工具。使用 BCC 的好处是,它把上述的 eBPF 执行过程通过内置框架抽象了起来,并提供了 Python、C++ 等编程语言接口。这样,你就可以直接通过 Python 语言去跟 eBPF 的各种事件和数据进行交互。


使用 BCC 开发 eBPF 程序,可以把前面讲到的五步简化为下面的三步。


第一步:使用 C 开发一个 eBPF 程序

新建一个  hello.c  文件,并输入下面的内容:

int hello_world(void *ctx)
{
    bpf_trace_printk("Hello, World!");
    return 0;
}

就像所有编程语言的“ Hello World ”示例一样,这段代码的含义就是打印一句 “Hello, World!” 字符串。其中, bpf_trace_printk()  是一个最常用的 BPF 辅助函数,它的作用是输出一段字符串。不过,由于 eBPF 运行在内核中,它的输出并不是通常的标准输出(stdout),而是内核调试文件  /sys/kernel/debug/tracing/trace_pipe ,你可以直接使用  cat  命令来查看这个文件的内容。


第二步:使用 Python 和 BCC 库开发一个用户态程序

接下来,创建一个  hello.py  文件,并输入下面的内容:

#!/usr/bin/env python3
# 1) import bcc library
from bcc import BPF
# 2) load BPF program
b = BPF(src_file="hello.c")
# 3) attach kprobe
b.attach_kprobe(event="do_sys_openat2", fn_name="hello_world")
# 4) read and print /sys/kernel/debug/tracing/trace_pipe
b.trace_print()

看看每一处的具体含义:

  • 第 1) 处导入了 BCC  库的 BPF 模块,以便接下来调用;
  • 第 2) 处调用 BPF() 加载第一步开发的 BPF 源代码;
  • 第 3) 处将 BPF 程序挂载到内核探针(简称 kprobe),其中  do_sys_openat2() 是系统调用  openat()  在内核中的实现;
  • 第 4) 处则是读取内核调试文件  /sys/kernel/debug/tracing/trace_pipe  的内容,并打印到标准输出中。

在运行的时候,BCC 会调用 LLVM,把 BPF 源代码编译为字节码,再加载到内核中运行。


第三步:执行 eBPF 程序

用户态程序开发完成之后,最后一步就是执行它了。需要注意的是, eBPF 程序需要以 root 用户来运行,非 root 用户需要加上 sudo 来执行:

sudo python3 hello.py

稍等一会,你就可以看到如下的输出:

b' cat-10656 [006] d... 2348.114455: bpf_trace_printk: Hello, World!'

输出的格式可由  /sys/kernel/debug/tracing/trace_options  来修改。比如前面这个默认的输出中,每个字段的含义如下所示:

  • cat-10656 表示进程的名字和 PID;
  • [006] 表示 CPU 编号;
  • d… 表示一系列的选项;
  • 2348.114455 表示时间戳;
  • bpf_trace_printk 表示函数名;
  • 最后的 “Hello, World!” 就是调用  bpf_trace_printk()  传入的字符串。


到了这里,已经成功开发并运行了第一个 eBPF 程序!

相关文章
|
存储 并行计算 Java
Python读取.nc文件的方法与技术详解
本文介绍了Python中读取.nc(NetCDF)文件的两种方法:使用netCDF4和xarray库。netCDF4库通过`Dataset`函数打开文件,`variables`属性获取变量,再通过字典键读取数据。xarray库利用`open_dataset`打开文件,直接通过变量名访问数据。文中还涉及性能优化,如分块读取、使用Dask进行并行计算以及仅加载所需变量。注意文件路径、变量命名和数据类型,读取后记得关闭文件(netCDF4需显式关闭)。随着科学数据的增长,掌握高效处理.nc文件的技能至关重要。
3358 0
|
Linux 网络安全 KVM
CentOS7 KVM环境下制作qcow2格式镜像
CentOS7 KVM环境下制作qcow2格式镜像
1955 0
CentOS7 KVM环境下制作qcow2格式镜像
|
机器学习/深度学习 人工智能 运维
智能化运维:从传统到未来的转型之路####
本文深入探讨了智能化运维(AIOps)的兴起背景、核心价值及其在现代IT运维管理中的实践应用。通过分析智能化技术如何优化运维流程、提升系统稳定性与效率,并结合具体案例,揭示智能化运维在降低成本、增强响应速度及预测性维护方面的优势。文章还展望了智能化运维的未来发展趋势,为读者提供一幅从传统运维向智能化转型的清晰蓝图。 ####
|
JavaScript 前端开发 开发者
VUE 开发——Node.js学习(一)
VUE 开发——Node.js学习(一)
338 2
|
Linux 编译器 Shell
eBPF动手实践系列三:基于原生libbpf库的eBPF编程改进方案
为了简化 eBPF程序的开发流程,降低开发者在使用 libbpf 库时的入门难度,libbpf-bootstrap 框架应运而生。本文详细介绍基于原生libbpf库的eBPF编程改进方案。
|
前端开发 Java API
淘系接口推荐:淘宝图片搜索商品数据接口,轻松获取相似商品
淘系接口推荐:淘宝图片搜索商品数据接口,轻松获取相似商品
1654 6
|
网络协议 网络性能优化 PHP
|
机器学习/深度学习 人工智能 算法
【机器学习】十大算法之一 “线性回归”
机器学习是人工智能的一个重要分支,它利用各种算法和模型,通过分析和理解数据,让机器学习到一个智能模型,从而对数据作出预测和判断。回归分析是一种基于统计学方法的数学分析技术,用于描述两个或多个变量之间的关系。线性回归是一种最简单的回归分析方法,它使用最小二乘法来拟合一个关于自变量的线性函数,以预测其与因变量之间的相互作用关系。线性回归是机器学习领域中最为常见的算法之一,它是一个简单但非常有效的算法,常用于数据挖掘和机器学习的预测分析,例如房价预测、销售额预测等等。
1150 0
【机器学习】十大算法之一 “线性回归”

热门文章

最新文章