mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-03 02:04:30 +08:00
fix linter issues for 0-3
This commit is contained in:
@@ -32,7 +32,7 @@ Linux内核一直是实现监控/可观测性、网络和安全功能的理想
|
||||
eBPF的雏形是BPF(Berkeley Packet Filter, 伯克利包过滤器)。BPF于
|
||||
1992年被Steven McCanne和Van Jacobson在其[论文](https://www.tcpdump.org/papers/bpf-usenix93.pdf)
|
||||
提出。二人提出BPF的初衷是是提供一种新的数据包过滤方法,该方法的模型如下图所示。
|
||||

|
||||

|
||||
|
||||
相较于其他过滤方法,BPF有两大创新点,首先是它使用了一个新的虚拟机,可以有效地工作在基于寄存器结构的CPU之上。其次是其不会全盘复制数据包的所有信息,只会复制相关数据,可以有效地提高效率。这两大创新使得BPF在实际应用中得到了巨大的成功,在被移植到Linux系统后,其被上层的`libcap`
|
||||
和`tcpdump`等应用使用,是一个性能卓越的工具。
|
||||
@@ -154,7 +154,7 @@ eBPF程序每次执行时候都需要进行编译,编译则需要用户配置
|
||||
|
||||
### 2.3 eunomia-bpf
|
||||
|
||||
开发、构建和分发 eBPF 一直以来都是一个高门槛的工作,使用 BCC、bpftrace 等工具开发效率高、可移植性好,但是分发部署时需要安装 LLVM、Clang等编译环境,每次运行的时候执行本地或远程编译过程,资源消耗较大;使用原生的 CO-RE libbpf时又需要编写不少用户态加载代码来帮助 eBPF 程序正确加载和从内核中获取上报的信息,同时对于 eBPF 程序的分发、管理也没有很好地解决方案.
|
||||
开发、构建和分发 eBPF 一直以来都是一个高门槛的工作,使用 BCC、bpftrace 等工具开发效率高、可移植性好,但是分发部署时需要安装 LLVM、Clang等编译环境,每次运行的时候执行本地或远程编译过程,资源消耗较大;使用原生的 CO-RE libbpf时又需要编写不少用户态加载代码来帮助 eBPF 程序正确加载和从内核中获取上报的信息,同时对于 eBPF 程序的分发、管理也没有很好地解决方案。
|
||||
|
||||
[eunomia-bpf](https://github.com/eunomia-bpf/eunomia-bpf) 是一个开源的 eBPF 动态加载运行时和开发工具链,是为了简化 eBPF 程序的开发、构建、分发、运行而设计的,基于 libbpf 的 CO-RE 轻量级开发框架。
|
||||
|
||||
@@ -171,6 +171,6 @@ eunomia-bpf 由一个编译工具链和一个运行时库组成, 对比传统的
|
||||
|
||||
## 参考资料
|
||||
|
||||
- eBPF 介绍:https://ebpf.io/
|
||||
- BPF Compiler Collection (BCC):https://github.com/iovisor/bcc
|
||||
- eunomia-bpf:https://github.com/eunomia-bpf/eunomia-bpf
|
||||
- eBPF 介绍:<https://ebpf.io/>
|
||||
- BPF Compiler Collection (BCC):<https://github.com/iovisor/bcc>
|
||||
- eunomia-bpf:<https://github.com/eunomia-bpf/eunomia-bpf>
|
||||
|
||||
@@ -45,18 +45,20 @@ Usage: ecli [--help] [--version] [--json] [--no-cache] url-and-args
|
||||
下载编译器工具链,用于将 eBPF 内核代码编译为 config 文件或 WASM 模块:
|
||||
|
||||
```console
|
||||
$ wget https://github.com/eunomia-bpf/eunomia-bpf/releases/latest/download/eunomia.tar.gz
|
||||
$ tar -xvf eunomia.tar.gz -C ~
|
||||
$ export PATH=$PATH:~/.eunomia/bin
|
||||
$ ecc -h
|
||||
$ wget https://github.com/eunomia-bpf/eunomia-bpf/releases/latest/download/ecc && chmod +x ./ecc
|
||||
$ ./ecc -h
|
||||
eunomia-bpf compiler
|
||||
Usage: ecc [OPTIONS] <SOURCE_PATH> [EXPORT_EVENT_HEADER]
|
||||
....
|
||||
```
|
||||
|
||||
也可以使用 docker 镜像进行编译:
|
||||
|
||||
```console
|
||||
$ docker run -it -v `pwd`/:/src/ yunwei37/ebpm:latest # 使用 docker 进行编译。`pwd` 应该包含 *.bpf.c 文件和 *.h 文件。
|
||||
export PATH=PATH:~/.eunomia/bin
|
||||
Compiling bpf object...
|
||||
Packing ebpf object and config into /src/package.json...
|
||||
```
|
||||
|
||||
## Hello World - minimal eBPF program
|
||||
@@ -77,11 +79,11 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||
SEC("tp/syscalls/sys_enter_write")
|
||||
int handle_tp(void *ctx)
|
||||
{
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
if (pid_filter && pid != pid_filter)
|
||||
return 0;
|
||||
bpf_printk("BPF triggered from PID %d.\n", pid);
|
||||
return 0;
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
if (pid_filter && pid != pid_filter)
|
||||
return 0;
|
||||
bpf_printk("BPF triggered from PID %d.\n", pid);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -89,7 +91,7 @@ int handle_tp(void *ctx)
|
||||
|
||||
- `bpf_trace_printk()`: 一种将信息输出到trace_pipe(/sys/kernel/debug/tracing/trace_pipe)简单机制。 在一些简单用例中这样使用没有问题, but它也有一些限制:最多3 参数; 第一个参数必须是%s(即字符串);同时trace_pipe在内核中全局共享,其他并行使用trace_pipe的程序有可能会将 trace_pipe 的输出扰乱。 一个更好的方式是通过 BPF_PERF_OUTPUT(), 稍后将会讲到。
|
||||
- `void *ctx`:ctx本来是具体类型的参数, 但是由于我们这里没有使用这个参数,因此就将其写成void *类型。
|
||||
- `return 0`;:必须这样,返回0 (如果要知道why, 参考 #139 https://github.com/iovisor/bcc/issues/139)。
|
||||
- `return 0`;:必须这样,返回0 (如果要知道why, 参考 #139 <https://github.com/iovisor/bcc/issues/139>)。
|
||||
|
||||
要编译和运行这段程序,可以使用 ecc 工具和 ecli 命令。首先使用 ecc 编译程序:
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ kprobes技术包括的3种探测手段分别时kprobe、jprobe和kretprobe。首
|
||||
|
||||
kprobes的技术原理并不仅仅包含存软件的实现方案,它也需要硬件架构提供支持。其中涉及硬件架构相关的是CPU的异常处理和单步调试技术,前者用于让程序的执行流程陷入到用户注册的回调函数中去,而后者则用于单步执行被探测点指令,因此并不是所有的架构均支持,目前kprobes技术已经支持多种架构,包括i386、x86_64、ppc64、ia64、sparc64、arm、ppc和mips(有些架构实现可能并不完全,具体可参考内核的Documentation/kprobes.txt)。
|
||||
|
||||
kprobes的特点与使用限制:
|
||||
kprobes的特点与使用限制:
|
||||
|
||||
1. kprobes允许在同一个被被探测位置注册多个kprobe,但是目前jprobe却不可以;同时也不允许以其他的jprobe回调函数和kprobe的post_handler回调函数作为被探测点。
|
||||
2. 一般情况下,可以探测内核中的任何函数,包括中断处理函数。不过在kernel/kprobes.c和arch/*/kernel/kprobes.c程序中用于实现kprobes自身的函数是不允许被探测的,另外还有do_page_fault和notifier_call_chain;
|
||||
@@ -40,23 +40,23 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||
SEC("kprobe/do_unlinkat")
|
||||
int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name)
|
||||
{
|
||||
pid_t pid;
|
||||
const char *filename;
|
||||
pid_t pid;
|
||||
const char *filename;
|
||||
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
filename = BPF_CORE_READ(name, name);
|
||||
bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename);
|
||||
return 0;
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
filename = BPF_CORE_READ(name, name);
|
||||
bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("kretprobe/do_unlinkat")
|
||||
int BPF_KRETPROBE(do_unlinkat_exit, long ret)
|
||||
{
|
||||
pid_t pid;
|
||||
pid_t pid;
|
||||
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret);
|
||||
return 0;
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -97,6 +97,6 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe
|
||||
|
||||
## 总结
|
||||
|
||||
通过本文的示例,我们学习了如何使用 eBPF 的 kprobe 和 kretprobe 捕获 unlink 系统调用。更多的例子和详细的开发指南,请参考 eunomia-bpf 的官方文档:https://github.com/eunomia-bpf/eunomia-bpf
|
||||
通过本文的示例,我们学习了如何使用 eBPF 的 kprobe 和 kretprobe 捕获 unlink 系统调用。更多的例子和详细的开发指南,请参考 eunomia-bpf 的官方文档:<https://github.com/eunomia-bpf/eunomia-bpf>
|
||||
|
||||
本文是 eBPF 入门开发实践指南的第二篇。下一篇文章将介绍如何在 eBPF 中使用 fentry 监测捕获 unlink 系统调用
|
||||
|
||||
@@ -16,21 +16,21 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||
SEC("fentry/do_unlinkat")
|
||||
int BPF_PROG(do_unlinkat, int dfd, struct filename *name)
|
||||
{
|
||||
pid_t pid;
|
||||
pid_t pid;
|
||||
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
bpf_printk("fentry: pid = %d, filename = %s\n", pid, name->name);
|
||||
return 0;
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
bpf_printk("fentry: pid = %d, filename = %s\n", pid, name->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("fexit/do_unlinkat")
|
||||
int BPF_PROG(do_unlinkat_exit, int dfd, struct filename *name, long ret)
|
||||
{
|
||||
pid_t pid;
|
||||
pid_t pid;
|
||||
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
bpf_printk("fexit: pid = %d, filename = %s, ret = %ld\n", pid, name->name, ret);
|
||||
return 0;
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
bpf_printk("fexit: pid = %d, filename = %s, ret = %ld\n", pid, name->name, ret);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -73,4 +73,4 @@ $ sudo cat /sys/kernel/debug/tracing/trace_pipe
|
||||
|
||||
这段程序是一个 eBPF 程序,通过使用 fentry 和 fexit 捕获 do_unlinkat 和 do_unlinkat_exit 函数,并通过使用 bpf_get_current_pid_tgid 和 bpf_printk 函数获取调用 do_unlinkat 的进程 ID、文件名和返回值,并在内核日志中打印出来。
|
||||
|
||||
编译这个程序可以使用 ecc 工具,运行时可以使用 ecli 命令,并通过查看 /sys/kernel/debug/tracing/trace_pipe 文件查看 eBPF 程序的输出。更多的例子和详细的开发指南,请参考 eunomia-bpf 的官方文档:https://github.com/eunomia-bpf/eunomia-bpf
|
||||
编译这个程序可以使用 ecc 工具,运行时可以使用 ecli 命令,并通过查看 /sys/kernel/debug/tracing/trace_pipe 文件查看 eBPF 程序的输出。更多的例子和详细的开发指南,请参考 eunomia-bpf 的官方文档:<https://github.com/eunomia-bpf/eunomia-bpf>
|
||||
|
||||
Reference in New Issue
Block a user