You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This tutorial is designed for developers who want to build custom kernel solutions, system administrators looking to enhance performance and security, and tech enthusiasts exploring cutting-edge kernel technologies. Whether you're debugging production issues or building the next generation of observability tools, this guide will help you get started with eBPF.
68
66
69
67
### What Will You Learn?
70
68
71
-
-**Core Concepts:** eBPF fundamentals and integration with the Linux kernel.
72
-
-**Practical Skills:** Writing and deploying eBPF programs.
73
-
-**Advanced Topics:** Exploring security, tracing, and future innovations in eBPF.
69
+
You'll learn eBPF fundamentals and how they integrate with the Linux kernel. We'll cover practical skills for writing and deploying eBPF programs, from simple "Hello World" examples to advanced topics like security monitoring, tracing, and performance profiling. By the end, you'll be able to write your own eBPF tools and understand how to apply them to real-world problems.
70
+
71
+
### Prerequisites
72
+
73
+
Before starting, make sure you have a Linux system with kernel version 4.8 or higher (we recommend 5.15+ or 6.2+ for full feature support). You'll need basic C programming knowledge and familiarity with system concepts like processes and system calls. Most examples require root or sudo privileges to run. You should also install development tools like clang, llvm, and libelf-dev on your system.
Copy file name to clipboardExpand all lines: src/1-helloworld/README.md
+14-9Lines changed: 14 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,7 @@ Once you have chosen a suitable development framework, such as BCC (BPF Compiler
35
35
36
36
Through the above process, you can develop, compile, run, and debug eBPF programs using the BCC tool. Note that the development process of other frameworks, such as libbpf, cilium/ebpf, and eunomia-bpf, is similar but slightly different. Therefore, when choosing a framework, please refer to the respective official documentation and examples.
37
37
38
-
By following this process, you can develop an eBPF program that runs in the kernel. eunomia-bpf is an open-source eBPF dynamic loading runtime and development toolchain. It aims to simplify the development, building, distribution, and running of eBPF programs. It is based on the libbpf CO-RE lightweight development framework, supports loading and executing eBPF programs through a user space WebAssembly (WASM) virtual machine, and packages precompiled eBPF programs into universal JSON or WASM modules for distribution. We will use eunomia-bpf for demonstration purposes.
38
+
We use eunomia-bpf to compile and run this example. You can install it from <https://github.com/eunomia-bpf/eunomia-bpf>.
39
39
40
40
## Download and Install eunomia-bpf Development Tools
41
41
@@ -98,11 +98,15 @@ int handle_tp(void *ctx)
98
98
}
99
99
```
100
100
101
-
This program defines a handle_tp function and attaches it to the sys_enter_write tracepoint using the SEC macro (i.e., it is executed when the write system call is entered). The function retrieves the process ID of the write system call invocation using the bpf_get_current_pid_tgid and bpf_printk functions, and prints it in the kernel log.
101
+
This program defines a handle_tp function and attaches it to the sys_enter_write tracepoint using the SEC macro. This means it gets executed every time the write system call is entered. The function retrieves the process ID of the current process and prints it to the kernel log using `bpf_printk`.
102
102
103
-
- `bpf_printk()`: A simple mechanism to output information to the trace_pipe (/sys/kernel/debug/tracing/trace_pipe). This is fine for simple use cases, but it has limitations: a maximum of 3 parameters; the first parameter must be %s (i.e., a string); and the trace_pipe is globally shared in the kernel, so other programs using the trace_pipe concurrently might disrupt its output. A better approach is to use BPF_PERF_OUTPUT(), which will be discussed later.
104
-
- `void *ctx`: ctx is originally a parameter of a specific type, but since it is not used here, it is written as void *.
105
-
- `return 0;`: This is necessary, returning 0 (to know why, refer to #139 <https://github.com/iovisor/bcc/issues/139>).
103
+
The `SEC("tp/syscalls/sys_enter_write")` macro tells the eBPF loader where to attach this function. The format is `tp` for tracepoint, followed by the subsystem (`syscalls`), and the specific event name (`sys_enter_write`). You can find available tracepoints by running `sudo ls /sys/kernel/debug/tracing/events/syscalls/` on your system.
104
+
105
+
The `BPF_NO_GLOBAL_DATA` macro at the top is for compatibility with older kernels (before 5.2) that don't support global variables in eBPF. If you're running a modern kernel (5.15+), this isn't strictly necessary but doesn't hurt to include for portability.
106
+
107
+
The `bpf_printk()` function is your friend for debugging. It outputs to `/sys/kernel/debug/tracing/trace_pipe`, which is a simple way to see what your eBPF program is doing. However, it has some limitations you should know about. It only accepts up to 3 parameters, the trace_pipe is shared globally across all eBPF programs, and it can impact performance on high-frequency events. For production use, you'll want to use ring buffers or perf event arrays, which we'll cover in later tutorials.
108
+
109
+
The `ctx` parameter contains tracepoint-specific data, but since we don't need it for this simple example, we just declare it as `void *`. In more advanced programs, you would cast this to access the tracepoint's arguments. Finally, eBPF programs must return an integer - returning 0 is standard practice for tracepoints.
106
110
107
111
To compile and run this program, you can use the ecc tool and ecli command. First, on Ubuntu/Debian, execute the following command:
Once you stop the ecli process by pressing Ctrl+C, the corresponding output will also stop.
143
147
144
-
Note: If your Linux distribution (e.g. Ubuntu) does not have the tracing subsystem enabled by default, you may not see any output. Use the following command to enable this feature:
148
+
If you don't see any output, the tracing subsystem might not be enabled on your system. This is common on some Linux distributions. You can enable it by running:
145
149
146
150
```console
147
-
$ sudo su
148
-
# echo 1 > /sys/kernel/debug/tracing/tracing_on
151
+
$ sudo sh -c 'echo 1 > /sys/kernel/debug/tracing/tracing_on'
149
152
```
150
153
154
+
If you're still not seeing output, make sure the program is actually loaded and running (you should see "Running eBPF program..." in the ecli terminal). Try triggering some write syscalls manually by running `echo "test" > /tmp/test.txt` in another terminal. You can also check if your eBPF program is loaded by running `sudo bpftool prog list`.
155
+
151
156
## Basic Framework of eBPF Program
152
157
153
158
As mentioned above, the basic framework of an eBPF program includes:
@@ -190,6 +195,6 @@ The development and usage process of eBPF programs can be summarized in the foll
190
195
- Use the eBPF program: This includes monitoring the execution of the eBPF program and exchanging and sharing data using eBPF kernel maps and shared memory.
191
196
- In practical development, there may be additional steps such as configuring compilation and loading parameters, managing eBPF kernel modules and kernel maps, and using other advanced features.
192
197
193
-
It should be noted that the execution of BPF programs occurs in the kernel space, so special tools and techniques are needed to write, compile, and debug BPF programs. eunomia-bpf is an open-source BPF compiler and toolkit that can help developers write and run BPF programs quickly and easily.
198
+
The execution of BPF programs occurs in the kernel space, so special tools and techniques are needed to write, compile, and debug them.
194
199
195
200
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, all of which are open-source. We will continue to share more about eBPF development practices to help you better understand and master eBPF technology.
Copy file name to clipboardExpand all lines: src/10-hardirqs/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -235,7 +235,7 @@ The code for Softirq is similar, and I won't elaborate on it here.
235
235
236
236
## Run code.Translated content
237
237
238
-
eunomia-bpf is an open-source eBPF dynamic loading runtime and development toolchain that combines Wasm. Its purpose is to simplify the development, building, distribution, and execution of eBPF programs. You can refer to <https://github.com/eunomia-bpf/eunomia-bpf> to download and install the ecc compilation toolchain and ecli runtime. We use eunomia-bpf to compile and run this example.
238
+
We use eunomia-bpf to compile and run this example. You can install it from <https://github.com/eunomia-bpf/eunomia-bpf>.
Copy file name to clipboardExpand all lines: src/2-kprobe-unlink/README.md
+7-3Lines changed: 7 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -76,7 +76,7 @@ First, we import necessary header files such as vmlinux.h, bpf_helpers.h, bpf_tr
76
76
char LICENSE[] SEC("license") = "Dual BSD/GPL";
77
77
```
78
78
79
-
Next, we define a kprobe named `BPF_KPROBE(do_unlinkat)` which gets triggered when the `do_unlinkat` function is entered. It takes two parameters: `dfd` (file descriptor) and `name` (filename structure pointer). In this kprobe, we retrieve the PID (process identifier) of the current process and then read the filename. Finally, we use the `bpf_printk` function to print the PID and filename in the kernel log.
79
+
The first kprobe hooks into the entry point of `do_unlinkat`. The `BPF_KPROBE` macro makes it easy to access the function's parameters - in this case `dfd` (file descriptor) and `name` (a pointer to the filename structure). We grab the current process ID and then use `BPF_CORE_READ`to safely read the filename from kernel memory.
80
80
81
81
```c
82
82
SEC("kprobe/do_unlinkat")
@@ -92,7 +92,9 @@ int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name)
92
92
}
93
93
```
94
94
95
-
Next, we define a kretprobe named `BPF_KRETPROBE(do_unlinkat_exit)` that will be triggered when exiting the `do_unlinkat` function. The purpose of this kretprobe is to capture the return value (`ret`) of the function. We again obtain the PID of the current process and use the `bpf_printk` function to print the PID and return value in the kernel log.
95
+
You might wonder why we can't just access `name->name` directly. The answer is that eBPF programs run in a restricted environment and need special helpers to safely read kernel memory. `BPF_CORE_READ` handles this safely and also provides CO-RE (Compile Once - Run Everywhere) support, meaning your program will work across different kernel versions even if the structure layout changes.
96
+
97
+
The kretprobe is the counterpart that triggers when the function returns. Here we can capture the return value to see if the unlink operation succeeded or failed. A return value of 0 means success, while negative values indicate errors.
96
98
97
99
```c
98
100
SEC("kretprobe/do_unlinkat")
@@ -106,7 +108,9 @@ int BPF_KRETPROBE(do_unlinkat_exit, long ret)
106
108
}
107
109
```
108
110
109
-
eunomia-bpf is an open-source eBPF dynamic loading runtime and development toolchain that combines with Wasm. Its goal is to simplify the development, build, distribution, and execution of eBPF programs. You can refer to <https://github.com/eunomia-bpf/eunomia-bpf> to download and install the ecc compiler toolchain and ecli runtime.
111
+
By combining kprobe and kretprobe, you get the complete picture - you can see what file is being deleted and whether the operation succeeded. This pattern is useful for debugging, security monitoring, or building observability tools.
112
+
113
+
We use eunomia-bpf to compile and run this example. You can install it from <https://github.com/eunomia-bpf/eunomia-bpf>.
Copy file name to clipboardExpand all lines: src/3-fentry-unlink/README.md
+9-20Lines changed: 9 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,23 +4,15 @@ eBPF (Extended Berkeley Packet Filter) is a powerful network and performance ana
4
4
5
5
This article is the third part of the eBPF Tutorial by Example, focusing on capturing unlink system calls using fentry in eBPF.
6
6
7
-
## Fentry
7
+
## What is fentry and Why Use It?
8
8
9
-
fentry (function entry) and fexit (function exit) are two types of probes in eBPF (Extended Berkeley Packet Filter) used for tracing at the entry and exit points of Linux kernel functions. They allow developers to collect information, modify parameters, or observe return values at specific stages of kernel function execution. This tracing and monitoring functionality is very useful in performance analysis, troubleshooting, and security analysis scenarios.
9
+
fentry (function entry) and fexit (function exit) are the modern way to trace kernel functions in eBPF. They were introduced in kernel 5.5 for x86 processors and 6.0 for ARM processors. Think of them as the faster, more efficient successors to kprobes.
10
10
11
-
Compared to kprobes, fentry and fexit programs have higher performance and availability. In this example, we can directly access the pointers to the functions' parameters, just like in regular C code, without needing various read helpers. The main difference between fexit and kretprobe programs is that fexit programs can access both the input parameters and return values of a function, while kretprobe programs can only access the return value. Starting from the 5.5 kernel, fentry and fexit are available for eBPF programs.
11
+
The big advantage of fentry/fexit over kprobes is performance and convenience. With fentry, you can directly access function parameters just like in regular C code - no need for special helpers like `BPF_CORE_READ`. This makes your code simpler and faster. fexit gives you an extra bonus - you can access both the input parameters and the return value at the same time, while kretprobe only gives you the return value.
12
12
13
-
> arm64 kernel version requires 6.0
14
-
>
15
-
> Refer to the learning eBPF documentation:
16
-
>
17
-
> A more efficient mechanism for tracing the entry to and exit from kernel functions
18
-
> was introduced along with the idea of BPF trampoline in kernel version 5.5 (on x86
19
-
> processors; BPF trampoline support doesn’t arrive for ARM processors until Linux
20
-
> 6.0). If you’re using a recent enough kernel, fentry/fexit is now the preferred method
21
-
> for tracing the entry to or exit from a kernel function
The performance difference is real. fentry/fexit programs run about 10x faster than kprobes because they use a BPF trampoline mechanism instead of the older breakpoint-based approach. If you're building production monitoring tools that run on every function call, this matters a lot.
14
+
15
+
Note that if you're on ARM, you'll need kernel 6.0 or newer. For x86, kernel 5.5+ works fine. If you're stuck on an older kernel, you'll need to use kprobes instead.
24
16
25
17
26
18
@@ -54,14 +46,11 @@ int BPF_PROG(do_unlinkat_exit, int dfd, struct filename *name, long ret)
54
46
}
55
47
```
56
48
57
-
This program is an eBPF (Extended Berkeley Packet Filter) program written in the C language. It uses BPF fentry and fexit probes to trace the Linux kernel function `do_unlinkat`. In this tutorial, we will use this program as an example to learn how to use fentry in eBPF to detect and capture unlink system calls.
49
+
Let's break down how this program works. The fentry probe attaches to the entry of `do_unlinkat` and can access the function's parameters directly. Notice how we access `name->name` without any special helpers - this is one of the benefits of using fentry instead of kprobes.
58
50
59
-
The program consists of the following parts:
51
+
The fexit probe is even more interesting. It gets triggered when the function returns, and it can access both the original parameters (dfd and name) and the return value (ret). This gives you complete visibility into what the function did. If ret is 0, the file was successfully deleted. If it's negative, something went wrong and you can see the error code.
60
52
61
-
1. Include header files: including vmlinux.h (for accessing kernel data structures), bpf/bpf_helpers.h (which includes eBPF helper functions), bpf/bpf_tracing.h (for eBPF tracing-related functionalities).
62
-
2. Define license: Here, a character array named `LICENSE` is defined, containing the license information "Dual BSD/GPL".
63
-
3. Define fentry probe: We define an fentry probe named `BPF_PROG(do_unlinkat)` that is triggered at the entry point of the `do_unlinkat` function. This probe retrieves the PID (Process ID) of the current process and prints it along with the filename to the kernel log.
64
-
4. Define fexit probe: We also define an fexit probe named `BPF_PROG(do_unlinkat_exit)` that is triggered at the exit point of the `do_unlinkat` function. Similar to the fentry probe, this probe also retrieves the PID of the current process and prints it along with the filename and return value to the kernel log.
53
+
The `BPF_PROG` macro is similar to `BPF_KPROBE` from the previous tutorial, but it's designed for fentry/fexit. It handles the parameter unwrapping automatically so you can focus on your logic.
65
54
66
55
Through this example, you can learn how to use fentry and fexit probes in eBPF to monitor and capture kernel function calls, such as the unlink system call in this tutorial. "eunomia-bpf is an open source eBPF dynamic loading runtime and development toolchain combined with Wasm. Its goal is to simplify the development, building, distribution, and running of eBPF programs. You can refer to [here](https://github.com/eunomia-bpf/eunomia-bpf) to download and install the ecc compilation toolchain and ecli runtime. We use eunomia-bpf to compile and run this example.
0 commit comments