Add User ring post (#93)

* update

* update ci

* update link to eunomia.dev

* Update documents
This commit is contained in:
云微
2024-01-20 16:57:48 +00:00
committed by GitHub
parent deee286952
commit fe5b53d6cd
40 changed files with 541 additions and 20 deletions

View File

@@ -61,3 +61,7 @@ jobs:
run: |
make -C src/30-sslsniff
sudo timeout -s 2 3 src/30-sslsniff/sslsniff || if [ $? = 124 ]; then exit 0; else exit $?; fi
- name: test 35-user-ringbuf
run: |
make -C src/35-user-ringbuf
sudo timeout -s 2 3 src/35-user-ringbuf/user_ringbuf || if [ $? = 124 ]; then exit 0; else exit $?; fi

View File

@@ -79,7 +79,11 @@ Android:
- [使用 eBPF 替换任意程序读取或写入的文本](src/27-replace/README.md)
- [BPF 的生命周期:使用 Detached 模式在用户态应用退出后持续运行 eBPF 程序](src/28-detach/README.md)
- [eBPF 运行时的安全性与面临的挑战](src/18-further-reading/ebpf-security.zh.md)
- [用户空间 eBPF 运行时:深度解析与应用实践](src\36-userspace-ebpf\README.md)
其他高级特性:
- [eBPF开发实践使用 user ring buffer 向内核异步发送信息](src/35-user-ringbuf/README.md)
- [用户空间 eBPF 运行时:深度解析与应用实践](src/36-userspace-ebpf/README.md)
持续更新中...

View File

@@ -67,7 +67,11 @@ Security:
- [Adding sudo users using eBPF](src/26-sudo/README_en.md)
- [Replacing text read or written by any program using eBPF](src/27-replace/README_en.md)
- [BPF lifecycle: Running eBPF programs continuously in Detached mode after user-mode applications exit](src/28-detach/README_en.md)
- [Userspace eBPF Runtimes: Overview and Applications](src\36-userspace-ebpf\README_en.md)
Other:
- [Using user ring buffer to send information to the kernel](src/35-user-ringbuf/README.md)
- [Userspace eBPF Runtimes: Overview and Applications](src/36-userspace-ebpf/README.md)
Continuously updating...

View File

@@ -168,3 +168,5 @@ eunomia-bpf 由一个编译工具链和一个运行时库组成, 对比传统的
- eunomia-bpf<https://github.com/eunomia-bpf/eunomia-bpf>
您还可以访问我们的教程代码仓库 <https://github.com/eunomia-bpf/bpf-developer-tutorial> 或网站 <https://eunomia.dev/zh/tutorials/> 以获取更多示例和完整的教程源代码。我们会继续分享更多有关 eBPF 开发实践的内容,帮助您更好地理解和掌握 eBPF 技术。
> 原文地址:<https://eunomia.dev/zh/tutorials/0-introduce/> 转载请注明

View File

@@ -191,3 +191,5 @@ eBPF 程序的开发和使用流程可以概括为如下几个步骤:
需要注意的是BPF 程序的执行是在内核空间进行的,因此需要使用特殊的工具和技术来编写、编译和调试 BPF 程序。eunomia-bpf 是一个开源的 BPF 编译器和工具包,它可以帮助开发者快速和简单地编写和运行 BPF 程序。
您还可以访问我们的教程代码仓库 <https://github.com/eunomia-bpf/bpf-developer-tutorial> 以获取更多示例和完整的教程,全部内容均已开源。我们会继续分享更多有关 eBPF 开发实践的内容,帮助您更好地理解和掌握 eBPF 技术。
> 原文地址:<https://eunomia.dev/zh/tutorials/1-helloworld/> 转载请注明出处。

View File

@@ -258,3 +258,5 @@ In this chapter (eBPF Tutorial by Example Ten: Capturing Interrupt Events in eBP
By studying the content of this chapter, you should have mastered the methods of capturing interrupt events with hardirqs or softirqs in eBPF, as well as how to analyze these events to identify performance issues and other problems related to interrupt handling in the kernel. These skills are crucial for analyzing and optimizing the performance of the Linux kernel.
To better understand and practice eBPF programming, we recommend reading the official documentation of eunomia-bpf: <https://github.com/eunomia-bpf/eunomia-bpf>. In addition, we provide a complete tutorial and source code for you to view and learn from at <https://github.com/eunomia-bpf/bpf-developer-tutorial>.
> The original link of this article: <https://eunomia.dev/tutorials/10-hardirqs/>

View File

@@ -628,4 +628,6 @@ If you would like to learn more about eBPF knowledge and practices, please refer
## Reference
- [Building BPF applications with libbpf-bootstrap](https://nakryiko.com/posts/libbpf-bootstrap/)
- <https://github.com/libbpf/libbpf-bootstrap>
- <https://github.com/libbpf/libbpf-bootstrap>
> The original link of this article: <https://eunomia.dev/tutorials/11-bootstrap>

View File

@@ -330,3 +330,5 @@ Through this introductory tutorial on eBPF, we have learned how to use eBPF prog
If you want to learn more about eBPF knowledge and practices, please refer to the official documentation of eunomia-bpf: <https://github.com/eunomia-bpf/eunomia-bpf>. You can also visit our tutorial code repository <https://github.com/eunomia-bpf/bpf-developer-tutorial> or website <https://eunomia.dev/tutorials/> for more examples and complete tutorials.
The next tutorial will further explore advanced features of eBPF. We will continue to share more content about eBPF development practices to help you better understand and master eBPF technology. We hope these contents will be helpful for your learning and practice on the eBPF development journey.
> The original link of this article: <https://eunomia.dev/tutorials/12-profile>

View File

@@ -582,7 +582,7 @@ PID COMM IP SADDR DADDR DPORT LAT(ms)
222774 ssh 4 192.168.88.15 1.15.149.151 22 25.31
```
源代码:<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/13-tcpconnlat>
源代码:<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/13-tcpconnlat> 关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
参考资料:

View File

@@ -567,3 +567,5 @@ In user-space, we introduced the usage of libbpf library APIs, such as perf_buff
If you are interested in learning more about eBPF and its practical applications, please refer to the official documentation of eunomia-bpf: [https://github.com/eunomia-bpf/eunomia-bpf](https://github.com/eunomia-bpf/eunomia-bpf). You can also visit our tutorial code repository at [https://github.com/eunomia-bpf/bpf-developer-tutorial](https://github.com/eunomia-bpf/bpf-developer-tutorial) for more examples and complete tutorials.
In the upcoming tutorials, we will dive deeper into advanced features of eBPF, such as tracing the path of network packets and fine-grained system performance monitoring. We will continue to share more content on eBPF development practices to help you better understand and master eBPF technology. We hope these resources will be valuable in your learning and practical journey with eBPF.
> The original link of this article: <https://eunomia.dev/tutorials/13-tcpconnect>

View File

@@ -405,3 +405,5 @@ References:
In this eBPF introductory tutorial, we learned how to use the tcpstates and tcprtt eBPF example programs to monitor and analyze the connection states and round-trip time of TCP. We understood the working principles and implementation methods of tcpstates and tcprtt, including how to store data using BPF maps, how to retrieve and process TCP connection information in eBPF programs, and how to parse and display the data collected by eBPF programs in user-space applications.
If you would like to learn more about eBPF knowledge and practices, you can visit our tutorial code repository at <https://github.com/eunomia-bpf/bpf-developer-tutorial> or website <https://eunomia.dev/tutorials/> for more examples and complete tutorials. The upcoming tutorials will further explore advanced features of eBPF, and we will continue to share more content about eBPF development practices.
> The original link of this article: <https://eunomia.dev/tutorials/14-tcpstates>

View File

@@ -42,9 +42,7 @@ adjust_time_range
用户级静态定义跟踪User-level Statically Defined Tracing, USDT则可以在某种程度上解决这些问题。USDT 探针(或者称为用户级 "marker")是开发者在代码的关键位置插入的跟踪宏,提供稳定且已经过文档说明的 API。这使得跟踪工作变得更加简单。
使用 USDT我们可以简单地跟踪一个名为 `mysql:query__start` 的探针,而不是去跟踪那个名为 `_Z16dispatch_command19enum_server_commandP3THDPcj` 的 C++ 符号,也就是 `dispatch_command()` 函数。当然,我们仍然可以在需要的时候去跟踪 `dispatch_command()` 以及
其他 21,000 个 mysqld 函数,但只有当 USDT 探针无法解决问题的时候我们才需要这么做。
使用 USDT我们可以简单地跟踪一个名为 `mysql:query__start` 的探针,而不是去跟踪那个名为 `_Z16dispatch_command19enum_server_commandP3THDPcj` 的 C++ 符号,也就是 `dispatch_command()` 函数。当然,我们仍然可以在需要的时候去跟踪 `dispatch_command()` 以及其他 21,000 个 mysqld 函数,但只有当 USDT 探针无法解决问题的时候我们才需要这么做。
在 Linux 中的 USDT无论是哪种形式的静态跟踪点其实都已经存在了几十年。它最近由于 Sun 的 DTrace 工具的流行而再次受到关注,这使得许多常见的应用程序,包括 MySQL、PostgreSQL、Node.js、Java 等都加入了 USDT。SystemTap 则开发了一种可以消费这些 DTrace 探针的方式。
@@ -73,6 +71,8 @@ Notes at offset 0x00c43058 with length 0x00000494:
在这一点上,你可以使用 SystemTap 或者 LTTng 来跟踪这些探针。然而,内置的 Linux 跟踪器,比如 ftrace 和 perf_events目前还无法做到这一点尽管 perf_events 的支持正在开发中)。
USDT 在内核态 eBPF 运行时,也可能产生比较大的性能开销,这时候也可以考虑使用用户态 eBPF 运行时,例如 [bpftime](https://github.com/eunomia-bpf/bpftime)。bpftime 是一个基于 LLVM JIT/AOT 的用户态 eBPF 运行时,它可以在用户态运行 eBPF 程序,和内核态的 eBPF 兼容,避免了内核态和用户态之间的上下文切换,从而提高了 eBPF 程序的执行效率。对于 uprobe 而言bpftime 的性能开销比 kernel 小一个数量级。
## Java GC 介绍
Java 作为一种高级编程语言其自动垃圾回收GC是其核心特性之一。Java GC 的目标是自动地回收那些不再被程序使用的内存空间从而减轻程序员在内存管理方面的负担。然而GC 过程可能会引发应用程序的停顿,对程序的性能和响应时间产生影响。因此,对 Java GC 事件进行监控和分析,对于理解和优化 Java 应用的性能是非常重要的。
@@ -323,3 +323,5 @@ TIME CPU PID GC TIME
此外,我们也介绍了一些关于 Java GC、USDT 和 eBPF 的基础知识和实践技巧,这些知识和技巧对于想要在网络和系统性能分析领域深入研究的开发者来说是非常有价值的。
如果您希望学习更多关于 eBPF 的知识和实践,可以访问我们的教程代码仓库 <https://github.com/eunomia-bpf/bpf-developer-tutorial> 或网站 <https://eunomia.dev/zh/tutorials/> 以获取更多示例和完整的教程。
> The original link of this article: <https://eunomia.dev/tutorials/15-javagc>

View File

@@ -75,6 +75,8 @@ Java, as a high-level programming language, has automatic garbage collection (GC
In the following tutorial, we will demonstrate how to use eBPF and USDT to monitor and analyze the duration of Java GC events. We hope this content will be helpful to you in your work with eBPF for application performance analysis.
USDT in kernel mode eBPF runtime may also cause relatively large performance overhead. In this case, you can also consider using user mode eBPF runtime, such as [bpftime](https://github.com/eunomia-bpf/bpftime). bpftime is a user mode eBPF runtime based on LLVM JIT/AOT. It can run eBPF programs in user mode and is compatible with kernel mode eBPF, avoiding context switching between kernel mode and user mode, thereby improving the execution efficiency of eBPF programs by 10 times.
## eBPF Implementation Mechanism
The eBPF program for Java GC is divided into two parts: kernel space and user space. We will introduce the implementation mechanisms of these two parts separately.

View File

@@ -44,7 +44,7 @@ Attaching to pid 5193, Ctrl+C to quit.
在基本层面上,`memleak` 的工作方式类似于在内存分配和释放路径上安装监控设备。它通过在内存分配和释放函数中插入 eBPF 程序来达到这个目标。这意味着,当这些函数被调用时,`memleak` 就会记录一些重要信息,如调用者的进程 IDPID、分配的内存地址以及分配的内存大小等。当释放内存的函数被调用时`memleak` 则会在其内部的映射表map中删除相应的内存分配记录。这种机制使得 `memleak` 能够准确地追踪到哪些内存块已被分配但未被释放。
对于用户态的常用内存分配函数,如 `malloc``calloc` 等,`memleak` 利用了用户态探测uprobe技术来实现监控。uprobe 是一种用于用户空间应用程序的动态追踪技术,它可以在运行时不修改二进制文件的情况下在任意位置设置断点,从而实现对特定函数调用的追踪。
对于用户态的常用内存分配函数,如 `malloc``calloc` 等,`memleak` 利用了用户态探测uprobe技术来实现监控。uprobe 是一种用于用户空间应用程序的动态追踪技术,它可以在运行时不修改二进制文件的情况下在任意位置设置断点,从而实现对特定函数调用的追踪。Uprobe 在内核态 eBPF 运行时,也可能产生比较大的性能开销,这时候也可以考虑使用用户态 eBPF 运行时,例如 [bpftime](https://github.com/eunomia-bpf/bpftime)。bpftime 是一个基于 LLVM JIT/AOT 的用户态 eBPF 运行时,它可以在用户态运行 eBPF 程序,和内核态的 eBPF 兼容,避免了内核态和用户态之间的上下文切换,从而提高了 eBPF 程序的执行效率。对于 uprobe 而言bpftime 的性能开销比 kernel 小一个数量级。
对于内核态的内存分配函数,如 `kmalloc` 等,`memleak` 则选择使用了 tracepoint 来实现监控。Tracepoint 是一种在 Linux 内核中提供的动态追踪技术,它可以在内核运行时动态地追踪特定的事件,而无需重新编译内核或加载内核模块。
@@ -455,9 +455,7 @@ int attach_uprobes(struct memleak_bpf *skel)
注意一些内存分配函数可能并不存在或已弃用比如valloc、pvalloc等因此它们的附加可能会失败。在这种情况下我们允许附加失败并不会阻止程序的执行。这是因为我们更关注的是主流和常用的内存分配函数而这些已经被弃用的函数往往在实际应用中较少使用。
完整的源代码:<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/16-memleak>
参考:<https://github.com/iovisor/bcc/blob/master/libbpf-tools/memleak.c>
完整的源代码:<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/16-memleak> 关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
## 编译运行
@@ -487,3 +485,5 @@ Tracing outstanding memory allocs... Hit Ctrl-C to end
您可以访问我们的教程代码仓库 <https://github.com/eunomia-bpf/bpf-developer-tutorial> 或网站 <https://eunomia.dev/zh/tutorials/> 以获取更多示例和完整的教程。
接下来的教程将进一步探讨 eBPF 的高级特性,我们会继续分享更多有关 eBPF 开发实践的内容。希望这些知识和技巧能帮助您更好地了解和使用 eBPF以解决实际工作中遇到的问题。
参考资料:<https://github.com/iovisor/bcc/blob/master/libbpf-tools/memleak.c>

View File

@@ -42,6 +42,8 @@ Over time, it becomes evident that the `main` function of the `allocs` process i
At a basic level, `memleak` operates by installing monitoring devices on the memory allocation and deallocation paths. It achieves this by inserting eBPF programs into memory allocation and deallocation functions. This means that when these functions are called, `memleak` will record important information, such as the caller's process ID (PID), the allocated memory address, and the size of the allocated memory. When the function for freeing memory is called, `memleak` will delete the corresponding memory allocation record in its internal map. This mechanism allows `memleak` to accurately trace which memory blocks have been allocated but not deallocated.For commonly used memory allocation functions in user space, such as `malloc` and `calloc`, `memleak` uses user space probing (uprobe) technology for monitoring. Uprobe is a dynamic tracing technology for user space applications, which can set breakpoints at any location at runtime without modifying the binary files, thus achieving tracing of specific function calls.
Uprobe in kernel mode eBPF runtime may also cause relatively large performance overhead. In this case, you can also consider using user mode eBPF runtime, such as [bpftime](https://github.com/eunomia-bpf/bpftime). bpftime is a user mode eBPF runtime based on LLVM JIT/AOT. It can run eBPF programs in user mode and is compatible with kernel mode eBPF, avoiding context switching between kernel mode and user mode, thereby improving the execution efficiency of eBPF programs by 10 times.
For kernel space memory allocation functions, such as `kmalloc`, `memleak` chooses to use tracepoints for monitoring. Tracepoint is a dynamic tracing technology provided in the Linux kernel, which can dynamically trace specific events in the kernel at runtime without recompiling the kernel or loading kernel modules.
## Kernel Space eBPF Program Implementation
@@ -442,3 +444,4 @@ Through this eBPF introductory tutorial, you have learned how to write a Memleak
You can visit our tutorial code repository at <https://github.com/eunomia-bpf/bpf-developer-tutorial> or website <https://eunomia.dev/tutorials/> for more examples and complete tutorials.
> The original link of this article: <https://eunomia.dev/tutorials/16-memleak>

View File

@@ -20,7 +20,7 @@ eBPF扩展的伯克利数据包过滤器是 Linux 内核中的一种新技
Biopattern 可以统计随机/顺序磁盘I/O次数的比例。
首先,确保你已经正确安装了 libbpf 和相关的工具集,可以在这里找到对应的源代码:[bpf-developer-tutorial](https://github.com/eunomia-bpf/bpf-developer-tutorial)
首先,确保你已经正确安装了 libbpf 和相关的工具集,可以在这里找到对应的源代码:[bpf-developer-tutorial](https://github.com/eunomia-bpf/bpf-developer-tutorial) 关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
导航到 `biopattern` 的源代码目录,并使用 `make` 命令进行编译:

View File

@@ -328,3 +328,5 @@ You can visit our tutorial code repository [at https://github.com/eunomia-bpf/bp
- Source repo<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/17-biopattern>
- bcc tool<https://github.com/iovisor/bcc/blob/master/libbpf-tools/biopattern.c>
> The original link of this article: <https://eunomia.dev/tutorials/17-biopattern>

View File

@@ -130,3 +130,5 @@ eBPF is a new technology which allows dynamically loading pieces of code into th
Low-power operating system runtimes used on IoT microcontrollers typically provide rudimentary APIs, basic connectivity and, sometimes, a (secure) firmware update mechanism. In contrast, on less constrained hardware, networked software has entered the age of serverless, microservices and agility. With a view to bridge this gap, in the paper we design Femto-Containers, a new middleware runtime which can be embedded on heterogeneous low-power IoT devices. Femto-Containers enable the secure deployment, execution and isolation of small virtual software functions on low-power IoT devices, over the network. We implement Femto-Containers, and provide integration in RIOT, a popular open source IoT operating system. We then evaluate the performance of our implementation, which was formally verified for fault-isolation, guaranteeing that RIOT is shielded from logic loaded and executed in a Femto-Container. Our experiments on various popular micro-controller architectures (Arm Cortex-M, ESP32 and RISC-V) show that Femto-Containers offer an attractive trade-off in terms of memory footprint overhead, energy consumption, and security.
<https://dl.acm.org/doi/abs/10.1145/3528535.3565242>
> The original link of this article: <https://eunomia.dev/tutorials/18-further-reading>

View File

@@ -166,3 +166,5 @@ If you want to learn more about eBPF knowledge and practices, you can visit our
+ <https://github.com/leodido/demo-cloud-native-ebpf-day>
+ <https://aya-rs.dev/book/programs/lsm/#writing-lsm-bpf-program>
> The original link of this article: <https://eunomia.dev/tutorials/19-lsm-connect>

View File

@@ -107,4 +107,5 @@ If you want to learn more about eBPF knowledge and practice, you can visit our t
+ <http://just4coding.com/2022/08/05/tc/>
+ <https://arthurchiao.art/blog/understanding-tc-da-mode-zh/>
"
> The original link of this article: <https://eunomia.dev/tutorials/20-tc>

View File

@@ -102,3 +102,5 @@ For more information, you can refer to:
+ <http://arthurchiao.art/blog/xdp-paper-acm-2018-zh/>
+ <http://arthurchiao.art/blog/linux-net-stack-implementation-rx-zh/>
+ <https://github.com/xdp-project/xdp-tutorial/tree/master/basic01-xdp-pass>
> The original link of this article: <https://eunomia.dev/tutorials/21-xdp>

View File

@@ -146,3 +146,5 @@ If you want to learn more about eBPF knowledge and practice, you can visit our t
+ [Google android docs](https://source.android.google.cn/docs/core/architecture/kernel/bpf)
+ [weixin WeiShu](https://mp.weixin.qq.com/s/mul4n5D3nXThjxuHV7GpMA)
+ [SeeFlowerX](https://blog.seeflower.dev/archives/138/>)
> The original link of this article: <https://eunomia.dev/tutorials/22-android>

View File

@@ -452,7 +452,7 @@ return skb->len;
### 编译运行
完整的源代码可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/23-http> 中找到。编译运行上述代码:
完整的源代码可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/23-http> 中找到。关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/> 编译运行上述代码:
```console
$ git submodule update --init --recursive
@@ -648,3 +648,5 @@ char _license[] SEC("license") = "GPL";
- 教程内容包括开发eBPF程序、使用eBPF工具链和实施HTTP请求的追踪。
通过这篇文章读者可以获得深入了解如何使用eBPF技术来追踪七层协议尤其是HTTP流量的知识。这将有助于更好地监控和分析网络流量从而提高应用程序性能和安全性。如果您希望学习更多关于 eBPF 的知识和实践,可以访问我们的教程代码仓库 <https://github.com/eunomia-bpf/bpf-developer-tutorial> 或网站 <https://eunomia.dev/zh/tutorials/> 以获取更多示例和完整的教程。
> 原文地址:<https://eunomia.dev/zh/tutorials/23-http/> 转载请注明出处。

View File

@@ -635,3 +635,5 @@ In today's complex technological landscape, system observability has become cruc
- The tutorial covers the development of eBPF programs, the use of the eBPF toolchain, and the implementation of HTTP request tracing.
Through this article, readers can gain a deep understanding of how to use eBPF technology for tracing seven-layer protocols, particularly HTTP traffic. This knowledge will help enhance the monitoring and analysis of network traffic, thereby improving application performance and security. If you're interested in learning more about eBPF and its practical applications, you can visit our tutorial code repository at <https://github.com/eunomia-bpf/bpf-developer-tutorial> or our website at <https://eunomia.dev/tutorials/> for more examples and complete tutorials.
> The original link of this article: <https://eunomia.dev/tutorials/23-http>

View File

@@ -425,3 +425,5 @@ yunwei 31583 0.0 0.0 17712 2612 pts/1 S+ 05:42 0:00 grep --color=
## Summary
You can also visit our tutorial code repository [at https://github.com/eunomia-bpf/bpf-developer-tutorial](https://github.com/eunomia-bpf/bpf-developer-tutorial) or our website [at https://eunomia.dev/zh/tutorials/](https://eunomia.dev/zh/tutorials/) for more examples and the full tutorial.
> The original link of this article: <https://eunomia.dev/tutorials/24-hide>

View File

@@ -196,3 +196,5 @@ Lastly, if you are interested in eBPF technology and wish to further understand
- <https://github.com/pathtofile/bad-bpf>
- <https://www.mail-archive.com/netdev@vger.kernel.org/msg296358.html>
> The original link of this article: <https://eunomia.dev/tutorials/25-signal>

View File

@@ -2,6 +2,8 @@
本文完整的源代码:<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/26-sudo>
关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
编译:
```bash

View File

@@ -1,5 +1,9 @@
# 使用 eBPF 替换任意程序读取或写入的文本
完整源代码:<https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/27-replace>
关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
编译:
```bash

View File

@@ -1,4 +1,6 @@
# Replace Text Read or Written by Any Program with eBPF
# Replace Text Read or Written by Any Program with eBPF
See <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/27-replace> for the full source code.
Compile:

View File

@@ -77,7 +77,7 @@ int pin_link(struct bpf_link *link, const char* path)
## 运行示例
在这个示例中,我们将继续使用前一节中的字符串替换示例来演示在应用程序退出后运行 eBPF 程序的方法,并展示潜在的安全风险。通过使用 `--detach` 参数运行该程序,可以使用户空间加载程序在不停止 eBPF 程序的情况下退出。完整的示例代码可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/28-detach> 中找到。
在这个示例中,我们将继续使用前一节中的字符串替换示例来演示在应用程序退出后运行 eBPF 程序的方法,并展示潜在的安全风险。通过使用 `--detach` 参数运行该程序,可以使用户空间加载程序在不停止 eBPF 程序的情况下退出。完整的示例代码可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/28-detach> 中找到。关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
在运行之前,请确保已经挂载了 BPF 文件系统:
@@ -113,3 +113,5 @@ sudo rm -r /sys/fs/bpf/textreplace
- [bad-bpf](https://github.com/pathtofile/bad-bpf)
- [Object Lifetime in the Linux kernel](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html)
- [BPFMan: A Novel Way to Manage eBPF—Beyond Capsule Mode](https://bpfman.io/main/blog/2023/09/07/bpfman-a-novel-way-to-manage-ebpf)
> 原文地址:<https://eunomia.dev/zh/tutorials/28-detach/>

View File

@@ -126,3 +126,5 @@ You can visit our tutorial code repository [at https://github.com/eunomia-bpf/bp
- <https://github.com/pathtofile/bad-bpf>
- <https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html>
- <https://bpfman.io/main/blog/2023/09/07/bpfman-a-novel-way-to-manage-ebpf>
> The original link of this article: <https://eunomia.dev/tutorials/28-detach>

View File

@@ -124,7 +124,7 @@ int bpf_sockops_handler(struct bpf_sock_ops *skops){
### 编译 eBPF 程序
这里我们使用 libbpf 编译这个 eBPF 程序。完整的源代码和工程可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/29-sockops> 中找到。
这里我们使用 libbpf 编译这个 eBPF 程序。完整的源代码和工程可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/29-sockops> 中找到。关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
```shell
# Compile the bpf program with libbpf
@@ -244,3 +244,5 @@ sudo ./unload.sh
- <https://github.com/zachidan/ebpf-sockops>
- <https://github.com/merbridge/merbridge>
> 原文地址:<https://eunomia.dev/zh/tutorials/29-sockops/> 转载请注明出处。

View File

@@ -244,3 +244,5 @@ Finally, if you are interested in eBPF technology and want to learn more and pra
- <https://github.com/zachidan/ebpf-sockops>
- <https://github.com/merbridge/merbridge>
> The original link of this article: <https://eunomia.dev/tutorials/29-sockops>

View File

@@ -430,6 +430,8 @@ void print_event(struct probe_SSL_data_t *event, const char *evt) {
## 编译与运行
关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
要开始使用 `sslsniff`,首先要进行编译:
```sh

View File

@@ -540,3 +540,5 @@ References:
- <https://www.openssl.org/docs/man1.1.1/man3/SSL_read.html>
- <https://github.com/iovisor/bcc/blob/master/tools/sslsniff_example.txt>
- <https://en.wikipedia.org/wiki/Transport_Layer_Security>
> The original link of this article: <https://eunomia.dev/tutorials/30-sslsniff>

View File

@@ -1,3 +1,223 @@
# user ring buffer
# eBPF开发实践使用 user ring buffer 向内核异步发送信息
maps between kernel and userspace
eBPF即扩展的Berkeley包过滤器Extended Berkeley Packet Filter是Linux内核中的一种革命性技术它允许开发者在内核态中运行自定义的“微程序”从而在不修改内核代码的情况下改变系统行为或收集系统细粒度的性能数据。
eBPF的一个独特之处是它不仅可以在内核态运行程序从而访问系统底层的状态和资源同时也可以通过特殊的数据结构与用户态程序进行通信。关于这方面的一个重要概念就是内核态和用户态之间的环形队列——ring buffer。在许多实时或高性能要求的应用中环形队列是一种常用的数据结构。由于它的FIFO先进先出特性使得数据在生产者和消费者之间可以持续、线性地流动从而避免了频繁的IO操作和不必要的内存 reallocation开销。
在eBPF中分别提供了两种环形队列: user ring buffer 和 kernel ring buffer以实现用户态和内核态之间的高效数据通信。本文是 eBPF 开发者教程的一部分,更详细的内容可以在这里找到:<https://eunomia.dev/tutorials/> 源代码在 [GitHub 仓库](https://github.com/eunomia-bpf/bpf-developer-tutorial) 中开源。
## 用户态和内核态环形队列—user ring buffer和kernel ring buffer
围绕内核态和用户态这两个主要运行级别eBPF提供了两种相应的环形队列数据结构用户态环形队列——User ring buffer和内核态环形队列——Kernel ring buffer。
Kernel ring buffer 则由 eBPF实现专为Linux内核设计用于追踪和记录内核日志、性能统计信息等它的能力是内核态和用户态数据传输的核心可以从内核态向用户态传送数据。Kernel ring buffer 在 5.7 版本的内核中被引入,目前已经被广泛应用于内核日志系统、性能分析工具等。
对于内核态往用户态发送应用场景如内核监控事件的发送、异步通知、状态更新通知等ring buffer 数据结构都能够胜任。比如当我们需要监听网络服务程序的大量端口状态时这些端口的开启、关闭、错误等状态更新就需由内核实时传递到用户空间进行处理。而Linux 内核的日志系统、性能分析工具等也需要频繁地将大量数据发送到用户空间以支持用户人性化地展示和分析这些数据。在这些场景中ring buffer在内核态往用户态发送数据中表现出了极高的效率。
User ring buffer 是基于环形缓冲器的一种新型 Map 类型,它提供了单用户空间生产者/单内核消费者的语义。这种环形队列的优点是对异步消息传递提供了优秀的支持避免了不必要的同步操作使得内核到用户空间的数据传输可以被优化并且降低了系统调用的系统开销。User ring buffer 在 6.1 版本的内核中被引入,目前的使用场景相对较少。
bpftime 是一个用户空间 eBPF 运行时,允许现有 eBPF 应用程序在非特权用户空间使用相同的库和工具链运行。它为 eBPF 提供了 Uprobe 和 Syscall 跟踪点,与内核 Uprobe 相比,性能有了显著提高,而且无需手动检测代码或重启进程。运行时支持用户空间共享内存中的进程间 eBPF 映射,也兼容内核 eBPF 映射,允许与内核 eBPF 基础架构无缝运行。它包括一个适用于各种架构的高性能 LLVM JIT以及一个适用于 x86 的轻量级 JIT 和一个解释器。GitHub 地址:<https://github.com/eunomia-bpf/bpftime>
在 bpftime 中,我们使用 user ring buffer 来实现用户态 eBPF 往内核态 eBPF 发送数据,并更新内核态 eBPF 对应的 maps让内核态和用户态的 eBPF 一起协同工作。user ring buffer 的异步特性,可以避免系统调用不必要的同步操作,从而提高了内核态和用户态之间的数据传输效率。
eBPF 的双向环形队列也和 io_uring 在某些方面有相似之处,但它们的设计初衷和应用场景有所不同:
- **设计焦点**io_uring主要专注于提高异步I/O操作的性能和效率而eBPF的环形队列更多关注于内核和用户空间之间的数据通信和事件传输。
- **应用范围**io_uring主要用于文件I/O和网络I/O的场景而eBPF的环形队列则更广泛不限于I/O操作还包括系统调用跟踪、网络数据包处理等。
- **灵活性和扩展性**eBPF提供了更高的灵活性和扩展性允许用户定义复杂的数据处理逻辑并在内核态执行。
下面,我们将通过一段代码示例,详细展示如何利用 user ring buffer实现从用户态向内核传送数据并以 kernel ring buffer 相应地从内核态向用户态传送数据。
## 一、实现:在用户态和内核态间使用 ring buffer 传送数据
借助新的 BPF MAP我们可以实现在用户态和内核态间通过环形缓冲区传送数据。在这个示例中我们将详细说明如何在用户空间创建一个 "用户环形缓冲区" (user ring buffer) 并向其写入数据,然后在内核空间中通过 `bpf_user_ringbuf_drain` 函数来消费这些数据。同时,我们也会使用 "内核环形缓冲区" (kernel ring buffer) 来从内核空间反馈数据到用户空间。为此,我们需要在用户空间和内核空间分别创建并操作这两个环形缓冲区。
完整的代码可以在 <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/35-user-ringbuf> 中找到。
### 创建环形缓冲区
在内核空间,我们创建了一个类型为 `BPF_MAP_TYPE_USER_RINGBUF``user_ringbuf`,以及一个类型为 `BPF_MAP_TYPE_RINGBUF``kernel_ringbuf`。在用户空间,我们创建了一个 `struct ring_buffer_user` 结构体的实例,并通过 `ring_buffer_user__new` 函数和对应的操作来管理这个用户环形缓冲区。
```c
/* Set up ring buffer polling */
rb = ring_buffer__new(bpf_map__fd(skel->maps.kernel_ringbuf), handle_event, NULL, NULL);
if (!rb)
{
err = -1;
fprintf(stderr, "Failed to create ring buffer\n");
goto cleanup;
}
user_ringbuf = user_ring_buffer__new(bpf_map__fd(skel->maps.user_ringbuf), NULL);
```
### 编写内核态程序
我们定义一个 `kill_exit` 的 tracepoint 程序,每当有进程退出时,它会通过 `bpf_user_ringbuf_drain` 函数读取 `user_ringbuf` 中的用户数据,然后通过 `bpf_ringbuf_reserve` 函数在 `kernel_ringbuf` 中创建一个新的记录,并写入相关信息。最后,通过 `bpf_ringbuf_submit` 函数将这个记录提交,使得该记录能够被用户空间读取。
```c
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "user_ringbuf.h"
char _license[] SEC("license") = "GPL";
struct
{
__uint(type, BPF_MAP_TYPE_USER_RINGBUF);
__uint(max_entries, 256 * 1024);
} user_ringbuf SEC(".maps");
struct
{
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} kernel_ringbuf SEC(".maps");
int read = 0;
static long
do_nothing_cb(struct bpf_dynptr *dynptr, void *context)
{
struct event *e;
pid_t pid;
/* get PID and TID of exiting thread/process */
pid = bpf_get_current_pid_tgid() >> 32;
/* reserve sample from BPF ringbuf */
e = bpf_ringbuf_reserve(&kernel_ringbuf, sizeof(*e), 0);
if (!e)
return 0;
e->pid = pid;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
/* send data to user-space for post-processing */
bpf_ringbuf_submit(e, 0);
__sync_fetch_and_add(&read, 1);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_kill")
int kill_exit(struct trace_event_raw_sys_exit *ctx)
{
long num_samples;
int err = 0;
// receive data from userspace
num_samples = bpf_user_ringbuf_drain(&user_ringbuf, do_nothing_cb, NULL, 0);
return 0;
}
```
### 编写用户态程序
在用户空间,我们通过 `ring_buffer_user__reserve` 函数在 ring buffer 中预留出一段空间,这段空间用于写入我们希望传递给内核的信息。然后,通过 `ring_buffer_user__submit` 函数提交数据,之后这些数据就可以在内核态被读取。
```c
static int write_samples(struct user_ring_buffer *ringbuf)
{
int i, err = 0;
struct user_sample *entry;
entry = user_ring_buffer__reserve(ringbuf, sizeof(*entry));
if (!entry)
{
err = -errno;
goto done;
}
entry->i = getpid();
strcpy(entry->comm, "hello");
int read = snprintf(entry->comm, sizeof(entry->comm), "%u", i);
if (read <= 0)
{
/* Assert on the error path to avoid spamming logs with
* mostly success messages.
*/
err = read;
user_ring_buffer__discard(ringbuf, entry);
goto done;
}
user_ring_buffer__submit(ringbuf, entry);
done:
drain_current_samples();
return err;
}
```
### 初始化环形缓冲区并轮询
最后,对 ring buffer 进行初始化并定时轮询,这样我们就可以实时得知内核态的数据消费情况,我们还可以在用户空间对 `user_ringbuf` 进行写入操作,然后在内核态对其进行读取和处理。
```c
write_samples(user_ringbuf);
/* Process events */
printf("%-8s %-5s %-16s %-7s %-7s %s\n",
"TIME", "EVENT", "COMM", "PID", "PPID", "FILENAME/EXIT CODE");
while (!exiting)
{
err = ring_buffer__poll(rb, 100 /* timeout, ms */);
/* Ctrl-C will cause -EINTR */
if (err == -EINTR)
{
err = 0;
break;
}
if (err < 0)
{
printf("Error polling perf buffer: %d\n", err);
break;
}
}
```
通过以上步骤,我们实现了用户态与内核态间环形缓冲区的双向数据传输。
## 二、编译和运行代码
为了编译和运行以上代码,我们可以通过以下命令来实现:
```sh
make
```
关于如何安装依赖,请参考:<https://eunomia.dev/tutorials/11-bootstrap/>
运行结果将展示如何使用 user ring buffer 和 kernel ringbuffer 在用户态和内核态间进行高效的数据传输:
```console
$ sudo ./user_ringbuf
Draining current samples...
TIME EVENT COMM PID
16:31:37 SIGN node 1707
Draining current samples...
16:31:38 SIGN node 1981
Draining current samples...
16:31:38 SIGN node 1707
Draining current samples...
16:31:38 SIGN node 1707
Draining current samples...
```
## 总结
在本篇文章中我们介绍了如何使用eBPF的user ring buffer和kernel ring buffer在用户态和内核态之间进行数据传输。通过这种方式我们可以有效地将用户态的数据传送给内核或者将内核生成的数据反馈给用户从而实现了内核态和用户态的双向通信。
如果您希望学习更多关于 eBPF 的知识和实践,可以访问我们的教程代码仓库 <https://github.com/eunomia-bpf/bpf-developer-tutorial> 或网站 <https://eunomia.dev/zh/tutorials/> 以获取更多示例和完整的教程。
参考资料:
1. [https://lwn.net/Articles/907056/](https://lwn.net/Articles/907056/)
> 原文地址:<https://eunomia.dev/zh/tutorials/35-user-ringbuf/> 转载请注明出处。

View File

@@ -0,0 +1,223 @@
# eBPF Development Practices: Asynchronously Send to Kernel with User Ring Buffer
eBPF, or Extended Berkeley Packet Filter, is a revolutionary technology in the Linux kernel that allows developers to run custom "micro programs" in kernel mode, thereby changing system behavior or collecting fine-grained performance data without modifying kernel code.
One unique aspect of eBPF is that it not only allows programs to run in kernel mode to access low-level system states and resources, but it can also communicate with user mode programs through special data structures. One important concept in this regard is the ring buffer between kernel mode and user mode. In many real-time or high-performance applications, the ring buffer is a commonly used data structure. Due to its FIFO (first in, first out) characteristics, data can flow continuously and linearly between the producer and the consumer, avoiding frequent IO operations and unnecessary memory reallocation overhead.
In eBPF, two types of ring buffers are provided: user ring buffer and kernel ring buffer, to achieve efficient data communication between user mode and kernel mode. This article is part of the eBPF developer tutorial. More detailed content can be found here: <https://eunomia.dev/tutorials/> The source code is open source in the <https://github.com/eunomia-bpf/bpf-developer-tutorial>.
## User mode and kernel mode ring buffers—user ring buffer and kernel ring buffer
Around the two main run levels of kernel mode and user mode, eBPF provides two corresponding ring buffer data structures: User ring buffer and Kernel ring buffer.
Kernel ring buffer is implemented by eBPF and is specially designed for the Linux kernel to track and record kernel logs, performance statistics, etc. It is the core of data transfer from kernel mode to user mode and can send data from kernel mode to user mode. Kernel ring buffer was introduced in the 5.7 version of the kernel and is now widely used in the kernel logging system, performance analysis tools, etc.
For scenarios where the kernel sends to user mode, such as sending kernel monitoring events, asynchronous notifications, status update notifications, etc., the ring buffer data structure can handle them. For example, when we need to monitor the status of a large number of ports of network service programs, the opening, closing, errors, and other status updates of these ports need to be real-time transferred to the user space for processing. Linux kernel's logging system, performance analysis tools, etc., also need to frequently send large amounts of data to user space to support user-friendly display and analysis of these data. In these scenarios, the ring buffer shows extremely high efficiency in sending data from the kernel to the user.
User ring buffer is a new type of Map type based on the ring buffer, it provides the semantics of a single user space producer/single kernel consumer. The advantage of this ring buffer is that it provides excellent support for asynchronous message passing, avoiding unnecessary synchronization operations, optimizing data transfer from the kernel to user space, and reducing the system overhead of system calls. User ring buffer was introduced in the 6.1 version of the kernel and its current use cases are relatively limited.
bpftime is a user space eBPF runtime that allows existing eBPF applications to run in unprivileged user space using the same libraries and toolchain. It provides Uprobe and Syscall tracing points for eBPF, which significantly improves performance compared to kernel Uprobe and does not require manual code detection or process restart. The runtime supports process eBPF mapping in user space shared memory, and is also compatible with kernel eBPF mapping, allowing seamless operation with the kernel eBPF infrastructure. It includes a high-performance LLVM JIT for various architectures, a lightweight JIT for x86, and an interpreter. GitHub address: <https://github.com/eunomia-bpf/bpftime>
In bpftime, we use the user ring buffer to implement data transmission from user mode eBPF to kernel mode eBPF, and update the maps corresponding to kernel mode eBPF, so that kernel mode and user mode eBPF can work together. The asynchronous characteristics of user ring buffer can avoid unnecessary synchronization operations of system calls, thereby improving the efficiency of data transmission between kernel mode and user mode.
The bi-directional ring buffer of eBPF also has similarities to io_uring in some respects, but their design intentions and use cases are different:
- **Design focus**: io_uring primarily focuses on improving the performance and efficiency of asynchronous I/O operations, while eBPF's ring buffer focuses more on data communication and event transmission between the kernel and user space.
- **Application range**: io_uring is mainly used in file I/O and network I/O scenarios, while eBPF's ring buffer is more widespread, not limited to I/O operations, but also including system call tracing, network packet processing, etc.
- **Flexibility and extensibility**: eBPF provides higher flexibility and extensibility, allowing users to define complex data processing logic and execute it in kernel mode.
Following is a code example where we will show in detail how to use user ring buffer to transmit data from user mode to the kernel, and how to respond accordingly with kernel ring buffer to transmit data from kernel mode to user mode.
## I. Implementation: Using Ring Buffer to Transfer Data Between User Mode and Kernel Mode
With the help of the new BPF MAP, we can implement the transfer of data between user mode and kernel mode through the ring buffer. In this example, we will detail how to create a "user ring buffer" in user space and write data to it and then consume this data in kernel space with the `bpf_user_ringbuf_drain` function. At the same time, we will use the "kernel ring buffer" to feed back data from kernel space to user space. To do this, we need to create and operate these two ring buffers separately in user space and kernel space.
The complete code can be found at <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/35-user-ringbuf>.
### Create Ring Buffer
In kernel mode, we created a `user_ringbuf` of type `BPF_MAP_TYPE_USER_RINGBUF` and a `kernel_ringbuf` of type `BPF_MAP_TYPE_RINGBUF`. In user mode, we created an instance of the `struct ring_buffer_user` structure and managed this user ring buffer through the `ring_buffer_user__new` function and corresponding operations.
```c
/* Set up ring buffer polling */
rb = ring_buffer__new(bpf_map__fd(skel->maps.kernel_ringbuf), handle_event, NULL, NULL);
if (!rb)
{
err = -1;
fprintf(stderr, "Failed to create ring buffer\n");
goto cleanup;
}
user_ringbuf = user_ring_buffer__new(bpf_map__fd(skel->maps.user_ringbuf), NULL);
```
### Writing Kernel Mode Programs
We define a `kill_exit` tracepoint program that will read user data from `user_ringbuf` with the `bpf_user_ringbuf_drain` function whenever a process exits. Then, it creates a new record in `kernel_ringbuf` with the `bpf_ringbuf_reserve` function and writes relevant information. Finally, the record is submitted with the `bpf_ringbuf_submit` function so that it can be read by user mode.
```c
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "user_ringbuf.h"
char _license[] SEC("license") = "GPL";
struct
{
__uint(type, BPF_MAP_TYPE_USER_RINGBUF);
__uint(max_entries, 256 * 1024);
} user_ringbuf SEC(".maps");
struct
{
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} kernel_ringbuf SEC(".maps");
int read = 0;
static long
do_nothing_cb(struct bpf_dynptr *dynptr, void *context)
{
struct event *e;
pid_t pid;
/* get PID and TID of exiting thread/process */
pid = bpf_get_current_pid_tgid() >> 32;
/* reserve sample from BPF ringbuf */
e = bpf_ringbuf_reserve(&kernel_ringbuf, sizeof(*e), 0);
if (!e)
return 0;
e->pid = pid;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
/* send data to user-space for post-processing */
bpf_ringbuf_submit(e, 0);
__sync_fetch_and_add(&read, 1);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_kill")
int kill_exit(struct trace_event_raw_sys_exit *ctx)
{
long num_samples;
int err = 0;
// receive data from userspace
num_samples = bpf_user_ringbuf_drain(&user_ringbuf, do_nothing_cb, NULL, 0);
return 0;
}
```
### Writing User Mode Programs
In user mode, we reserved a section of space in the ring buffer with the `ring_buffer_user__reserve` function. This space is used to write the information we want to pass to the kernel. Then, the data is submitted using the `ring_buffer_user__submit` function, after which this data can be read and processed in kernel mode.
```c
static int write_samples(struct user_ring_buffer *ringbuf)
{
int i, err = 0;
struct user_sample *entry;
entry = user_ring_buffer__reserve(ringbuf, sizeof(*entry));
if (!entry)
{
err = -errno;
goto done;
}
entry->i = getpid();
strcpy(entry->comm, "hello");
int read = snprintf(entry->comm, sizeof(entry->comm), "%u", i);
if (read <= 0)
{
/* Assert on the error path to avoid spamming logs with
* mostly success messages.
*/
err = read;
user_ring_buffer__discard(ringbuf, entry);
goto done;
}
user_ring_buffer__submit(ringbuf, entry);
done:
drain_current_samples();
return err;
}
```
### Initialization of the Ring Buffer and Poll
Finally, initialize the ring buffer and periodically poll, so we can know in real-time the consumption of data in kernel mode. We can also write to the `user_ringbuf` in user mode, then read and process it in kernel mode.
```c
write_samples(user_ringbuf);
/* Process events */
printf("%-8s %-5s %-16s %-7s %-7s %s\n",
"TIME", "EVENT", "COMM", "PID", "PPID", "FILENAME/EXIT CODE");
while (!exiting)
{
err = ring_buffer__poll(rb, 100 /* timeout, ms */);
/* Ctrl-C will cause -EINTR */
if (err == -EINTR)
{
err = 0;
break;
}
if (err < 0)
{
printf("Error polling perf buffer: %d\n", err);
break;
}
}
```
Through the above steps, we have implemented two-way data transmission between user mode and kernel mode.
## II. Compile and Run the Code
To compile and run the above code, we can run the following command:
```sh
make
```
For information on how to install dependencies, refer to: <https://eunomia.dev/tutorials/11-bootstrap/>
The execution result displays how to use the user ring buffer and kernel ringbuffer for efficient data transmission between user mode and kernel mode:
```console
$ sudo ./user_ringbuf
Draining current samples...
TIME EVENT COMM PID
16:31:37 SIGN node 1707
Draining current samples...
16:31:38 SIGN node 1981
Draining current samples...
16:31:38 SIGN node 1707
Draining current samples...
16:31:38 SIGN node 1707
Draining current samples...
```
## Conclusion
In this article, we discussed how to use eBPF's user ring buffer and kernel ring buffer for data transmission between user mode and kernel mode. Through this method, we can effectively deliver user data to the kernel or feed back kernel-generated data to the user, thus implementing two-way communication between the kernel and user modes.
If you want to learn more about eBPF knowledge and practices, you can visit our tutorial code repository at <https://github.com/eunomia-bpf/bpf-developer-tutorial> or our website at <https://eunomia.dev/zh/tutorials/> for more examples and complete tutorials.
References:
1. [https://lwn.net/Articles/907056/](https://lwn.net/Articles/907056/)
> Original URL: <https://eunomia.dev/zh/tutorials/35-user-ringbuf/> Please indicate the source when reprinting.

View File

@@ -12,7 +12,7 @@ uprobe is file-based. When a function in a binary file is traced, all processes
uprobe is suitable for parsing some traffic in user mode that cannot be resolved by kernel mode probes, such as HTTP/2 traffic (where the header is encoded and cannot be decoded by the kernel) and HTTPS traffic (which is encrypted and cannot be decrypted by the kernel). For more information, see the example in [eBPF Tutorial by Example: Capturing SSL/TLS Plaintext Data from Multiple Libraries with Uprobe](../30-sslsniff).
Uprobe in kernel mode eBPF runtime may also cause relatively large performance overhead. In this case, you can also consider using user mode eBPF runtime, such as [bpftime](https://github.com/eunomia-bpf/bpftime). bpftime is a user mode eBPF runtime based on LLVM JIT/AOT. It can run eBPF programs in user mode and is compatible with kernel mode eBPF, avoiding context switching between kernel mode and user mode, thereby improving the execution efficiency of eBPF programs.
Uprobe in kernel mode eBPF runtime may also cause relatively large performance overhead. In this case, you can also consider using user mode eBPF runtime, such as [bpftime](https://github.com/eunomia-bpf/bpftime). bpftime is a user mode eBPF runtime based on LLVM JIT/AOT. It can run eBPF programs in user mode and is compatible with kernel mode eBPF, avoiding context switching between kernel mode and user mode, thereby improving the execution efficiency of eBPF programs by 10 times.
## Capturing readline Function Calls in bash using uprobe

View File

@@ -53,8 +53,10 @@
- [BPF 的生命周期:使用 Detached 模式在用户态应用退出后持续运行 eBPF 程序](28-detach/README.md)
- [eBPF 运行时的安全性与面临的挑战](18-further-reading/ebpf-security.zh.md)
- [使用 eBPF 修改系统调用参数](34-syscall/README.md)
- [eBPF开发实践使用 user ring buffer 向内核异步发送信息](35-user-ringbuf/README.md)
- [用户空间 eBPF 运行时:深度解析与应用实践](36-userspace-ebpf/README.md)
# bcc 和 bpftrace 教程与文档
- [BPF Features by Linux Kernel Version](bcc-documents/kernel-versions.md)

View File

@@ -63,6 +63,10 @@ Security:
- [Replacing text read or written by any program using eBPF](27-replace/README.md)
- [BPF lifecycle: Running eBPF programs continuously in Detached mode after user-mode applications exit](28-detach/README.md)
- [Modifying System Call Parameters with eBPF](34-syscall/README.md)
Other:
- [Using user ring buffer to send information to the kernel](35-user-ringbuf/README.md)
- [Userspace eBPF Runtimes: Overview and Applications](36-userspace-ebpf/README.md)
# bcc and bpftrace tutorial