bpf,ebpf,libbpf,libbpf_bootstarp概念介绍(如何安装libbpf_bootstarp库),以及四者关系,ebpf程序执行流程(代码分层,具体如何编译,后续操作,关系总结)

本文主要是介绍bpf,ebpf,libbpf,libbpf_bootstarp概念介绍(如何安装libbpf_bootstarp库),以及四者关系,ebpf程序执行流程(代码分层,具体如何编译,后续操作,关系总结),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

概念介绍

bpf

​编辑

ebpf

eBPF 虚拟机

libbpf 

libbpf-bootstrap

如何安装

源码目录 

ebpf, libbpf 和libbpf-bootstrap之间的关系

ebfp程序数据流程

介绍

代码

用户层函数

编译

查看

生成内核层的.o文件

第一模块

第二模块

第三模块

第四模块

第五模块

生成辅助文件(.skel.h)

生成代码层的.o文件

第一模块

第二模块

第三模块

链接出可执行文件

后续+总结


本文参考哔哩哔哩up主"张口就问"发布的ebpf的学习视频,感谢大佬

概念介绍

bpf

ebpf

  • 它提供了一个功能强大的虚拟机,在内核中执行用户定义的程序
  • 通过 eBPF,用户可以编写并在内核中动态加载运行自定义的程序,而无需修改/重新编译内核源代码,从而实现了一种灵活而安全的内核扩展方式

eBPF 虚拟机

  • 用户编写的 eBPF 程序以字节码的形式加载到内核中,并由 eBPF 虚拟机执行
  • 通过特定的用户态工具或接口,将eBPF程序加载到内核中的特定区域,并在不再需要时将其从内核中移除
  • 我理解的他们之间的关系也许是:
  • 这样各是各的,互不影响

libbpf 

对bpf syscall(系统调用) 做出了基础封装,提供了 open, load, attach, maps操作, CO-RE等功能

libbpf-bootstrap

基于 libbpf 开发出来的eBPF内核层代码,通过bpftool工具直接生成用户层代码操作接口,极大减少开发人员的工作量

如何安装

首先需要linux环境+11版本及以上的clang编译器

  • 最好使用ubuntu环境,centos提供的软件包版本太低了
  • ubuntu可以指定安装clang版本(注意更新一下软件包,但默认还是下载的clang10),但centos好像需要自己下载源码编译

然后根据libbpf-bootstrap 开发指南:概念与如何安装-CSDN博客进行环境搭建即可

源码目录 

 

ebpf, libbpf 和libbpf-bootstrap之间的关系

类似于在c语言中的系统调用,c库,第三方库之间的关系

  • ebpf 提供底层接口,让用户程序可以在内核中动态执行
  • 而libbpf 是用户态的c库,它对ebpf程序的接口和函数进行了封装,减少了我们的使用成本
  • libbpf-bootstrap 是一个辅助工具和示例代码集合,他是使用者自己开发的一种工具,帮助我们更好地使用libbpf

ebfp程序数据流程

介绍

代码

ebpf代码一般分为两个部分,用户层代码(.c)和内核层代码(.bpf.c)

  • 内核层代码:跑在内核层,负责实现真正的eBPF功能(也就是核心功能代码)
  • 用户层代码:跑在用户层,负责 open, load, attach eBPF内核层代码到内核,并负责用户层和内核层的数据交互

用户层函数

  • 注意,在用户层写的代码中,我们使用的核心函数其实是经过了进一步封装的:
  • 他们的函数名第一个都是程序名,这么自定义的行为说明底层绝对是调用了其他函数,但我们在使用时并不需要关心,因为肯定是库自发性的行为
  • (当然啦,学习的时候还是要懂原理的,将在下面的编译里介绍)

编译

查看

我们可以通过现成的makefile来查看编译时的具体语句:

make kprobe V=1

生成内核层的.o文件

我们先看生成了内核层的.o文件的编译语句:

clang -g -O2 -target bpf -D__TARGET_ARCH_x86   -I.output 
-I../../libbpf/include/uapi 
-I../../vmlinux/x86/ 
-I/libbpf-bootstrap/blazesym/capi/include -idirafter /usr/local/include 
-idirafter /usr/lib/llvm-11/lib/clang/11.0.0/include 
-idirafter /usr/include/x86_64-linux-gnu 
-idirafter /usr/include                -c kprobe.bpf.c -o .output/kprobe.tmp.bpf.o/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/bpftool
gen object 
.output/kprobe.bpf.o .output/kprobe.tmp.bpf.o

我们把这里的编译语句分为五部分:

第一模块

基本信息+功能选项

第二模块

添加libbpf-bootstrap库中的文件到搜索路径中

第三模块

添加系统库文件到搜索路径中

  • -I和-idirafter的区别:
第四模块

指定要生成的目标文件

第五模块

使用bptool工具生成两份bpf.o文件(编译成 eBPF 字节码,字节码用elf格式存储)

  • 一份用于生成辅助文件,以及加载到内核中
  • 一份备份文件 
  • (根据实际语句理解的,应该是这样)

生成辅助文件(.skel.h)

/libbpf-bootstrap/examples/c/.output/bpftool/bootstrap/bpftool 
gen skeleton 
.output/kprobe.bpf.o > .output/kprobe.skel.h

还记得前面说的,用户层使用的函数其实是再次经过封装的吗?

  • 由bpftool工具自动帮我们根据.bpf.o来生成.skel.h头文件的
  • 根据实际要在内核中执行的功能,根据执行过程需要的函数,生成一份用户层和内核层的中间文件
  • 它提供了用户层的接口,并且自动在里面封装出可以执行内核层代码的代码
  • 官方一点就是它里面包含了.bpf.c 对应的elf文件数据,以及用户层需要的 open, load, attach 等接口

  • 就像这样,他帮我们自动生成用户层接口,并在里面调用所需的libbpf中的函数,并进行一定处理:
  • 这个更是如此,甚至将两个函数合在一块,方便我们使用:
  • 如果追根溯源的话,更能体现它会根据内核层代码,建立中间要使用的数据结构,生成中间代码,生成用户层接口:
  • 让我们一起说,谢谢它!!! 

生成代码层的.o文件

cc -g -Wall -I.output 
-I../../libbpf/include/uapi 
-I../../vmlinux/x86/ 
-I/libbpf-bootstrap/blazesym/capi/include -c kprobe.c -o .output/kprobe.o

和内核层的类似,我们可以把它分成三部分:

第一模块

普通选项

第二模块

添加搜索路径

  • 添加.output是因为,有生成的.skel.h头文件在那个目录下
  • 我们必须加上实际的库函数,才能编译成功
第三模块

指定目标文件名

链接出可执行文件

cc -g -Wall .output/kprobe.o 
/libbpf-bootstrap/examples/c/.output/libbpf.a   
-lelf 
-lz -o kprobe

后续+总结

可以看到,用户层代码.o文件+库文件最终链接出了可执行文件

那.bpf.o呢?

我是这么理解的 :

用户层代码用于管理ebpf程序的执行(启动啦,挂接啦,销毁啦等等)

而内核层代码只负责编写挂接后的操作(或者说核心操作),然后被加载到内核中,等待被触发:

  • 可以看到,在libbpf库中,提供了一系列函数,用于将ebpf码传进系统调用函数中
  • 也就说,.bpf.o并不在可执行文件里,而是被加载进了内核里,由可执行文件远程控制它的生命周期
  • 然后就等待其被触发

并且经过一系列安全检查,保证这份程序被加载进内核前是安全的:

  • 这个安全检查是利用了ebpf的特性编写的
  • 在进入vts_write函数之前,先进行数组检查
  • 如果越界,内核就可以在实际执行之前拒绝它

总之,它形成了一系列的关系:

内核层代码 -> ebpf码 -> 加载进内核中(用户空间程序调用系统调用,将ebpf码作为参数传入)

                   -> elf.h头文件 -> 提供用户层接口 -> 控制ebpf程序的执行流程                                         

这篇关于bpf,ebpf,libbpf,libbpf_bootstarp概念介绍(如何安装libbpf_bootstarp库),以及四者关系,ebpf程序执行流程(代码分层,具体如何编译,后续操作,关系总结)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Python对PDF书签进行添加,修改提取和删除操作

《Python对PDF书签进行添加,修改提取和删除操作》PDF书签是PDF文件中的导航工具,通常包含一个标题和一个跳转位置,本教程将详细介绍如何使用Python对PDF文件中的书签进行操作... 目录简介使用工具python 向 PDF 添加书签添加书签添加嵌套书签Python 修改 PDF 书签Pytho

uniapp小程序中实现无缝衔接滚动效果代码示例

《uniapp小程序中实现无缝衔接滚动效果代码示例》:本文主要介绍uniapp小程序中实现无缝衔接滚动效果的相关资料,该方法可以实现滚动内容中字的不同的颜色更改,并且可以根据需要进行艺术化更改和自... 组件滚动通知只能实现简单的滚动效果,不能实现滚动内容中的字进行不同颜色的更改,下面实现一个无缝衔接的滚动

PyQt5 QDate类的具体使用

《PyQt5QDate类的具体使用》QDate是PyQt5中处理日期的核心类,本文主要介绍了PyQt5QDate类的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录核心功能常用方法及代码示例​1. 创建日期对象​2. 获取日期信息​3. 日期计算与比较​4. 日

利用Python实现可回滚方案的示例代码

《利用Python实现可回滚方案的示例代码》很多项目翻车不是因为不会做,而是走错了方向却没法回头,技术选型失败的风险我们都清楚,但真正能提前规划“回滚方案”的人不多,本文从实际项目出发,教你如何用Py... 目录描述题解答案(核心思路)题解代码分析第一步:抽象缓存接口第二步:实现两个版本第三步:根据 Fea

Java计算经纬度距离的示例代码

《Java计算经纬度距离的示例代码》在Java中计算两个经纬度之间的距离,可以使用多种方法(代码示例均返回米为单位),文中整理了常用的5种方法,感兴趣的小伙伴可以了解一下... 目录1. Haversine公式(中等精度,推荐通用场景)2. 球面余弦定理(简单但精度较低)3. Vincenty公式(高精度,

QT6中绘制UI的两种方法详解与示例代码

《QT6中绘制UI的两种方法详解与示例代码》Qt6提供了两种主要的UI绘制技术:​​QML(QtMeta-ObjectLanguage)​​和​​C++Widgets​​,这两种技术各有优势,适用于不... 目录一、QML 技术详解1.1 QML 简介1.2 QML 的核心概念1.3 QML 示例:简单按钮

一文详解如何查看本地MySQL的安装路径

《一文详解如何查看本地MySQL的安装路径》本地安装MySQL对于初学者或者开发人员来说是一项基础技能,但在安装过程中可能会遇到各种问题,:本文主要介绍如何查看本地MySQL安装路径的相关资料,需... 目录1. 如何查看本地mysql的安装路径1.1. 方法1:通过查询本地服务1.2. 方法2:通过MyS

电脑软件不能安装到C盘? 真相颠覆你的认知!

《电脑软件不能安装到C盘?真相颠覆你的认知!》很多人习惯把软件装到D盘、E盘,刻意绕开C盘,这种习惯从哪来?让我们用数据和案例,拆解背后的3大原因... 我身边不少朋友,在使用电脑安装软件的时候,总是习惯性的把软件安装到D盘或者E盘等位置,刻意避开C盘。如果你也有这样的习惯,或者不明白为什么要这么做,那么我

Mysql数据库中数据的操作CRUD详解

《Mysql数据库中数据的操作CRUD详解》:本文主要介绍Mysql数据库中数据的操作(CRUD),详细描述对Mysql数据库中数据的操作(CRUD),包括插入、修改、删除数据,还有查询数据,包括... 目录一、插入数据(insert)1.插入数据的语法2.注意事项二、修改数据(update)1.语法2.有

SQL Server中的PIVOT与UNPIVOT用法具体示例详解

《SQLServer中的PIVOT与UNPIVOT用法具体示例详解》这篇文章主要给大家介绍了关于SQLServer中的PIVOT与UNPIVOT用法的具体示例,SQLServer中PIVOT和U... 目录引言一、PIVOT:将行转换为列核心作用语法结构实战示例二、UNPIVOT:将列编程转换为行核心作用语