【BPF之旅】认识eBPF

news2024/9/20 18:52:42

文章目录

    • 一、eBPF基础认识
      • 1.1 eBPF历史演进
      • 1.2 eBPF特点和使用场景
        • eBPF的特点(优势)
        • eBPF的限制(安全性的体现)
        • eBPF vs 内核模块
        • 应用场景
      • 1.3 eBPF工作原理
        • eBPF程序执行过程
        • eBPF的开销
    • 二、eBPF简单实践(Hello World)
      • 2.1 准备环境
      • 2.2 使用 C 语言开发eBPF程序
      • 2.3 使用 Python 语言开发一个用户态程序
      • 2.4 执行eBPF程序

一、eBPF基础认识

1.1 eBPF历史演进

BPF(Berkeley Packet Filter,伯克利数据包过滤器) 的概念最早源自于1992 伯克利实验室的一篇论文《The BSD Packet Filter: A New Architecture for User-level Packet Capture》,这篇论文描述了如何更加高效灵活地从操作系统内核中抓取网络数据包。

我们熟悉的 tcpdump 工具,就是利用了 BPF技术来抓取 Unix/Linux 操作系统中的网络包。

随着内核的发展,BPF 逐步从最初的数据包过滤扩展到了网络、内核、安全、跟踪等,而且它的功能特性还在快速发展中,这种扩展后的 BPF 被简称为 eBPF(即extended BPF)。早期的 BPF 被称为经典 BPF,简称 cBPF(即classic BPF)。实际上,现代内核所运行的都是 eBPF。

简言之,eBPF是一种不需要修改内核代码或加载内核模块,就可以在 Linux 内核中运行用户程序的技术。通过eBPF技术,使得Linux内核实现可动态编程化。

1.2 eBPF特点和使用场景

eBPF的特点(优势)
  • 稳定:有循环次数和代码路径触达限制,保证程序可以固定时间结束

  • 高效:可通过 JIT 方式翻译成本地机器码,执行效率高效

  • 安全:验证器会对 eBPF 程序的可访问函数集合和内存地址有严格限制,不会导致内核Panic

  • 热加载/卸载:可热加载/卸载 eBPF 程序,无需重启 Linux 系统

  • 内核内置:eBPF 自身提供了稳定的 API

eBPF的限制(安全性的体现)
  • eBPF程序不能调用任意的内核函数,只限于内核模块中列出的BPF辅助函数,函数支持列表也随着内核的演进在不断增加

  • eBPF程序不允许包含无法到达的指令,防止加载无效代码,延迟程序的终止

  • eBPF程序中循环次数限制且必须在有限时间内结束

eBPF vs 内核模块

kprobes和tracepoint技术已经存在很多年了,内核模块和BPF都能够通过它们来对内核进行跟踪和修改,但是相对而言,eBPF具有如下优势:

  • eBPF程序会通过验证器的安全性检查,而内核模块可能引入bug,导致内核崩溃。

  • eBFP通过映射表提供丰富的数据支持。

  • eBPF程序通过一次编译,然后在任何地方运行。

  • eBPF程序的编译不依赖内核编译过程的中间结果。

  • eBPF程序的开发难度更低。

  • eBPF程序具备原子性替换特性

当然,内核模块的一个好处是:模块中可以使用其他内核函数和内核设施,而eBPF只能使用有限的API函数。

应用场景

基于上述特点,eBPF可用于如下场景:

  • 性能监控:传统的系统分析工具(如top、vmstat、pidstat、netstat、iostat等),多是从 /proc、/sys、/dev 中获取信息,会对系统产生一定的开销,不适合频繁调用。相比之下,使用eBPF采集系统信息的开销小的多。

  • 性能调优:eBPF发现系统/网络性能抖动,特别是一些毛刺情况,会主动采集当时系统运行状态。

  • 程序分析:在程序无感的情况下做用户程序活体分析,比如程序内存使用监控,程序运行状态的查看。

  • 防御攻击:在网络包未到网络栈之前就处理掉,而且开销较小。

1.3 eBPF工作原理

Linux 内核提供了各种 hook point。eBPF 程序是基于事件驱动模型,通过实现指定hook point的“callback函数”,并把这些“callback函数”注册到相应hook point来完成“内核编程”。

Tips:Linux 内核提供的 hook point,主要分为三类:

  1. 静态跟踪类型: 网络套接字,跟踪点,用户态标记(USDT)。

  2. 动态跟踪类型:kprobe, uprobes。

  3. 采样和PMC:perf_events。

eBPF程序执行过程

eBPF程序的一般开发流程:

  • 用户态

    • 编写:可以使用 eBPF汇编 或者 C语言 来编写eBPF程序(注:一般很少会用 eBPF 汇编来写程序)。

    • 编译:使用 LLVM 或者 GCC 编译工具将 eBPF 源程序编译成 eBPF 字节码。

    • 加载:通过 sys_bpf() 系统调用,把 eBPF 字节码提交给内核。

  • 内核态

    • 验证:内核会对eBPF字节码进行验证,保证其是安全无害的。

    • 翻译:内核使用 JIT(Just In Time,即时编译)技术将 eBPF 字节编译成本地机器码(Native Code)。

    • 绑定:内核将eBPF程序绑定到具体的hook point

    • 触发运行:在内核对应事件触发时,运行 eBPF程序,可通过 map 或者 perf_event 与用户态程序进行数据交互。
      在这里插入图片描述

eBPF的开销

eBPF工具分析性能问题时,对于内核层的trace,产生的额外开销就是在tracepoint处,触发单步中断(或者jmp),多调用一次“callback”函数。而对于应用层的trace,额外开销是在tracepoint处,触发单步中断,陷入内核,在内核中执行“callback”,这个开销是比较大的,对与这类问题,需要关注eBPF工具本身对应用程序性能的影响。

二、eBPF简单实践(Hello World)

这里,我们使用 BCC 开发一个跟踪 openat() 系统调用的 eBPF 程序。

注:BCC(BPF Compiler Collection,BPF编译器集合)是一个知名的eBPF前端(另一个是bpftrace,后面会专文介绍),包含了用于构建 BPF 程序的编程框架和库,提供了大量可以直接使用的工具,并提供了 Python、C++ 等编程语言接口,可以通过 Python/C++ 等高级语言去跟 eBPF 的各种事件和数据进行交互。

2.1 准备环境

虽然 Linux 内核很早就已经支持了 eBPF,但很多新特性都是在 4.x 版本中逐步增加的。在开发和学习 eBPF 时,为了体验和掌握最新的 eBPF 特性,推荐使用 5.x 或更新的内核。本文使用Ubuntu 20.04.6进行演示。

安装工具

sudo apt install -y make clang llvm libelf-dev libbpf-dev bpfcc-tools libbpfcc-dev python3-bpfcc linux-tools-$(uname -r) linux-headers-$(uname -r)

2.2 使用 C 语言开发eBPF程序

使用C语言编写 hello.c 如下:

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

注:bpf_trace_printk() 是一个常用的 BPF 函数,它的作用是输出一段字符串。由于 eBPF 运行在内核中,它的输出并不是通常的标准输出(stdout),而是内核调试文件 /sys/kernel/debug/tracing/trace_pipe

2.3 使用 Python 语言开发一个用户态程序

使用Python语言编写 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")
# 4) read and print /sys/kernel/debug/tracing/trace_pipe
b.trace_print()

注:

  • b = BPF(src_file=“hello.c”) :调用 BPF() 加载第一步开发的 BPF 源代码。

  • b.attach_kprobe(event=“do_sys_openat2”, fn_name=“hello”):将 BPF 程序挂载到内核探针。

    do_sys_openat2 是系统调用 openat() 在内核中的实现。

  • b.trace_print():读取 /sys/kernel/debug/tracing/trace_pipe 文件的内容,并打印到标准输出中。

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

2.4 执行eBPF程序

eBPF 程序需要以 root 用户来运行。

chmod a+x hello.py
sudo ./hello.py

该eBPF程序会持续跟踪使用openat系统调用的进程,并将其信息打印出来,需按Ctrl-C组合键停止该程序。

终端输出如下(省略部分内容):

b'   systemd-udevd-127691  [014] ....1 494931.727453: bpf_trace_printk: Hello, World!'
b' ThreadPoolForeg-4973    [001] ....1 494932.004075: bpf_trace_printk: Hello, World!'
b' Chrome_ChildIOT-4974    [013] ....1 494932.031537: bpf_trace_printk: Hello, World!'
b'          docker-1297951 [009] ....1 494932.402515: bpf_trace_printk: Hello, World!'
b'           <...>-1282206 [018] ....1 494932.611929: bpf_trace_printk: Hello, World!'
b'   systemd-udevd-513     [010] ....1 494932.694446: bpf_trace_printk: Hello, World!'

注:

  • 第一列 systemd-udevd-127691 : 进程名字和PID

  • 第二列 [014] : CPU编号

  • 第三列 ....1: 一系列的选项

  • 第四列 494931.727453: 时间戳

  • 第五列 bpf_trace_printk: 函数名

  • 第六列 Hello, World!: 调用函数时的传参

参考:

Linux eBPF Tracing Tools

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

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

相关文章

大数据技术

4v特点 volume&#xff08;体量大&#xff09; velocity&#xff08;处理速度快&#xff09; variety&#xff08;数据类型多&#xff09; value&#xff08;价值密度低&#xff09; 核心设计理念 并行化 规模经济 虚拟化 分布式系统满足需求 系统架构 大数据处理流程 结构化…

如何在QT6上配置文心一言的接口,从而生成一个自己的对话框

这里写自定义目录标题 前言&#xff1a;效果展示&#xff1a;环境配置&#xff1a;计划完善&#xff1a;核心代码&#xff1a; 前言&#xff1a; 网上有很多在前端调用文心一言接口的&#xff0c;想在QT上配置文心一言的接口&#xff0c;从而生成一个自己的对话框。 效果展示…

Sentinel-1 Level 1数据处理的详细算法定义(九)

《Sentinel-1 Level 1数据处理的详细算法定义》文档定义和描述了Sentinel-1实现的Level 1处理算法和方程&#xff0c;以便生成Level 1产品。这些算法适用于Sentinel-1的Stripmap、Interferometric Wide-swath (IW)、Extra-wide-swath (EW)和Wave模式。 今天介绍的内容如下&…

JavaScript学习文档(10):日期对象、节点操作、 M端事件、JS插件、学生信息表案例

目录 一、日期对象 1、实例化 2、时间对象方法 3、时间戳 &#xff08;1&#xff09;时间戳 &#xff08;2&#xff09;获取时间戳的三种方式&#xff1a; &#xff08;3&#xff09;倒计时效果 二、节点操作 1、DOM 节点 2、 查找节点 3、增加节点 &#xff08;1&…

windows11 上安装了python的wxpython模块,vscode运行时还是报错的解决方法

遇到问题&#xff1a;windows11 上明明安装了python的wxpython模块&#xff0c;vscode运行时还是报错“Traceback (most recent call last): File “c:\pythoncode\new\tonguedetect.py”, line 1, in import wx ModuleNotFoundError: No module named ‘wx’” 如何解决&…

uniapp uni-popup底部弹框留白 底部颜色修改 滚动穿刺

做底部弹框的时候&#xff0c;可能出现以下场景需要处理。 一、出现底部留白不是白色&#xff0c;需要修改颜色的时候&#xff1a; 1、如果弹框不需要圆角效果&#xff0c;则在uni-popup加上背景色就行&#xff0c;弹框是个直角样式&#xff1a; 2、如果需要圆角效果&#xff0…

芒格-“用幸存者心态去对待问题,永远不要有受害者心态”

我不会因为人性而感到意外&#xff0c;也不会花太多时间感受背叛&#xff0c; 我总是低下头去调整自己&#xff0c;去适应这一类事情&#xff0c; 所以我不允许自己花太多时间&#xff0c;去感受背叛&#xff0c; 但凡有一丁点这种想法&#xff0c;从我脑海闪过&#xff0c;我就…

Ubuntu 18.04升级gclibc为2.28版本

一、查看系统支持的 GLIBC 版本号 ​strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC_出现以下&#xff0c;说明到2.27版本&#xff0c;没有2.28版本&#xff0c;所以我们需要手动安装 GLIBC_2.2.5 GLIBC_2.2.6 GLIBC_2.3 GLIBC_2.3.2 GLIBC_2.3.3 GLIBC_2.3.4 GLIBC_…

Linux环境下的MySQL的卸载、安装与使用[以CentOS7为例说明]

Linux环境下的MySQL的卸载、安装与使用[以CentOS7为例说明] 1、下载MySQL安装包2、卸载MySQL&#xff08;1&#xff09;检查是否安装过MySQL和mariadb&#xff08;2&#xff09;卸载MySQL和mariadb&#xff08;3&#xff09;问题记录&#xff08;了解&#xff09; 3、安装MySQL…

MacOS通过Docker部署MySQL数据库,以及Docker Desktop进行管理

目录 一.不需要持久化存储 1.启动容器 2.查看容器和镜像 3.容器管理 二.持久化存储启动mysql容器 1.创建docker卷 2.运行容器,指定卷 3.在mysql里面随便建个库,建张表,弄点数据 4.停止并删除MySQL容器 5.重新运行容器,并且挂载相同的卷,也就是上面第二步的命令 6.连…

【412】【统计近似相等数对 II】

差130个样例&#xff0c;等佬解 class Solution:def ifqual(self,str1,str2):return int(str1)int(str2)def change(self,str1,str2):str1 list(str1)nlen(str1)t0for i in range(n):for j in range(i1,n):str1[i],str1[j]str1[j],str1[i]t1if self.ifqual("".join…

k8s-使用Network Policies实现网络隔离

一、需求 Kubernetes 的命名空间主要用于组织和隔离资源&#xff0c;但默认情况下&#xff0c;不同命名空间中的 Pod 之间是可以相互通信的。为了实现更严格的网络隔离&#xff0c;同一套k8s需要根据不同的命名空间进行网络环境隔离&#xff0c;例如开发&#xff08;dev01&…

Plik文件上传系统本地docker部署与远程访问传输文件详细操作流程

文章目录 前言1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 前言 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设…

blender4.2中安装插件的方式

1&#xff0c;安装好blender之后&#xff0c;打开软件&#xff0c;找到 编辑&#xff0c;---> 偏好设置&#xff0c; 插件---> 从磁盘安装...., 找到插件.zip格式的文件&#xff0c; 选择 .zip格式的文件后&#xff0c;点击“从磁盘安装”按钮&#xff0c;即可

【linux003】目录操作命令篇 - cd 命令

文章目录 1、基本用法2、常见选项3、举例4、注意事项 cd 命令在 Linux 中用于更改当前工作目录。它是“change directory”的缩写。 cd 命令本身比较简单&#xff0c;不具有复杂的选项和参数&#xff0c;但它提供了一些有用的功能。 1、基本用法 cd [目录]2、常见选项 ~&…

示波器常识概述及简介

1、示波器分类 DSO&#xff1a;数字存储示波器&#xff1b; MSO&#xff1a;混合信号示波器&#xff0c;将传统的 DSO 测量模拟与逻辑分析测量相结合。 2、示波器探头提供高阻抗输入的原因 示波器探头在测试点提供相对较高的输入阻抗端子功能&#xff08;高电阻&#xff0c;低…

Html 添加音效音乐音频播放和震动效果

文章目录 需求分析1.我们需要将用到的音频文件导入到我们的网页中2.赋给图片点击的方法3.编写play()方法4. wav 格式转 MP35. 添加震动效果需求 给页面添加背景音乐和震动效果 分析 点击指定点播放音乐,再次点击则停止音乐. 1.我们需要将用到的音频文件导入到我们的网页…

数据库:头歌实验一关系数据库标准语言SQL

一、创建数据库 本关任务&#xff1a; 建立数据库 任务要求&#xff1a; 建立demo数据库 并显示所有数据库 #代码开始 CREATE DATABASE demo; show databases;#代码结束 二、创建表 本关任务&#xff1a; 建立数据表 任务要求 设有一个demo数据库&#xff0c;包括S,P,…

Android 动态性能框架 (ADPF)

Performance Hint API | Android game development | Android Developers (google.cn) ADPF 是一组 API&#xff0c;可让游戏和性能密集型应用更为直接地与 Android 设备的电源和散热系统进行互动。借助这些 API&#xff0c;您可以监控 Android 系统上的动态行为&#xff…

给Ubuntu添加硬盘之后,该如何使用

当你给Ubuntu系统添加了新的硬盘后&#xff0c;你需要按照以下步骤来识别、分区、格式化和挂载新硬盘&#xff1a; 1. 检查新硬盘是否被系统识别 首先确认新硬盘已经被系统识别&#xff1a; lsblk 2. 分区新硬盘 如果硬盘没有分区或者需要重新分区&#xff0c;可以使用fdis…