初识ebpf

介绍eBPF技术

当代计算机系统中,性能、安全性和可观察性是至关重要的关键因素。为了应对这些挑战,Linux 内核引入了一种名为eBPF(extended Berkeley Packet Filter)的强大技术。eBPF 不仅仅是一种网络数据包过滤器,它是一种可编程的内核技术,可以用于解决各种各样的问题,从网络性能优化到安全审计。本文将深入介绍eBPF技术,包括其起源、基本概念、工作原理、应用领域和相关工具。

在当今计算机领域,Linux 内核是一个广泛使用的操作系统内核,而eBPF是 Linux 内核中的一项创新技术,它具有广泛的用途,可以用于改善系统性能、提高安全性、监控和审计系统行为。eBPF 能够实现高性能和可编程性,使其成为解决多种问题的理想选择。

eBPF的起源

eBPF 最初起源于 Berkeley Packet Filter(BPF),后来演化为 extended BPF,随着时间的推移,它已经成为 Linux 内核的一部分。BPF 最早是由 Steven McCanne 和 Van Jacobson 在 1992 年创建的,用于数据包捕获和过滤。extended BPF 允许用户编写更复杂的程序,而不仅仅是数据包过滤,从而扩展了其应用范围。

eBPF的基本概念

eBPF 提供了一个基于寄存器的虚拟机,可以执行内核中嵌入的程序,这些程序通常称为 BPF 程序。这些程序使用一种特殊的指令集,可以访问内核数据和功能,并在内核中执行。eBPF 具有以下基本概念:

BPF 程序:eBPF 程序是由用户编写的程序,使用 BPF 指令集执行。它们通常编译成字节码并加载到内核中。

BPF 虚拟机:eBPF 程序在 BPF 虚拟机中执行,这是一个安全且受限的执行环境,可以在内核中运行用户定义的代码。

BPF 地址空间:eBPF 程序可以访问内核的地址空间,包括数据结构和函数。

Hook Points:eBPF 可以绑定到内核的挂钩点(hook points),这些挂钩点允许程序拦截和修改内核事件。

eBPF的工作原理

eBPF 工作原理涉及以下步骤:

1、用户编写 eBPF 程序,通常使用高级语言(如C)编写,并使用 BPF 编译器编译成字节码。

2、编译后的程序加载到内核中,然后通过 BPF 虚拟机执行。程序可以连接到内核的挂钩点(hook points),例如网络数据包处理、系统调用等。

3、在运行时,eBPF 程序可以访问内核数据和事件,并根据需求执行自定义逻辑。

4、eBPF 程序可以生成输出,或者修改内核状态,以实现各种用途,例如性能优化、安全审计、监控和跟踪。

这里有详细的文档:https://man7.org/linux/man-pages/man7/bpf-helpers.7.html
在这里插入图片描述

eBPF的应用领域

eBPF 具有多个应用领域,包括但不限于:

网络性能优化

eBPF 可以用于实现高性能的网络数据包过滤、转发和路由。它可以用于改善网络性能、诊断网络问题,并支持各种网络应用。

安全审计和监控

eBPF 可以用于监控系统的安全性,跟踪恶意行为,检测入侵,并生成审计日志。它可以帮助系统管理员保持对系统安全性的可见性。

容器和云原生环境

eBPF 在容器和云原生环境中得到了广泛的应用。它可以用于监控容器的性能、安全性和行为,以及在多个容器之间实现网络隔离和路由。

性能分析和跟踪

eBPF 可以用于性能分析和跟踪,帮助开发人员识别和解决性能问题。它可以跟踪系统调用、函数执行时间、资源利用率等。

eBPF工具和库

为了更好地利用eBPF技术,开发人员和系统管理员可以使用各种工具和库,包括以下几种:

bpftrace
bpftrace 是一个高级工具,用于跟踪和诊断系统性能问题。它提供了一种简洁的语法,用于编写eBPF脚本,以捕获和分析系统事件。

BCC(BPF Compiler Collection)
BCC 是一个工具集,提供了许多用于eBPF开发的工具和示例程序。它包括各种用于网络分析、性能分析和安全监控的工具。

libbpf
libbpf 是一个库,用于编写eBPF程序的用户空间工具。它提供了与内核交互的功能,以及加载和执行eBPF程序的能力。

开始你的第一个 BPF 程序

BPF 程序的编译,一般使用 LLVM.LLVM 是一种 genreal-purpose 的编译器,LLVM 可以emit 不同的字节码。在本章中,LLVM 将生成 bpf 的字节码,然后我们会 load 到内核的虚拟中。
内核提供了一个系统调用,专门用于 load bpf 的程序,除了 load bpf 的程序,这个系统调用,还可以有一些其他的操作,后面我们会看到它的用法,接下来,我们来看下 Hello world:

#include <linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))
static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *)BPF_FUNC_trace_printk;
SEC("tracepoint/syscalls/sys_enter_execve")int bpf_prog(void *ctx) {char msg[] = "Hello, BPF World!";bpf_trace_printk(msg, sizeof(msg));return 0;
}
char _license[] SEC("license") = "GPL";

编译命令

clang -O2 -target bpf -c bpf_program.c -I /usr/include/x86_64-linux-
gnu/ -o bpf_program.o

我们使用 SEC 属性,告诉 BPF VM,我们想在什么时候运行我们写的这个程序。在上面的代码中,我们指定在 kernel 调用到 execve 的时候,来调用我们自己写的程序。即:SEC 中定义的是一个 Tracepoints,是 kernel 预先定义好的,允许开发者,在这里 injet 进去自己的代码。那你可能会问,我怎么知道都有哪些 tracepoints 呢?这个可以在/sys/kernel/debug/tracing/events/syscalls/这个目录下找到系统预留的所有的tracepoints.
另外,我们需要使用指定 GPL 的协议。因为 kernel 本身就是 GPL 的。我们使用
bpf_trace_printk 来 打 印 在 内 核 中 生 成 的 日 志 。 当 然 你 也 可 以 通 过
/sys/kernel/debug/tracing/trace_pipe 来查看内核的日志。

我们需要一份源码来编译 libbpf

git clone --depth 1 git://kernel.ubuntu.com/ubuntu/ubuntu-bionic.git

可以将源码拷贝到/kernel-src 目录下,然后编译 libbpf

sudo mv ubuntu-bionic /kernel-srccd /kernel-src/tools/lib/bpfsudo make && sudo make install prefix=/usr/local

现在我们有了 bpf 的代码,需要一个程序把它 load 到内核中。

#include "bpf_load.h"
#include <stdio.h>
int main(int argc, char **argv) {if (load_bpf_file("bpf_program.o") != 0) {printf("The kernel didn't load the BPF program\n");return -1;}read_trace_pipe();return 0;
}

Makefile

CLANG = clang
EXECABLE = monitor-exec
BPFCODE = bpf_program
BPFTOOLS = /home/king/share/ubuntu-bionic/samples/bpf
BPFLOADER = $(BPFTOOLS)/bpf_load.c
CCINCLUDE += -I/home/king/share/ubuntu-
bionic/tools/testing/selftests/bpf
LOADINCLUDE += -I/home/king/share/ubuntu-bionic/samples/bpf
LOADINCLUDE += -I/home/king/share/ubuntu-bionic/tools/lib
LOADINCLUDE += -I/home/king/share/ubuntu-bionic/tools/perf
LOADINCLUDE += -I/home/king/share/ubuntu-bionic/tools/include
LIBRARY_PATH = -L/usr/local/lib64
BPFSO = -lbpf
.PHONY: clean $(CLANG) bpfload build
clean:rm -f *.o *.so $(EXECABLE)
build: ${BPFCODE.c} ${BPFLOADER}$(CLANG) -O2 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o
${BPFCODE:=.o}
bpfload: buildclang -o $(EXECABLE) -lelf $(LOADINCLUDE) $(LIBRARY_PATH)
$(BPFSO) \$(BPFLOADER) loader.c
$(EXECABLE): bpfload
.DEFAULT_GOAL := $(EXECABLE)

make
在这里插入图片描述
每执行一个 ls 就会有一行打印信息
在这里插入图片描述

bpftrace工具简介

bpftrace进行内核跟踪#### bpftrace 命令行操作单行命令工具:
bpftrace -e 'program'bpftrace直接跟-e选项后面加单行命令,一些示例,比如:bpftrace -e 'BEGIN { printf("Hello world!\n"); }'
bpftrace -e 'kprobe:vfs_read { @[tid] = count();}'
bpftrace -e 'kprobe:vfs_read  /pid == 123/ { @[tid, comm] = count();}'
bpftrace -e 't:block:block_rq_insert { @[kstack] = count(); }'单行命令工具可以按ctrl-c也结束,只有结束后才会打印输出结果。#### bpftrace 编写脚本工具
bpftrace支持脚本编写,只需要在其实出添加#!/usr/local/bin/bpftrace,会被认为是一个bpftrace脚本。#!/usr/local/bin/bpftrace
// this program times vfs_read()
kprobe:vfs_read
{@start[tid] = nsecs;
} 
retprobe:vfs_read
/@start[tid]/
{$duration_us = (nsecs - @start[tid]) / 1000;@us = hist($duration_us);delete(@start[tid]);
}#### debug调试bpftrace -d
bpftrace -vbpftrace语法结构
bpftrace编程语言参考了awk的语法,基础结构:probes /filter/ { actions }它是一种事件驱动的运行方式。
probes表示的就是事件,包括tracepoint、kprobe、kretprobe、uprobe等等。除了这些跟踪点,还有两个特殊的事件BEGIN、END,用于在脚本开始处和结束处执行。filter表示的是过滤条件,当一个事件触发时,会先判断该条件,满足条件才会执行后面的action行为。action表示的具体执行的操作。
示例:bpftrace -e 'kprobe:vfs_read  /pid == 123/ { @[tid, comm] = count();}'#### bpftrace 脚本变量内部变量(built-in)uid:    用户id。
tid:   线程id
pid:   进程id。
cpu:   cpu id。
cgroup:cgroup id.
probe: 当前的trace点。
comm:  进程名字。
nsecs: 纳秒级别的时间戳。
kstack:内核栈描述
curtask:当前进程的task_struct地址。
args:   获取该kprobe或者tracepoint的参数列表
arg0:   获取该kprobe的第一个变量,tracepoint不可用
arg1:   获取该kprobe的第二个变量,tracepoint不可用
arg2:   获取该kprobe的第三个变量,tracepoint不可用
retval: kretprobe中获取函数返回值
args->ret: kretprobe中获取函数返回值备注:bpftrace -lv tracepoint:syscalls:sys_enter_read这个命令-lv可以用来查看一个tracepoint对应的参数都有哪些。自定义临时变量
以"$"标志起始来定义和引用一个变量$x = 1Map变量
map变量是用于内核向用户空间传递数据的一种存储结构,定义方式是以"@"符号作为其实标记。
这个map可以有单个key或者多个key:@path[tid] = nsecs
@path[pid, $fd] =nsecsbpftrace默认在结束时会打印从内核接收到的map变量。#### 函数exit():退出bpftrace程序
str(char *):转换一个指针到string类型
system(format[, arguments ...]):运行一个shell命令
join(char *str[]):打印一个字符串列表并在每个前面加上空格,比如可以用来输出args->argv
ksym(addr):用于转换一个地址到内核symbol
kaddr(char *name):通过symbol转换为内核地址
print(@m [, top [, div]]):可选择参数打印map中的top n个数据,数据可选择除以一个div值#### map函数
bpftrace内构的一些map函数,用于传递数据给map变量,注意接收他们的变量是map类型。常用的包括:count():用于计算次数
sum(int n):用于累加计算
avg(int n):用于计算平均值
min(int n):用于计算最小值
max(int n):用于计算最大值
hist(int n):数据分布直方图(范围为2的幂次增长)
lhist(int n):数据线性直方图
delete(@m[key]):删除map中的对应的key数据
clear(@m):删除map中的所有数据
zero(@m):map中的所有值设置为0#### 附件
常用的一些单行命令示例:bpftrace -e 'tracepoint:block:block_rq_i* { @[probe] = count(); } interval:s:1 { print(@); clear(@); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret > 0/ { @bytes = sum(args->ret); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_read { @ret = hist(args->ret); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_read { @ret = lhist(args->ret, 0, 1000, 100); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret < 0/ { @[- args->ret] = count(); }'
bpftrace -e 'kprobe:vfs_* { @[probe] = count(); } END { print(@, 5); clear(@); }'
bpftrace -e 'kprobe:vfs_read { @start[tid] =nsecs; } kretprobe:vfs_read /@start[tid]/ { @ms[comm] = sum(nsecs - @start[tid]); delete(@start[tid]); } END { print(@ms, 0, 1000000); clear(@ms); clear(@start); }'
bpftrace -e 'k:vfs_read { @[pid] = count(); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s -> %s\n", comm, str(args->filename)); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_execve { join(args->argv); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
bpftrace -e 'tracepoint:raw_syscalls:sys_enter {@[comm] = count(); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_* {@[probe] = count(); }'
bpftrace -e 'tracepoint:raw_syscalls:sys_enter {@[pid, comm] = count(); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ { @[comm] = sum(args->ret); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_read { @[comm] = hist(args->ret); }'
bpftrace -e 'tracepoint:block:block_rq_issue { printf("%d %s %d\n", pid, comm, args->bytes); }'
bpftrace -e 'software:major-faults:1 { @[comm] = count(); }'
bpftrace -e 'software:faults:1 { @[comm] = count(); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_clone { printf("-> clone() by %s PID %d\n", comm, pid); } tracepoint:syscalls:sys_exit_clone { printf("<- clone() return %d, %s PID %d\n", args->ret, comm, pid); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_setuid { printf("setuid by PID %d (%s), UID %d\n", pid, comm, uid); }'
bpftrace -e 'tracepoint:syscalls:sys_exit_setuid { printf("setuid by %s returned %d\n", comm, args->ret); }'
bpftrace -e 'tracepoint:block:block_rq_insert { printf("Block I/O by %s\n", kstack); }'
bpftrace -e 'tracepoint:syscalls:sys_enter_connect /pid == 123/ { printf("PID %d called connect()\n", $1); }'
bpftrace -e 'tracepoint:timer:hrtimer_start { @[ksym(args->function)] = count(); }'
bpftrace -e 't:syscalls:sys_enter_read { @reads = count(); } interval:s:5 { exit(); }'
bpftrace -e 'kprobe:vfs_read {@ID = pid;} interval:s:2 {printf("ID:%d\n", @ID);}'

这只是简介,留下个以后详细学习的地址:
地址1

地址2

结论

eBPF 技术已经成为 Linux 内核中的一个强大工具,用于解决性能、安全性和可观察性等各种挑战。通过可编程性和灵活性,eBPF 为开发人员和系统管理员提供了解决问题的新途径,为未来的系统优化和安全性提供了更多的机会。

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

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

相关文章

笔记1-2:

一、磁荷与磁流的引入 麦克斯韦方程组&#xff1a; 引入磁荷和磁流的概念&#xff0c;上述方程可以写成对称形式&#xff1a; 磁荷和磁流实际上不存在&#xff0c;只具有某种等效意义&#xff0c;可以把某个区域中的电磁场看成是由一组等效磁型源所产生。 对于均匀和各向同性…

gpt扣款失败,openai扣款失败无法使用-如何解决gpt扣款失败的问题?

gpt扣款失败&#xff0c;openai扣款失败无法使用。毕竟你花了钱却无法使用你所期待的服务&#xff0c;这种情况确实令人不快。但是&#xff0c; 为什么gpt扣款失败&#xff1f; 可能是由于支付问题导致的扣款失败。这包括信用卡额度不足、支付信息错误等等。如果你的支付信息…

DolphinDB x 龙蜥社区,打造多样化的数据底座

近日&#xff0c;浙江智臾科技有限公司&#xff08;以下简称“DolphinDB”&#xff09;正式签署 CLA 贡献者许可协议&#xff0c;加入龙蜥社区&#xff08;OpenAnolis&#xff09;。 DolphinDB 主创团队从 2012 年开始投入研发产品。作为一款基于高性能时序数据库&#xff0c;D…

LeetCode 1194.锦标赛优胜者

数据准备 Create table If Not Exists Players (player_id int, group_id int); Create table If Not Exists Matches (match_id int, first_player int, second_player int, first_score int, second_score int); Truncate table Players; insert into Players (player_id, g…

9+铜死亡+缺氧+分型+单细胞+实验生信思路

今天给同学们分享一篇铜死亡缺氧分型实验的生信文章“Unraveling Colorectal Cancer and Pan-cancer Immune Heterogeneity and Synthetic Therapy Response Using Cuproptosis and Hypoxia Regulators by Multi-omic Analysis and Experimental Validation”&#xff0c;这篇文…

ElasticSearch深度分页解决方案

文章目录 概要ElasticSearch介绍es分页方法es分页性能对比表方案对比 From/Size参数深度分页问题Scroll#性能对比向前翻页 总结个人思考 概要 好久没更新文章了&#xff0c;最近研究了一下es的深分页解决方案。和大家分享一下&#xff0c;祝大家国庆节快乐。 ElasticSearch介…

WorkPlus Meet:高效私有音视频会议,助力多场景协作

在当今数字化时代&#xff0c;远程协作和在线教育需求不断增长&#xff0c;企业和教育机构需要可靠的音视频会议工具来满足各种场景的需求。WorkPlus Meet&#xff0c;作为一款私有化音视频会议软件&#xff0c;强大而多功能&#xff0c;为用户提供了流畅的百人会议、实时协作、…

firefox_dev_linux下载安装配置(部分系统自带包请看结尾)

download 从 Firefox 的官方网站下载 Firefox Developer Edition 的 tar 文件 firefox_dev_linux_download # 终端快速下载 wget https://download.mozilla.org/?productfirefox-devedition-latest-ssl&oslinux64&langen-US彻底删除自带原版 # apt系 sudo apt --pu…

SpringBoot之异常处理

文章目录 前言一、默认规则二、定制异常处理处理自定义错误页面ControllerAdviceExceptionHandler处理全局异常ResponseStatus自定义异常自定义实现 HandlerExceptionResolver 处理异常 三、异常处理自动配置原理四、异常处理流程总结 前言 包含SpringBoot默认处理规则、如何定…

ubuntu x86_64 源码编译 rust 1.48.0

源码地址 GitHub - rust-lang/rust: Empowering everyone to build reliable and efficient software. git clone https://github.com/rust-lang/rust cd rust git checkout 1.48.0 ./configure ./x.py build 安装前执行cargo vendor yeqiangyeqiang-MS-7B23:~/Downloads/sr…

数据备份文件生成--根据表名生成对应的sql语句文件

最近客户有个需求&#xff0c;希望在后台增加手动备份功能&#xff0c;将数据导出下载保存。 当然&#xff0c;此方法不适用于海量数据的备份&#xff0c;这只适用于少量数据的sql备份。 这是我生成的sql文件&#xff0c;以及sql文件里的insert语句&#xff0c;已亲测&#x…

C++基于Qt中QOpenGLWidget模块实现的画图板源码+可执行文件

基于Qt中QOpenGLWidget模块实现的画图板 一、系统概述 本系统拟完成一个画图板&#xff0c;对多种常见图形进行基本操作系统功能 二维图形的输入&#xff1a;可输入或全部清除直线、矩形、圆、椭圆、多边形、文本等二维图形的变换&#xff1a;在直线、矩形、圆、椭圆、多边形…

【AI视野·今日NLP 自然语言处理论文速览 第四十期】Mon, 25 Sep 2023

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 25 Sep 2023 Totally 46 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers ReConcile: Round-Table Conference Improves Reasoning via Consensus among Diverse LLMs Authors Justin C…

基于微信小程序的民宿短租酒店预订系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

【斯坦福cs324w】中译版 大模型学习笔记九 大模型之Adaptation

文章目录 引言Adaptation的必要性从llm的训练过程分析从下游任务和原始训练任务之间的差异分析 通用的Adaptation配置 当前主流的Adaptation方法ProbingFine-tuningLightweight Fine-tuningPrompt TuningPrefix TuningAdapter Tuning 参考资料 在特定领域的下游任务中&#xff…

使用Python做一个微信机器人

介绍 简介 该程序将微信的内部功能提取出来&#xff0c;然后在程序里加载Python&#xff0c;接着将这些功能导出成库函数&#xff0c;就可以在Python里使用这些函数 程序启动的时候会执行py_code目录下的main.py&#xff0c;类似于你在命令行使用python main.py。 现在会以…

vue + openlayer 按路径移动

示例 创建一个方形的规矩&#xff0c;并让点按轨迹移动。效果如下: 源代码 <template><div><div id"map" class"map"></div><button id"start-animation" ref"startButton">Start Animation</bu…

03 MIT线性代数-矩阵乘法和逆矩阵Multiplication inverse matrices

1. 矩阵乘法 Matrix multiplication 我们通过四种方法讨论如何使矩阵A与B相乘得到矩阵C。其中A为mxn&#xff08;m行n列&#xff09;矩阵&#xff0c;而B为nxp矩阵&#xff0c;则C为mxp矩阵&#xff0c;记cij为矩阵C中第i行第j列的元素 1.1 Regular way 矩阵乘法的标准计算方…

uni-app:canvas-图形实现1

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width:200p…

【AI视野·今日CV 计算机视觉论文速览 第253期】Mon, 25 Sep 2023

AI视野今日CS.CV 计算机视觉论文速览 Mon, 25 Sep 2023 Totally 64 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers MosaicFusion: Diffusion Models as Data Augmenters for Large Vocabulary Instance Segmentation Authors Jiahao Xie, W…