Linux C语言实践eBPF

news2024/11/17 11:47:35

手动编译了解过程

通过对关键步骤make M=samples/bpf的实践,我们已经可以编译出内核源码中提供的ebpf样例。但这还不够我们充分地理解这个编译过程,我们将这编译过程拆解一下,拆解成可以一步步执行的那种,首先是环境准备:

$ sudo apt-get install linux-source
$ cd /usr/src/
$ ls
linux-source-5.15.0.tar.bz2 linux-headers-5.15.0-43-generic linux-source-5.15.0
$ sudo tar -xvf linux-source-5.15.0.tar.bz2 -C /tmp/
$ cd /tmp/linux-source-5.15.0/

内核源码树环境准备

$ sudo make oldconfig
$ sudo make init 
$ sudo make headers_install

进入tools目录编译依赖库

$ sudo cd tools/lib/bpf/

编译依赖库为object中间件

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o libbpf.o libbpf.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o bpf.o bpf.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o btf.o btf.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o nlattr.o nlattr.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o strset.o strset.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o str_error.o str_error.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o hashmap.o hashmap.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o libbpf_probes.o libbpf_probes.c

$ sudo gcc -I. -I/tmp/linux-source-5.15.0/samples/bpf/../..//tools/include -I/tmp/linux-source-5.15.0/samples/bpf/../..//tools/include/uapi -fvisibility=hidden -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D"BUILD_STR(s)=#s" -c -o /tmp/linux-source-5.15.0/samples/bpf/libbpf/staticobjs/gen_loader.o gen_loader.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o relo_core.o relo_core.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o netlink.o netlink.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o linker.o linker.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o xsk.o xsk.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o ringbuf.o ringbuf.c

$ sudo gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-source-5.15.0/tools/bpf/ -I/tmp/linux-source-5.15.0/tools/arch/x86/include/uapi -I/tmp/linux-source-5.15.0/tools/include/ -I/tmp/linux-source-5.15.0/tools/perf -D"BUILD_STR(s)=#s" -c -o btf_dump.o btf_dump.c

将编译好的object文件链接为libbpf.a静态库

$ cd /tmp/linux-source-5.15.0/tools/lib/bpf
$ sudo ar rcs libbpf.a bpf.o btf.o libbpf.o nlattr.o str_error.o strset.o gen_loader.o libbpf_probes.o relo_core.o ringbuf.o linker.o netlink.o xsk.o btf_dump.o

编译用户态测试程序

$ cd /tmp/linux-source-5.15.0
$ sudo gcc -I./usr/include -I./tools/testing/selftests/bpf/ -I/tmp/linux-source-5.15.0/samples/bpf/libbpf/include -I./tools/include -I./tools/perf -DHAVE_ATTR_TEST=0  -c -o samples/bpf/trace_output_user.o samples/bpf/trace_output_user.c
$ sudo gcc -I./usr/include -I./tools/testing/selftests/bpf/ -I/tmp/linux-source-5.15.0/samples/bpf/libbpf/include -I./tools/include -I./tools/perf -DHAVE_ATTR_TEST=0 -o samples/bpf/trace_output samples/bpf/trace_output_user.o /tmp/linux-source-5.15.0/samples/bpf/libbpf/libbpf.a -lelf -lz -lrt

编译示例程序的第二部分,即需要给内核虚拟机运行的,由bpf_load()加载的字节码

$ cd /tmp/linux-source-5.15.0
$ sudo clang -g -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/8/include -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -Isamples/bpf -Isamples/bpf/libbpf/include/ -Isamples/bpf/libbpf/ -I./tools/testing/selftests/bpf/ -D__KERNEL__ -D__BPF_TRACING__ -D__TARGET_ARCH_x86 -O2 -emit-llvm -c samples/bpf/trace_output_kern.c -o - | sudo llc -march=bpf -filetype=obj -o samples/bpf/trace_output_kern.o
$ sudo llvm-strip -g /tmp/linux-source-5.15.0/samples/bpf/trace_output_kern.o

测试 

$ cd /tmp/linux-source-5.15.0/samples/bpf
$ sudo ./trace_output
recv 236472 events per sec
100013+0 records in
100013+0 records out
51206656 bytes (51 MB, 49 MiB) copied, 0.420891 s, 122 MB/s

解析源代码

BPF程序结构图:

由上图可知BPF程序要由两部分组成用户态执行程序和BPF bytecode。

trace_output示例的量部分如下,其中trace_output_user.c为用户态执行程序,trace_output_kern.c为BPF bytecode,所以trace_output_user.c使用gcc编译,trace_output_kern.c使用clang编译。

$ ls samples/bpf/ | grep trace_output
trace_output_kern.c
trace_output_user.c

trace_output_user.c里的主要内容

int main(int argc, char **argv)
{
        struct perf_buffer_opts pb_opts = {};
        struct bpf_link *link = NULL;
        struct bpf_program *prog;
        struct perf_buffer *pb;
        struct bpf_object *obj;
        int map_fd, ret = 0;
        char filename[256];
        FILE *f;

        snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
        obj = bpf_object__open_file(filename, NULL);
        if (libbpf_get_error(obj)) {
                fprintf(stderr, "ERROR: opening BPF object file failed\n");
                return 0;
        }

        /* load BPF program */
        if (bpf_object__load(obj)) {
                fprintf(stderr, "ERROR: loading BPF object file failed\n");
                goto cleanup;
        }

        map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
        if (map_fd < 0) {
                fprintf(stderr, "ERROR: finding a map in obj file failed\n");
                goto cleanup;
        }

        prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
        if (libbpf_get_error(prog)) {
                fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
                goto cleanup;
        }

        link = bpf_program__attach(prog);
        if (libbpf_get_error(link)) {
                fprintf(stderr, "ERROR: bpf_program__attach failed\n");
                link = NULL;
                goto cleanup;
        }

        pb_opts.sample_cb = print_bpf_output;
        pb = perf_buffer__new(map_fd, 8, &pb_opts);
        ret = libbpf_get_error(pb);
        if (ret) {
                printf("failed to setup perf_buffer: %d\n", ret);
                return 1;
        }

        f = popen("taskset 1 dd if=/dev/zero of=/dev/null", "r");
        (void) f;

        start_time = time_get_ns();
        while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) {
        }
        kill(0, SIGINT);

cleanup:
        bpf_link__destroy(link);
        bpf_object__close(obj);
        return ret;
}

其中bpf_object__open_file打开的字节码文件trace_output_kern.c里的内容如下:

struct {
        __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
        __uint(key_size, sizeof(int));
        __uint(value_size, sizeof(u32));
        __uint(max_entries, 2);
} my_map SEC(".maps");

SEC("kprobe/" SYSCALL(sys_write))
int bpf_prog1(struct pt_regs *ctx)
{
        struct S {
                u64 pid;
                u64 cookie;
        } data;

        data.pid = bpf_get_current_pid_tgid();
        data.cookie = 0x12345678;

        bpf_perf_event_output(ctx, &my_map, 0, &data, sizeof(data));

        return 0;
}

char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;


参考链接

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

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

相关文章

算法通关村第二关——两两交换链表中的节点的问题解析

题目类型 链表反转 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点&#xff0c;且必须在不修改节点内部的值的情况下完成本题&#xff0c;即&#xff1a;只能进行节点交换 效果图 题目分析 如果原始顺序是 dummy(虚拟头节点) …

JavaSE复盘2

Collection接口的接口对象集合&#xff08;单列集合&#xff09; List接口&#xff1a;元素按照先后有序保存&#xff0c;可重复 LinkList接口实现类&#xff0c;链表&#xff0c;随机访问&#xff0c;没有同步&#xff0c;线程不安全ArrayList接口实现类&#xff0c;数组&…

❤️创意网页:打造炫酷网页 - 旋转彩虹背景中的星星动画

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

iOS - 检测项目中无用类和无用图片

一、无引用图片检测 LSUnusedResources 安装插件 LSUnusedResources &#xff0c;用【My Mac】模拟器运行,如下图&#xff1a; Project Path 就是项目所在的路径&#xff0c;然后点击右下角 Search按钮&#xff0c;就可以看到被搜索出来的图片资源。 注意&#xff1a;这里被搜…

【TypeScript】类型声明及应用(二)

【TypeScript】类型声明及应用&#xff08;二&#xff09; 一、前言 TypeScript开发中需要对定义的变量指定类型&#xff0c;目前版本都支持哪些类型&#xff0c;每一个类型都有哪些含义&#xff0c;在这篇文章中&#xff0c;我们将会对其进行总结说明 二、JavaScript基本数据…

预约上门系统源码开发,改变服务行业的未来

预约上门系统源码开发是一项复杂而有挑战性的任务&#xff0c;但也是实现智能化预约服务的关键一步。通过自主开发预约上门系统的源码&#xff0c;企业可以完全定制系统的功能、界面和安全性&#xff0c;从而为用户提供更高效、便捷、个性化的预约体验。本文将带你深入了解预约…

【算法基础:动态规划】5.3 计数类DP(整数拆分、分拆数)

文章目录 例题&#xff1a;900. 整数划分解法1——完全背包解法2——分拆数⭐⭐⭐ 例题&#xff1a;900. 整数划分 https://www.acwing.com/problem/content/902/ 解法1——完全背包 容量是 n&#xff0c;物品的大小和价值是 1 ~ n 中的所有数字。 import java.util.*;pub…

软考A计划-系统集成项目管理工程师-项目人力资源管理-中

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

word2vec原理总结

参考文章&#xff1a;https://www.cnblogs.com/pinard/p/7160330.html word2vec是google在2013年推出的一个NLP工具&#xff0c;它的特点是将所有的词向量化&#xff0c;这样词与词之间就可以定量的去度量他们之间的关系&#xff0c;挖掘词之间的联系。 1 词向量编码 1.1 one…

【滑动窗口】算法实战

文章目录 一、算法原理二、算法实战1. leetcode209 长度最小的子数组2. leetcode3 无重复字符的最长子串3. leetcode1004 最大连续1的个数4. leetcode1685 将x减到0的最小操作数5. leetcode904 水果成篮6. leetcode438 找到字符串中所有字母异位词7. leetcode30 串联所有单词的…

助你丝滑过度到 Vue3 其他变化 ②⑨

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; VUE3~TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f449;…

【COlor传感器】通过扰动调制光传感实现智能光传输的占用分布估计研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

重排链表——力扣143

文章目录 题目描述法一&#xff1a;寻找链表中点、链表逆序、链表合并 题目描述 法一&#xff1a;寻找链表中点、链表逆序、链表合并 void reorderList(ListNode* head){if(headnullptr){return;}// 找到中点 ListNode* mid FindMiddle(head);ListNode *h1head, *h2mid->ne…

数值分析第七章节 用Python实现非线性方程与方程组的数值解法

参考书籍&#xff1a;数值分析 第五版 李庆杨 王能超 易大义编 第7章 非线性方程与方程组的数值解法 文章声明&#xff1a;如有发现错误&#xff0c;欢迎批评指正 文章目录 迭代法求解 x e x − 1 0 xe^x-10 xex−10牛顿法求解 x e x − 1 0 xe^x-10 xex−10简化牛顿法求解 …

PUBG(最短路BFS)

题目&#xff1a;https://ac.nowcoder.com/acm/contest/62106/E 最近&#xff0c;喜爱ACM的PBY同学沉迷吃鸡&#xff0c;无法自拔&#xff0c;于是又来到了熟悉的ERANGEL。经过一番搜寻&#xff0c;PBY同学准备动身前往安全区&#xff0c;但是&#xff0c;地图中埋伏了许多LYB&…

黑苹果如何在macOS Sonoma中驱动博通网卡

准备资源&#xff08;百度&#xff1a;黑果魏叔 下载&#xff09; 资源包中包含&#xff1a;AirportBrcmFixup.kext/IOSkywalkFamily.kext/IO80211FamilyLegacy.kext/OpenCore-Patcher 使用方法&#xff1a; 1.将 csr-active-config 设置为 03080000 全选代码 复制 2.在 …

Flutter ios真机调试连接断开后应用闪退

使用ios真机调试的时候&#xff0c;能正常打开应用&#xff0c;但是当数据线断开连接的时候&#xff0c;应用就会关闭&#xff0c;重新打开就会闪退。 原因是flutter默认在开发过程中使用debug模式编译 只需要将debug选择为release 重新编译就行。

AI工程师的崛起:填补AI革命中的空白

在一个拥有大约5000名语言学习模型&#xff08;LLM&#xff09;研究员&#xff0c;但大约有5000万软件工程师的世界中&#xff0c;供应限制决定了一种新型专业人才—AI工程师的迅猛增长。他们的崛起不仅仅是一种预测&#xff0c;更是对科技世界动态变化的必然反应。AI工程师作为…

AutoSAR系列讲解(实践篇)10.2-EcuM的上下电流程

目录 一、上电(StartUp) 二、下电(Shutdown) 三、睡眠(Sleep) 上下电,说白了就是给Ecu上下电后,Ecu的代码执行顺序。这里还讲到了大家可能经常会用到的Sleep流程,主要就是可以归纳为以下这张图,大家 掌握这张图就基本掌握了EcuM的上下电流程了。这张图的具体内容博…

MySQL的JSON操作

官网地址 1. MySQL json介绍 As of MySQL 5.7.8, MySQL supports a native JSON data type defined by RFC 7159 that enables efficient access to data in JSON (JavaScript Object Notation) documents. Automatic validation of JSON documents stored in JSON columns. …