mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-04-03 10:38:59 +08:00
add config for generate TOC
This commit is contained in:
95
README.md
95
README.md
@@ -21,75 +21,72 @@ The tutorial focuses on eBPF examples in observability, networking, security, an
|
|||||||
|
|
||||||
This section contains simple eBPF program examples and introductions. It primarily utilizes the `eunomia-bpf` framework to simplify development and introduces the basic usage and development process of eBPF.
|
This section contains simple eBPF program examples and introductions. It primarily utilizes the `eunomia-bpf` framework to simplify development and introduces the basic usage and development process of eBPF.
|
||||||
|
|
||||||
- [lesson 0-introduce](src/0-introduce/README_en.md) Introduces basic concepts of eBPF and common development tools
|
- [lesson 0-introduce](src/0-introduce/README_en.md) Introduction to Core Concepts and Tools
|
||||||
- [lesson 1-helloworld](src/1-helloworld/README_en.md) Develops the simplest "Hello World" program using eBPF and introduces the basic framework and development process of eBPF
|
- [lesson 1-helloworld](src/1-helloworld/README_en.md) Hello World, Framework and Development
|
||||||
- [lesson 2-kprobe-unlink](src/2-kprobe-unlink/README_en.md) Uses kprobe in eBPF to capture the unlink system call
|
- [lesson 2-kprobe-unlink](src/2-kprobe-unlink/README_en.md) Monitoring unlink System Calls with kprobe
|
||||||
- [lesson 3-fentry-unlink](src/3-fentry-unlink/README_en.md) Uses fentry in eBPF to capture the unlink system call
|
- [lesson 3-fentry-unlink](src/3-fentry-unlink/README_en.md) Monitoring unlink System Calls with fentry
|
||||||
- [lesson 4-opensnoop](src/4-opensnoop/README_en.md) Uses eBPF to capture the system call collection of processes opening files, and filters process PIDs in eBPF using global variables
|
- [lesson 4-opensnoop](src/4-opensnoop/README_en.md) Capturing Opening Files and Filter with Global Variables
|
||||||
- [lesson 5-uprobe-bashreadline](src/5-uprobe-bashreadline/README_en.md) Uses uprobe in eBPF to capture the readline function calls in bash
|
- [lesson 5-uprobe-bashreadline](src/5-uprobe-bashreadline/README_en.md) Capturing readline Function Calls with Uprobe
|
||||||
- [lesson 6-sigsnoop](src/6-sigsnoop/README_en.md) Captures the system call collection of processes sending signals and uses a hash map to store states
|
- [lesson 6-sigsnoop](src/6-sigsnoop/README_en.md) Capturing Signal Sending and Store State with Hash Maps
|
||||||
- [lesson 7-execsnoop](src/7-execsnoop/README_en.md) Captures process execution times and prints output to user space through perf event array
|
- [lesson 7-execsnoop](src/7-execsnoop/README_en.md) Capturing Process Execution, Output with perf event array
|
||||||
- [lesson 8-exitsnoop](src/8-exitsnoop/README_en.md) Captures process exit events and prints output to user space using a ring buffer
|
- [lesson 8-exitsnoop](src/8-exitsnoop/README_en.md) Monitoring Process Exit Events, Output with Ring Buffer
|
||||||
- [lesson 9-runqlat](src/9-runqlat/README_en.md) Captures process scheduling delays and records them in histogram format
|
- [lesson 9-runqlat](src/9-runqlat/README_en.md) Capturing Scheduling Latency and Recording as Histogram
|
||||||
- [lesson 10-hardirqs](src/10-hardirqs/README_en.md) Captures interrupt events using hardirqs or softirqs
|
- [lesson 10-hardirqs](src/10-hardirqs/README_en.md) Capturing Interrupts with hardirqs or softirqs
|
||||||
|
|
||||||
### Advanced Documents and Examples
|
### Advanced Documents and Examples
|
||||||
|
|
||||||
We start to build complete eBPF projects mainly based on `libbpf` and combine them with various application scenarios for practical use.
|
We start to build complete eBPF projects mainly based on `libbpf` and combine them with various application scenarios for practical use.
|
||||||
|
|
||||||
- [lesson 11-bootstrap](src/11-bootstrap/README_en.md) Writes native libbpf user space code for eBPF using libbpf-bootstrap and establishes a complete libbpf project.
|
- [lesson 11-bootstrap](src/11-bootstrap/README_en.md) Develop User-Space Programs with libbpf and Trace exec() and exit()
|
||||||
- [lesson 12-profile](src/12-profile/README_en.md) Performs performance analysis using eBPF
|
- [lesson 12-profile](src/12-profile/README_en.md) Using eBPF Program Profile for Performance Analysis
|
||||||
- [lesson 13-tcpconnlat](src/13-tcpconnlat/README_en.md) Records TCP connection latency and processes data in user space using libbpf
|
- [lesson 13-tcpconnlat](src/13-tcpconnlat/README_en.md) Statistics of TCP Connection Delay with libbpf
|
||||||
- [lesson 14-tcpstates](src/14-tcpstates/README_en.md) Records TCP connection state and TCP RTT.- [lesson 15-javagc](src/15-javagc/README_en.md) Capture user-level Java GC event duration using usdt
|
- [lesson 14-tcpstates](src/14-tcpstates/README_en.md) Recording TCP Connection Status and TCP RTT
|
||||||
- [lesson 16-memleak](src/16-memleak/README_en.md) Detect memory leaks
|
- [lesson 15-javagc](src/15-javagc/README_en.md) Capturing User-Space Java GC Duration Using USDT
|
||||||
- [lesson 17-biopattern](src/17-biopattern/README_en.md) Capture disk IO patterns
|
- [lesson 16-memleak](src/16-memleak/README_en.md) Monitoring Memory Leaks
|
||||||
- [lesson 18-further-reading](src/18-further-reading/README_en.md) Further reading: papers list, projects, blogs, etc.
|
- [lesson 17-biopattern](src/17-biopattern/README_en.md) Count Random/Sequential Disk I/O
|
||||||
- [lesson 19-lsm-connect](src/19-lsm-connect/README_en.md) Use LSM for security detection and defense
|
- [lesson 18-further-reading](src/18-further-reading/README_en.md) More Reference Materials: papers, projects
|
||||||
- [lesson 20-tc](src/20-tc/README_en.md) Use eBPF for tc traffic control
|
- [lesson 19-lsm-connect](src/19-lsm-connect/README_en.md) Security Detection and Defense using LSM
|
||||||
- [lesson 21-xdp](src/21-xdp/README_en.md) Use eBPF for XDP packet processing
|
- [lesson 20-tc](src/20-tc/README_en.md) tc Traffic Control
|
||||||
|
- [lesson 21-xdp](src/21-xdp/README_en.md) Programmable Packet Processing with XDP
|
||||||
### In-Depth Topics
|
### In-Depth Topics
|
||||||
|
|
||||||
This section covers advanced topics related to eBPF, including using eBPF programs on Android, possible attacks and defenses using eBPF programs, and complex tracing. Combining the user-mode and kernel-mode aspects of eBPF can bring great power (as well as security risks).
|
This section covers advanced topics related to eBPF, including using eBPF programs on Android, possible attacks and defenses using eBPF programs, and complex tracing. Combining the user-mode and kernel-mode aspects of eBPF can bring great power (as well as security risks).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Android:
|
Android:
|
||||||
|
|
||||||
- [Using eBPF programs on Android](src/22-android/README_en.md)
|
- [lesson 22-android](src/22-android/README_en.md) Using eBPF Programs on Android
|
||||||
|
|
||||||
|
|
||||||
Networking:
|
Networking:
|
||||||
|
|
||||||
- [Accelerating network request forwarding using sockops](src/29-sockops/README.md)
|
- [lesson 23-http](src/23-http/README_en.md) L7 Tracing with eBPF: HTTP and Beyond via Socket Filters and Syscall Tracepoints
|
||||||
- [Capturing TCP Information with XDP](src/41-xdp-tcpdump/README.md)
|
- [lesson 29-sockops](src/29-sockops/README_en.md) Accelerating Network Request Forwarding with Sockops
|
||||||
- [XDP Load Balancer](src/42-xdp-loadbalancer/README.md)
|
- [lesson 41-xdp-tcpdump](src/41-xdp-tcpdump/README_en.md) Capturing TCP Information with XDP
|
||||||
|
- [lesson 42-xdp-loadbalancer](src/42-xdp-loadbalancer/README_en.md) XDP Load Balancer
|
||||||
|
|
||||||
tracing:
|
|
||||||
|
|
||||||
- [Tracing HTTP requests or other layer-7 protocols using eBPF socket filter or syscall trace](src/23-http/README.md)
|
|
||||||
- [Capturing Plain Text Data of Various Libraries' SSL/TLS Using uprobe](src/30-sslsniff/README.md)
|
|
||||||
- [Using eBPF to Trace Go Routine States](src/31-goroutine/README.md)
|
|
||||||
- [Measuring Function Latency with eBPF](src/33-funclatency/README.md)
|
|
||||||
- [Use Uprobe to trace Rust programs](src/37-uprobe-rust/README.md)
|
|
||||||
- [Using eBPF to Trace Nginx Requests](src/39-nginx/README.md)
|
|
||||||
- [Using eBPF to Trace MySQL Queries](src/40-mysql)
|
|
||||||
|
|
||||||
Security:
|
Security:
|
||||||
|
|
||||||
- [Use eBPF to modify syscall parameters](src/34-syscall/README.md)
|
- [lesson 24-hide](src/24-hide/README_en.md) Hiding Process or File Information
|
||||||
- [The Secure Path Forward for eBPF: Challenges and Innovations](src/18-further-reading/ebpf-security.md)
|
- [lesson 25-signal](src/25-signal/README_en.md) Using bpf_send_signal to Terminate Malicious Processes in eBPF
|
||||||
- [Hiding process or file information using eBPF](src/24-hide/README_en.md)
|
- [lesson 26-sudo](src/26-sudo/README_en.md) Using eBPF to add sudo user
|
||||||
- [Terminating processes by sending signals using bpf_send_signal](src/25-signal/README_en.md)
|
- [lesson 27-replace](src/27-replace/README_en.md) Replace Text Read or Written by Any Program with eBPF
|
||||||
- [Adding sudo users using eBPF](src/26-sudo/README_en.md)
|
- [lesson 28-detach](src/28-detach/README_en.md) Running eBPF After Application Exits: The Lifecycle of eBPF Programs
|
||||||
- [Replacing text read or written by any program using eBPF](src/27-replace/README_en.md)
|
- [lesson 34-syscall](src/34-syscall/README_en.md) Modifying System Call Arguments with eBPF
|
||||||
- [BPF lifecycle: Running eBPF programs continuously in Detached mode after user-mode applications exit](src/28-detach/README_en.md)
|
|
||||||
|
|
||||||
|
Scheduler:
|
||||||
|
|
||||||
|
- [lesson 44-scx-simple](src/44-scx-simple/README_en.md) Introduction to the BPF Scheduler
|
||||||
|
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
|
|
||||||
- [Using user ring buffer to send information to the kernel](src/35-user-ringbuf/README.md)
|
- [lesson 35-user-ringbuf](src/35-user-ringbuf/README_en.md) Asynchronously Send to Kernel with User Ring Buffer
|
||||||
- [Userspace eBPF Runtimes: Overview and Applications](src/36-userspace-ebpf/README.md)
|
- [lesson 36-userspace-ebpf](src/36-userspace-ebpf/README_en.md) Userspace eBPF Runtimes: Overview and Applications
|
||||||
- [Compile Once, Run Everywhere for userspace trace with eBPF and BTF](src/38-btf-uprobe/README.md)
|
- [lesson 38-btf-uprobe](src/38-btf-uprobe/README_en.md) Expanding eBPF Compile Once, Run Everywhere(CO-RE) to Userspace Compatibility
|
||||||
- [Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules](src/43-kfuncs/README.md)
|
- [lesson 43-kfuncs](src/43-kfuncs/README_en.md) Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Continuously updating...
|
Continuously updating...
|
||||||
|
|
||||||
|
|||||||
1
src/0-introduce/.config
Normal file
1
src/0-introduce/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/1-helloworld/.config
Normal file
1
src/1-helloworld/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/10-hardirqs/.config
Normal file
1
src/10-hardirqs/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/11-bootstrap/.config
Normal file
1
src/11-bootstrap/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/12-profile/.config
Normal file
1
src/12-profile/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/13-tcpconnlat/.config
Normal file
1
src/13-tcpconnlat/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/14-tcpstates/.config
Normal file
1
src/14-tcpstates/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/15-javagc/.config
Normal file
1
src/15-javagc/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/16-memleak/.config
Normal file
1
src/16-memleak/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/17-biopattern/.config
Normal file
1
src/17-biopattern/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/18-further-reading/.config
Normal file
1
src/18-further-reading/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/19-lsm-connect/.config
Normal file
1
src/19-lsm-connect/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/2-kprobe-unlink/.config
Normal file
1
src/2-kprobe-unlink/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/20-tc/.config
Normal file
1
src/20-tc/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
1
src/21-xdp/.config
Normal file
1
src/21-xdp/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Advance
|
||||||
2
src/22-android/.config
Normal file
2
src/22-android/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Android
|
||||||
2
src/23-http/.config
Normal file
2
src/23-http/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Networking
|
||||||
2
src/24-hide/.config
Normal file
2
src/24-hide/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Security
|
||||||
2
src/25-signal/.config
Normal file
2
src/25-signal/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Security
|
||||||
2
src/26-sudo/.config
Normal file
2
src/26-sudo/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Security
|
||||||
2
src/27-replace/.config
Normal file
2
src/27-replace/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Security
|
||||||
2
src/28-detach/.config
Normal file
2
src/28-detach/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Security
|
||||||
2
src/29-sockops/.config
Normal file
2
src/29-sockops/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Networking
|
||||||
1
src/3-fentry-unlink/.config
Normal file
1
src/3-fentry-unlink/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
2
src/30-sslsniff/.config
Normal file
2
src/30-sslsniff/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
2
src/31-goroutine/.config
Normal file
2
src/31-goroutine/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
2
src/32-http2/.config
Normal file
2
src/32-http2/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# func latency
|
# trace http2 request in go
|
||||||
|
|
||||||
TODO: make it work
|
TODO: make it work
|
||||||
|
|
||||||
|
|||||||
2
src/33-funclatency/.config
Normal file
2
src/33-funclatency/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
2
src/34-syscall/.config
Normal file
2
src/34-syscall/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Security
|
||||||
2
src/35-user-ringbuf/.config
Normal file
2
src/35-user-ringbuf/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Other
|
||||||
2
src/36-userspace-ebpf/.config
Normal file
2
src/36-userspace-ebpf/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Other
|
||||||
2
src/37-uprobe-rust/.config
Normal file
2
src/37-uprobe-rust/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
2
src/38-btf-uprobe/.config
Normal file
2
src/38-btf-uprobe/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Other
|
||||||
2
src/39-nginx/.config
Normal file
2
src/39-nginx/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
1
src/4-opensnoop/.config
Normal file
1
src/4-opensnoop/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
2
src/40-mysql/.config
Normal file
2
src/40-mysql/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Tracing
|
||||||
2
src/41-xdp-tcpdump/.config
Normal file
2
src/41-xdp-tcpdump/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Networking
|
||||||
2
src/42-xdp-loadbalancer/.config
Normal file
2
src/42-xdp-loadbalancer/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Networking
|
||||||
2
src/43-kfuncs/.config
Normal file
2
src/43-kfuncs/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Other
|
||||||
2
src/44-scx-simple/.config
Normal file
2
src/44-scx-simple/.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
level=Depth
|
||||||
|
type=Scheduler
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# eBPF Tutorial by Example: Introduction to the BPF Scheduler
|
# eBPF Tutorial: Introduction to the BPF Scheduler
|
||||||
|
|
||||||
Welcome to our deep dive into the world of eBPF with a focus on the BPF scheduler! If you're looking to extend your eBPF knowledge beyond the basics, you're in the right place. In this tutorial, we'll explore the **scx_simple scheduler**, a minimal example of the sched_ext scheduler class introduced in Linux kernel version 6.12. We'll walk you through its architecture, how it leverages BPF programs to define scheduling behavior, and guide you through compiling and running the example. By the end, you'll have a solid understanding of how to create and manage advanced scheduling policies using eBPF.
|
Welcome to our deep dive into the world of eBPF with a focus on the BPF scheduler! If you're looking to extend your eBPF knowledge beyond the basics, you're in the right place. In this tutorial, we'll explore the **scx_simple scheduler**, a minimal example of the sched_ext scheduler class introduced in Linux kernel version `6.12`. We'll walk you through its architecture, how it leverages BPF programs to define scheduling behavior, and guide you through compiling and running the example. By the end, you'll have a solid understanding of how to create and manage advanced scheduling policies using eBPF.
|
||||||
|
|
||||||
## Understanding the Extensible BPF Scheduler
|
## Understanding the Extensible BPF Scheduler
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ With these features, sched_ext provides a robust foundation for experimenting wi
|
|||||||
|
|
||||||
## Introducing scx_simple: A Minimal sched_ext Scheduler
|
## Introducing scx_simple: A Minimal sched_ext Scheduler
|
||||||
|
|
||||||
The **scx_simple** scheduler is a straightforward example of a sched_ext scheduler. It's designed to be easy to understand and serves as a foundation for more complex scheduling policies. scx_simple can operate in two modes:
|
The **scx_simple** scheduler is a straightforward example of a sched_ext scheduler in the linux tools. It's designed to be easy to understand and serves as a foundation for more complex scheduling policies. scx_simple can operate in two modes:
|
||||||
|
|
||||||
1. **Global Weighted Virtual Time (vtime) Mode:** Prioritizes tasks based on their virtual time, allowing for fair scheduling across different workloads.
|
1. **Global Weighted Virtual Time (vtime) Mode:** Prioritizes tasks based on their virtual time, allowing for fair scheduling across different workloads.
|
||||||
2. **FIFO (First-In-First-Out) Mode:** Simple queue-based scheduling where tasks are executed in the order they arrive.
|
2. **FIFO (First-In-First-Out) Mode:** Simple queue-based scheduling where tasks are executed in the order they arrive.
|
||||||
@@ -60,121 +60,121 @@ UEI_DEFINE(uei);
|
|||||||
#define SHARED_DSQ 0
|
#define SHARED_DSQ 0
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||||
__uint(key_size, sizeof(u32));
|
__uint(key_size, sizeof(u32));
|
||||||
__uint(value_size, sizeof(u64));
|
__uint(value_size, sizeof(u64));
|
||||||
__uint(max_entries, 2); /* [local, global] */
|
__uint(max_entries, 2); /* [local, global] */
|
||||||
} stats SEC(".maps");
|
} stats SEC(".maps");
|
||||||
|
|
||||||
static void stat_inc(u32 idx)
|
static void stat_inc(u32 idx)
|
||||||
{
|
{
|
||||||
u64 *cnt_p = bpf_map_lookup_elem(&stats, &idx);
|
u64 *cnt_p = bpf_map_lookup_elem(&stats, &idx);
|
||||||
if (cnt_p)
|
if (cnt_p)
|
||||||
(*cnt_p)++;
|
(*cnt_p)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool vtime_before(u64 a, u64 b)
|
static inline bool vtime_before(u64 a, u64 b)
|
||||||
{
|
{
|
||||||
return (s64)(a - b) < 0;
|
return (s64)(a - b) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 BPF_STRUCT_OPS(simple_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags)
|
s32 BPF_STRUCT_OPS(simple_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags)
|
||||||
{
|
{
|
||||||
bool is_idle = false;
|
bool is_idle = false;
|
||||||
s32 cpu;
|
s32 cpu;
|
||||||
|
|
||||||
cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &is_idle);
|
cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &is_idle);
|
||||||
if (is_idle) {
|
if (is_idle) {
|
||||||
stat_inc(0); /* count local queueing */
|
stat_inc(0); /* count local queueing */
|
||||||
scx_bpf_dispatch(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0);
|
scx_bpf_dispatch(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu;
|
return cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPF_STRUCT_OPS(simple_enqueue, struct task_struct *p, u64 enq_flags)
|
void BPF_STRUCT_OPS(simple_enqueue, struct task_struct *p, u64 enq_flags)
|
||||||
{
|
{
|
||||||
stat_inc(1); /* count global queueing */
|
stat_inc(1); /* count global queueing */
|
||||||
|
|
||||||
if (fifo_sched) {
|
if (fifo_sched) {
|
||||||
scx_bpf_dispatch(p, SHARED_DSQ, SCX_SLICE_DFL, enq_flags);
|
scx_bpf_dispatch(p, SHARED_DSQ, SCX_SLICE_DFL, enq_flags);
|
||||||
} else {
|
} else {
|
||||||
u64 vtime = p->scx.dsq_vtime;
|
u64 vtime = p->scx.dsq_vtime;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Limit the amount of budget that an idling task can accumulate
|
* Limit the amount of budget that an idling task can accumulate
|
||||||
* to one slice.
|
* to one slice.
|
||||||
*/
|
*/
|
||||||
if (vtime_before(vtime, vtime_now - SCX_SLICE_DFL))
|
if (vtime_before(vtime, vtime_now - SCX_SLICE_DFL))
|
||||||
vtime = vtime_now - SCX_SLICE_DFL;
|
vtime = vtime_now - SCX_SLICE_DFL;
|
||||||
|
|
||||||
scx_bpf_dispatch_vtime(p, SHARED_DSQ, SCX_SLICE_DFL, vtime,
|
scx_bpf_dispatch_vtime(p, SHARED_DSQ, SCX_SLICE_DFL, vtime,
|
||||||
enq_flags);
|
enq_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPF_STRUCT_OPS(simple_dispatch, s32 cpu, struct task_struct *prev)
|
void BPF_STRUCT_OPS(simple_dispatch, s32 cpu, struct task_struct *prev)
|
||||||
{
|
{
|
||||||
scx_bpf_consume(SHARED_DSQ);
|
scx_bpf_consume(SHARED_DSQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPF_STRUCT_OPS(simple_running, struct task_struct *p)
|
void BPF_STRUCT_OPS(simple_running, struct task_struct *p)
|
||||||
{
|
{
|
||||||
if (fifo_sched)
|
if (fifo_sched)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global vtime always progresses forward as tasks start executing. The
|
* Global vtime always progresses forward as tasks start executing. The
|
||||||
* test and update can be performed concurrently from multiple CPUs and
|
* test and update can be performed concurrently from multiple CPUs and
|
||||||
* thus racy. Any error should be contained and temporary. Let's just
|
* thus racy. Any error should be contained and temporary. Let's just
|
||||||
* live with it.
|
* live with it.
|
||||||
*/
|
*/
|
||||||
if (vtime_before(vtime_now, p->scx.dsq_vtime))
|
if (vtime_before(vtime_now, p->scx.dsq_vtime))
|
||||||
vtime_now = p->scx.dsq_vtime;
|
vtime_now = p->scx.dsq_vtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPF_STRUCT_OPS(simple_stopping, struct task_struct *p, bool runnable)
|
void BPF_STRUCT_OPS(simple_stopping, struct task_struct *p, bool runnable)
|
||||||
{
|
{
|
||||||
if (fifo_sched)
|
if (fifo_sched)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scale the execution time by the inverse of the weight and charge.
|
* Scale the execution time by the inverse of the weight and charge.
|
||||||
*
|
*
|
||||||
* Note that the default yield implementation yields by setting
|
* Note that the default yield implementation yields by setting
|
||||||
* @p->scx.slice to zero and the following would treat the yielding task
|
* @p->scx.slice to zero and the following would treat the yielding task
|
||||||
* as if it has consumed all its slice. If this penalizes yielding tasks
|
* as if it has consumed all its slice. If this penalizes yielding tasks
|
||||||
* too much, determine the execution time by taking explicit timestamps
|
* too much, determine the execution time by taking explicit timestamps
|
||||||
* instead of depending on @p->scx.slice.
|
* instead of depending on @p->scx.slice.
|
||||||
*/
|
*/
|
||||||
p->scx.dsq_vtime += (SCX_SLICE_DFL - p->scx.slice) * 100 / p->scx.weight;
|
p->scx.dsq_vtime += (SCX_SLICE_DFL - p->scx.slice) * 100 / p->scx.weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPF_STRUCT_OPS(simple_enable, struct task_struct *p)
|
void BPF_STRUCT_OPS(simple_enable, struct task_struct *p)
|
||||||
{
|
{
|
||||||
p->scx.dsq_vtime = vtime_now;
|
p->scx.dsq_vtime = vtime_now;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 BPF_STRUCT_OPS_SLEEPABLE(simple_init)
|
s32 BPF_STRUCT_OPS_SLEEPABLE(simple_init)
|
||||||
{
|
{
|
||||||
return scx_bpf_create_dsq(SHARED_DSQ, -1);
|
return scx_bpf_create_dsq(SHARED_DSQ, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPF_STRUCT_OPS(simple_exit, struct scx_exit_info *ei)
|
void BPF_STRUCT_OPS(simple_exit, struct scx_exit_info *ei)
|
||||||
{
|
{
|
||||||
UEI_RECORD(uei, ei);
|
UEI_RECORD(uei, ei);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCX_OPS_DEFINE(simple_ops,
|
SCX_OPS_DEFINE(simple_ops,
|
||||||
.select_cpu = (void *)simple_select_cpu,
|
.select_cpu = (void *)simple_select_cpu,
|
||||||
.enqueue = (void *)simple_enqueue,
|
.enqueue = (void *)simple_enqueue,
|
||||||
.dispatch = (void *)simple_dispatch,
|
.dispatch = (void *)simple_dispatch,
|
||||||
.running = (void *)simple_running,
|
.running = (void *)simple_running,
|
||||||
.stopping = (void *)simple_stopping,
|
.stopping = (void *)simple_stopping,
|
||||||
.enable = (void *)simple_enable,
|
.enable = (void *)simple_enable,
|
||||||
.init = (void *)simple_init,
|
.init = (void *)simple_init,
|
||||||
.exit = (void *)simple_exit,
|
.exit = (void *)simple_exit,
|
||||||
.name = "simple");
|
.name = "simple");
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Kernel-Side Breakdown
|
#### Kernel-Side Breakdown
|
||||||
@@ -213,70 +213,70 @@ This modular structure allows scx_simple to be both simple and effective, provid
|
|||||||
```c
|
```c
|
||||||
static void read_stats(struct scx_simple *skel, __u64 *stats)
|
static void read_stats(struct scx_simple *skel, __u64 *stats)
|
||||||
{
|
{
|
||||||
int nr_cpus = libbpf_num_possible_cpus();
|
int nr_cpus = libbpf_num_possible_cpus();
|
||||||
__u64 cnts[2][nr_cpus];
|
__u64 cnts[2][nr_cpus];
|
||||||
__u32 idx;
|
__u32 idx;
|
||||||
|
|
||||||
memset(stats, 0, sizeof(stats[0]) * 2);
|
memset(stats, 0, sizeof(stats[0]) * 2);
|
||||||
|
|
||||||
for (idx = 0; idx < 2; idx++) {
|
for (idx = 0; idx < 2; idx++) {
|
||||||
int ret, cpu;
|
int ret, cpu;
|
||||||
|
|
||||||
ret = bpf_map_lookup_elem(bpf_map__fd(skel->maps.stats),
|
ret = bpf_map_lookup_elem(bpf_map__fd(skel->maps.stats),
|
||||||
&idx, cnts[idx]);
|
&idx, cnts[idx]);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
continue;
|
continue;
|
||||||
for (cpu = 0; cpu < nr_cpus; cpu++)
|
for (cpu = 0; cpu < nr_cpus; cpu++)
|
||||||
stats[idx] += cnts[idx][cpu];
|
stats[idx] += cnts[idx][cpu];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct scx_simple *skel;
|
struct scx_simple *skel;
|
||||||
struct bpf_link *link;
|
struct bpf_link *link;
|
||||||
__u32 opt;
|
__u32 opt;
|
||||||
__u64 ecode;
|
__u64 ecode;
|
||||||
|
|
||||||
libbpf_set_print(libbpf_print_fn);
|
libbpf_set_print(libbpf_print_fn);
|
||||||
signal(SIGINT, sigint_handler);
|
signal(SIGINT, sigint_handler);
|
||||||
signal(SIGTERM, sigint_handler);
|
signal(SIGTERM, sigint_handler);
|
||||||
restart:
|
restart:
|
||||||
skel = SCX_OPS_OPEN(simple_ops, scx_simple);
|
skel = SCX_OPS_OPEN(simple_ops, scx_simple);
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "fvh")) != -1) {
|
while ((opt = getopt(argc, argv, "fvh")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'f':
|
case 'f':
|
||||||
skel->rodata->fifo_sched = true;
|
skel->rodata->fifo_sched = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, help_fmt, basename(argv[0]));
|
fprintf(stderr, help_fmt, basename(argv[0]));
|
||||||
return opt != 'h';
|
return opt != 'h';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SCX_OPS_LOAD(skel, simple_ops, scx_simple, uei);
|
SCX_OPS_LOAD(skel, simple_ops, scx_simple, uei);
|
||||||
link = SCX_OPS_ATTACH(skel, simple_ops, scx_simple);
|
link = SCX_OPS_ATTACH(skel, simple_ops, scx_simple);
|
||||||
|
|
||||||
while (!exit_req && !UEI_EXITED(skel, uei)) {
|
while (!exit_req && !UEI_EXITED(skel, uei)) {
|
||||||
__u64 stats[2];
|
__u64 stats[2];
|
||||||
|
|
||||||
read_stats(skel, stats);
|
read_stats(skel, stats);
|
||||||
printf("local=%llu global=%llu\n", stats[0], stats[1]);
|
printf("local=%llu global=%llu\n", stats[0], stats[1]);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bpf_link__destroy(link);
|
bpf_link__destroy(link);
|
||||||
ecode = UEI_REPORT(skel, uei);
|
ecode = UEI_REPORT(skel, uei);
|
||||||
scx_simple__destroy(skel);
|
scx_simple__destroy(skel);
|
||||||
|
|
||||||
if (UEI_ECODE_RESTART(ecode))
|
if (UEI_ECODE_RESTART(ecode))
|
||||||
goto restart;
|
goto restart;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
1
src/5-uprobe-bashreadline/.config
Normal file
1
src/5-uprobe-bashreadline/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/6-sigsnoop/.config
Normal file
1
src/6-sigsnoop/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/7-execsnoop/.config
Normal file
1
src/7-execsnoop/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/8-exitsnoop/.config
Normal file
1
src/8-exitsnoop/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
1
src/9-runqlat/.config
Normal file
1
src/9-runqlat/.config
Normal file
@@ -0,0 +1 @@
|
|||||||
|
level=Basic
|
||||||
@@ -12,32 +12,33 @@ For the complete source code of the tutorial, please refer to the repo [https://
|
|||||||
|
|
||||||
This section contains simple eBPF program examples and introductions. It primarily utilizes the `eunomia-bpf` framework to simplify development and introduces the basic usage and development process of eBPF.
|
This section contains simple eBPF program examples and introductions. It primarily utilizes the `eunomia-bpf` framework to simplify development and introduces the basic usage and development process of eBPF.
|
||||||
|
|
||||||
- [lesson 0-introduce](0-introduce/README.md) Introduces basic concepts of eBPF and common development tools
|
- [lesson 0-introduce](0-introduce/README_en.md) Introduction to Core Concepts and Tools
|
||||||
- [lesson 1-helloworld](1-helloworld/README.md) Develops the simplest "Hello World" program using eBPF and introduces the basic framework and development process of eBPF
|
- [lesson 1-helloworld](1-helloworld/README_en.md) Hello World, Framework and Development
|
||||||
- [lesson 2-kprobe-unlink](2-kprobe-unlink/README.md) Uses kprobe in eBPF to capture the unlink system call
|
- [lesson 2-kprobe-unlink](2-kprobe-unlink/README_en.md) Monitoring unlink System Calls with kprobe
|
||||||
- [lesson 3-fentry-unlink](3-fentry-unlink/README.md) Uses fentry in eBPF to capture the unlink system call
|
- [lesson 3-fentry-unlink](3-fentry-unlink/README_en.md) Monitoring unlink System Calls with fentry
|
||||||
- [lesson 4-opensnoop](4-opensnoop/README.md) Uses eBPF to capture the system call collection of processes opening files, and filters process PIDs in eBPF using global variables
|
- [lesson 4-opensnoop](4-opensnoop/README_en.md) Capturing Opening Files and Filter with Global Variables
|
||||||
- [lesson 5-uprobe-bashreadline](5-uprobe-bashreadline/README.md) Uses uprobe in eBPF to capture the readline function calls in bash
|
- [lesson 5-uprobe-bashreadline](5-uprobe-bashreadline/README_en.md) Capturing readline Function Calls with Uprobe
|
||||||
- [lesson 6-sigsnoop](6-sigsnoop/README.md) Captures the system call collection of processes sending signals and uses a hash map to store states
|
- [lesson 6-sigsnoop](6-sigsnoop/README_en.md) Capturing Signal Sending and Store State with Hash Maps
|
||||||
- [lesson 7-execsnoop](7-execsnoop/README.md) Captures process execution times and prints output to user space through perf event array
|
- [lesson 7-execsnoop](7-execsnoop/README_en.md) Capturing Process Execution, Output with perf event array
|
||||||
- [lesson 8-exitsnoop](8-exitsnoop/README.md) Captures process exit events and prints output to user space using a ring buffer
|
- [lesson 8-exitsnoop](8-exitsnoop/README_en.md) Monitoring Process Exit Events, Output with Ring Buffer
|
||||||
- [lesson 9-runqlat](9-runqlat/README.md) Captures process scheduling delays and records them in histogram format
|
- [lesson 9-runqlat](9-runqlat/README_en.md) Capturing Scheduling Latency and Recording as Histogram
|
||||||
- [lesson 10-hardirqs](10-hardirqs/README.md) Captures interrupt events using hardirqs or softirqs
|
- [lesson 10-hardirqs](10-hardirqs/README_en.md) Capturing Interrupts with hardirqs or softirqs
|
||||||
|
|
||||||
# Advanced Documents and Examples
|
# Advanced Documents and Examples
|
||||||
|
|
||||||
We start to build complete eBPF projects mainly based on `libbpf` and combine them with various application scenarios for practical use.
|
We start to build complete eBPF projects mainly based on `libbpf` and combine them with various application scenarios for practical use.
|
||||||
|
|
||||||
- [lesson 11-bootstrap](11-bootstrap/README.md) Writes native libbpf user space code for eBPF using libbpf-bootstrap and establishes a complete libbpf project.
|
- [lesson 11-bootstrap](11-bootstrap/README_en.md) Develop User-Space Programs with libbpf and Trace exec() and exit()
|
||||||
- [lesson 12-profile](12-profile/README.md) Performs performance analysis using eBPF
|
- [lesson 12-profile](12-profile/README_en.md) Using eBPF Program Profile for Performance Analysis
|
||||||
- [lesson 13-tcpconnlat](13-tcpconnlat/README.md) Records TCP connection latency and processes data in user space using libbpf
|
- [lesson 13-tcpconnlat](13-tcpconnlat/README_en.md) Statistics of TCP Connection Delay with libbpf
|
||||||
- [lesson 14-tcpstates](14-tcpstates/README.md) Records TCP connection state and TCP RTT.- [lesson 15-javagc](15-javagc/README.md) Capture user-level Java GC event duration using usdt
|
- [lesson 14-tcpstates](14-tcpstates/README_en.md) Recording TCP Connection Status and TCP RTT
|
||||||
- [lesson 16-memleak](16-memleak/README.md) Detect memory leaks
|
- [lesson 15-javagc](15-javagc/README_en.md) Capturing User-Space Java GC Duration Using USDT
|
||||||
- [lesson 17-biopattern](17-biopattern/README.md) Capture disk IO patterns
|
- [lesson 16-memleak](16-memleak/README_en.md) Monitoring Memory Leaks
|
||||||
- [lesson 18-further-reading](18-further-reading/README.md) Further reading: papers list, projects, blogs, etc.
|
- [lesson 17-biopattern](17-biopattern/README_en.md) Count Random/Sequential Disk I/O
|
||||||
- [lesson 19-lsm-connect](19-lsm-connect/README.md) Use LSM for security detection and defense
|
- [lesson 18-further-reading](18-further-reading/README_en.md) More Reference Materials: papers, projects
|
||||||
- [lesson 20-tc](20-tc/README.md) Use eBPF for tc traffic control
|
- [lesson 19-lsm-connect](19-lsm-connect/README_en.md) Security Detection and Defense using LSM
|
||||||
- [lesson 21-xdp](21-xdp/README.md) Use eBPF for XDP packet processing
|
- [lesson 20-tc](20-tc/README_en.md) tc Traffic Control
|
||||||
|
- [lesson 21-xdp](21-xdp/README_en.md) Programmable Packet Processing with XDP
|
||||||
|
|
||||||
# In-Depth Topics
|
# In-Depth Topics
|
||||||
|
|
||||||
@@ -45,41 +46,36 @@ This section covers advanced topics related to eBPF, including using eBPF progra
|
|||||||
|
|
||||||
Android:
|
Android:
|
||||||
|
|
||||||
- [Using eBPF programs on Android](22-android/README.md)
|
- [lesson 22-android](22-android/README_en.md) Using eBPF Programs on Android
|
||||||
|
|
||||||
Networking:
|
Networking:
|
||||||
|
|
||||||
- [Accelerating network request forwarding using sockops](29-sockops/README.md)
|
- [lesson 23-http](23-http/README_en.md) L7 Tracing with eBPF: HTTP and Beyond via Socket Filters and Syscall Tracepoints
|
||||||
- [Capturing TCP Information with XDP](41-xdp-tcpdump/README.md)
|
- [lesson 29-sockops](29-sockops/README_en.md) Accelerating Network Request Forwarding with Sockops
|
||||||
- [XDP Load Balancer](42-xdp-loadbalancer/README.md)
|
- [lesson 41-xdp-tcpdump](41-xdp-tcpdump/README_en.md) Capturing TCP Information with XDP
|
||||||
|
- [lesson 42-xdp-loadbalancer](42-xdp-loadbalancer/README_en.md) XDP Load Balancer
|
||||||
tracing:
|
|
||||||
|
|
||||||
- [Tracing HTTP requests or other layer-7 protocols using eBPF socket filter or syscall trace](23-http/README.md)
|
|
||||||
- [Capturing Plain Text Data of Various Libraries' SSL/TLS Using uprobe](30-sslsniff/README.md)
|
|
||||||
- [Using eBPF to Trace Go Routine States](31-goroutine/README.md)
|
|
||||||
- [Measuring Function Latency with eBPF](33-funclatency/README.md)
|
|
||||||
- [Use uprobe to trace Rust programs](37-uprobe-rust/README.md)
|
|
||||||
- [Using eBPF to Trace Nginx Requests](39-nginx/README.md)
|
|
||||||
- [Using eBPF to Trace MySQL Queries](src/40-mysql)
|
|
||||||
|
|
||||||
Security:
|
Security:
|
||||||
|
|
||||||
- [Use eBPF to modify syscall parameters](34-syscall/README.md)
|
- [lesson 24-hide](24-hide/README_en.md) Hiding Process or File Information
|
||||||
- [The Secure Path Forward for eBPF: Challenges and Innovations](18-further-reading/ebpf-security.md)
|
- [lesson 25-signal](25-signal/README_en.md) Using bpf_send_signal to Terminate Malicious Processes in eBPF
|
||||||
- [Hiding process or file information using eBPF](24-hide/README.md)
|
- [lesson 26-sudo](26-sudo/README_en.md) Using eBPF to add sudo user
|
||||||
- [Terminating processes by sending signals using bpf_send_signal](25-signal/README.md)
|
- [lesson 27-replace](27-replace/README_en.md) Replace Text Read or Written by Any Program with eBPF
|
||||||
- [Adding sudo users using eBPF](26-sudo/README.md)
|
- [lesson 28-detach](28-detach/README_en.md) Running eBPF After Application Exits: The Lifecycle of eBPF Programs
|
||||||
- [Replacing text read or written by any program using eBPF](27-replace/README.md)
|
- [lesson 34-syscall](34-syscall/README_en.md) Modifying System Call Arguments with eBPF
|
||||||
- [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)
|
Scheduler:
|
||||||
|
|
||||||
|
- [lesson 44-scx-simple](44-scx-simple/README_en.md) Introduction to the BPF Scheduler
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
|
|
||||||
- [Using user ring buffer to send information to the kernel](35-user-ringbuf/README.md)
|
- [lesson 35-user-ringbuf](35-user-ringbuf/README_en.md) Asynchronously Send to Kernel with User Ring Buffer
|
||||||
- [Userspace eBPF Runtimes: Overview and Applications](36-userspace-ebpf/README.md)
|
- [lesson 36-userspace-ebpf](36-userspace-ebpf/README_en.md) Userspace eBPF Runtimes: Overview and Applications
|
||||||
- [Compile Once, Run Everywhere for userspace with eBPF and BTF](38-btf-uprobe/README.md)
|
- [lesson 38-btf-uprobe](38-btf-uprobe/README_en.md) Expanding eBPF Compile Once, Run Everywhere(CO-RE) to Userspace Compatibility
|
||||||
- [Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules](43-kfuncs/README.md)
|
- [lesson 43-kfuncs](43-kfuncs/README_en.md) Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules
|
||||||
|
|
||||||
|
Continuously updating...
|
||||||
|
|
||||||
# bcc and bpftrace tutorial
|
# bcc and bpftrace tutorial
|
||||||
|
|
||||||
|
|||||||
219
src/scripts/generate_toc.py
Normal file
219
src/scripts/generate_toc.py
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Define a function to walk through the directory and generate the TOC structure
|
||||||
|
def generate_toc(base_dir, project_root):
|
||||||
|
toc = "## Table of Contents\n\n"
|
||||||
|
section_headers = {
|
||||||
|
"Basic": "### Getting Started Examples\n\nThis section contains simple eBPF program examples and introductions. It primarily utilizes the `eunomia-bpf` framework to simplify development and introduces the basic usage and development process of eBPF.\n\n",
|
||||||
|
"Advance": "### Advanced Documents and Examples\n\nWe start to build complete eBPF projects mainly based on `libbpf` and combine them with various application scenarios for practical use.\n\n",
|
||||||
|
"Depth": "### In-Depth Topics\n\nThis section covers advanced topics related to eBPF, including using eBPF programs on Android, possible attacks and defenses using eBPF programs, and complex tracing. Combining the user-mode and kernel-mode aspects of eBPF can bring great power (as well as security risks).\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
subsection_titles = {
|
||||||
|
"Android": "\n\nAndroid:\n\n",
|
||||||
|
"Networking": "\n\nNetworking:\n\n",
|
||||||
|
"tracing": "\n\ntracing:\n\n",
|
||||||
|
"Security": "\n\nSecurity:\n\n",
|
||||||
|
"Scheduler": "\n\nScheduler:\n\n",
|
||||||
|
"Other": "\n\nOther:\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
subsection_order = ['Android', 'Networking', 'tracing', 'Security', 'Scheduler', 'Other']
|
||||||
|
|
||||||
|
# To ensure numeric sorting of directories
|
||||||
|
def sort_key(directory_name):
|
||||||
|
return list(map(int, re.findall(r'\d+', directory_name)))
|
||||||
|
|
||||||
|
sections = {} # {section_level: {subsection_type: [lessons]}}
|
||||||
|
|
||||||
|
# Sort directories properly by numeric order
|
||||||
|
all_dirs = sorted([d for d in os.listdir(base_dir) if os.path.isdir(os.path.join(base_dir, d))], key=sort_key)
|
||||||
|
|
||||||
|
# Loop over the sorted directories
|
||||||
|
for directory in all_dirs:
|
||||||
|
lesson_path = os.path.join(base_dir, directory)
|
||||||
|
config_path = os.path.join(lesson_path, ".config")
|
||||||
|
readme_path = os.path.join(lesson_path, "README_en.md")
|
||||||
|
|
||||||
|
if os.path.exists(config_path) and os.path.exists(readme_path):
|
||||||
|
# Read the .config file for 'level', 'type', and 'desc'
|
||||||
|
with open(config_path, 'r') as config_file:
|
||||||
|
config_lines = config_file.readlines()
|
||||||
|
level = None
|
||||||
|
lesson_type = None
|
||||||
|
desc = None
|
||||||
|
for line in config_lines:
|
||||||
|
if line.startswith("level="):
|
||||||
|
level = line.split("=",1)[1].strip()
|
||||||
|
elif line.startswith("type="):
|
||||||
|
lesson_type = line.split("=",1)[1].strip()
|
||||||
|
elif line.startswith("desc="):
|
||||||
|
desc = line.split("=",1)[1].strip()
|
||||||
|
|
||||||
|
# Extract the first markdown title in README_en.md
|
||||||
|
with open(readme_path, 'r') as readme_file:
|
||||||
|
first_title = None
|
||||||
|
for line in readme_file:
|
||||||
|
if line.startswith("#"):
|
||||||
|
first_title = line.strip().lstrip("#").strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
# If title starts with "eBPF", remove the part before the colon
|
||||||
|
if first_title and first_title.startswith("eBPF"):
|
||||||
|
if ":" in first_title:
|
||||||
|
first_title = first_title.split(":", 1)[1].strip()
|
||||||
|
|
||||||
|
# Get the relative path for the lesson
|
||||||
|
lesson_rel_path = os.path.relpath(readme_path, project_root)
|
||||||
|
|
||||||
|
# Prepare lesson data
|
||||||
|
lesson_number = directory.split('-')[0]
|
||||||
|
lesson_name = directory.split('-', 1)[1]
|
||||||
|
link_text = f"lesson {lesson_number}-{lesson_name}"
|
||||||
|
link = f"{lesson_rel_path}"
|
||||||
|
# Use description if available, else use first title
|
||||||
|
lesson_desc = desc if desc else first_title
|
||||||
|
|
||||||
|
lesson_entry = {
|
||||||
|
'link_text': link_text,
|
||||||
|
'link': link,
|
||||||
|
'desc': lesson_desc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Organize lessons into sections and subsections
|
||||||
|
sections.setdefault(level, {}).setdefault(lesson_type, []).append(lesson_entry)
|
||||||
|
|
||||||
|
# Now, output the TOC in the desired order
|
||||||
|
section_order = ['Basic', 'Advance', 'Depth']
|
||||||
|
|
||||||
|
for level in section_order:
|
||||||
|
if level in sections:
|
||||||
|
toc += section_headers.get(level, "")
|
||||||
|
# For Basic and Advance sections, no subsections
|
||||||
|
if level != 'Depth':
|
||||||
|
for lesson in sum(sections[level].values(), []): # Flatten the list
|
||||||
|
toc += f"- [{lesson['link_text']}]({lesson['link']}) {lesson['desc']}\n"
|
||||||
|
else:
|
||||||
|
# For Depth section, output subsections in the desired order
|
||||||
|
for subsection in subsection_order:
|
||||||
|
if subsection in sections[level]:
|
||||||
|
toc += subsection_titles.get(subsection, "")
|
||||||
|
for lesson in sections[level][subsection]:
|
||||||
|
toc += f"- [{lesson['link_text']}]({lesson['link']}) {lesson['desc']}\n"
|
||||||
|
|
||||||
|
toc += "\nContinuously updating..."
|
||||||
|
return toc
|
||||||
|
|
||||||
|
|
||||||
|
# Define a function to walk through the directory and generate the TOC structure in Chinese
|
||||||
|
def generate_toc_cn(base_dir, project_root):
|
||||||
|
toc = "## 目录\n\n"
|
||||||
|
section_headers = {
|
||||||
|
"Basic": "### 入门示例\n\n这一部分包含简单的 eBPF 程序示例和介绍。主要利用 `eunomia-bpf` 框架简化开发,介绍 eBPF 的基本用法和开发流程。\n\n",
|
||||||
|
"Advance": "### 高级文档和示例\n\n我们开始构建完整的 eBPF 项目,主要基于 `libbpf`,并将其与各种应用场景结合起来,以便实际使用。\n\n",
|
||||||
|
"Depth": "### 深入主题\n\n这一部分涵盖了与 eBPF 相关的高级主题,包括在 Android 上使用 eBPF 程序、利用 eBPF 程序进行的潜在攻击和防御以及复杂的追踪。结合用户模式和内核模式的 eBPF 可以带来强大的能力(也可能带来安全风险)。\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
subsection_titles = {
|
||||||
|
"Android": "Android:\n\n",
|
||||||
|
"Networking": "网络:\n\n",
|
||||||
|
"tracing": "追踪:\n\n",
|
||||||
|
"Security": "安全:\n\n",
|
||||||
|
"Scheduler": "调度器:\n\n",
|
||||||
|
"Other": "其他:\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
subsection_order = ['Android', 'Networking', 'tracing', 'Security', 'Scheduler', 'Other']
|
||||||
|
|
||||||
|
# To ensure numeric sorting of directories
|
||||||
|
def sort_key(directory_name):
|
||||||
|
return list(map(int, re.findall(r'\d+', directory_name)))
|
||||||
|
|
||||||
|
sections = {} # {section_level: {subsection_type: [lessons]}}
|
||||||
|
|
||||||
|
# Sort directories properly by numeric order
|
||||||
|
all_dirs = sorted([d for d in os.listdir(base_dir) if os.path.isdir(os.path.join(base_dir, d))], key=sort_key)
|
||||||
|
|
||||||
|
# Loop over the sorted directories
|
||||||
|
for directory in all_dirs:
|
||||||
|
lesson_path = os.path.join(base_dir, directory)
|
||||||
|
config_path = os.path.join(lesson_path, ".config")
|
||||||
|
readme_path = os.path.join(lesson_path, "README.md")
|
||||||
|
|
||||||
|
if os.path.exists(config_path) and os.path.exists(readme_path):
|
||||||
|
# Read the .config file for 'level', 'type', and 'desc'
|
||||||
|
with open(config_path, 'r') as config_file:
|
||||||
|
config_lines = config_file.readlines()
|
||||||
|
level = None
|
||||||
|
lesson_type = None
|
||||||
|
desc = None
|
||||||
|
for line in config_lines:
|
||||||
|
if line.startswith("level="):
|
||||||
|
level = line.split("=",1)[1].strip()
|
||||||
|
elif line.startswith("type="):
|
||||||
|
lesson_type = line.split("=",1)[1].strip()
|
||||||
|
elif line.startswith("desc="):
|
||||||
|
desc = line.split("=",1)[1].strip()
|
||||||
|
|
||||||
|
# Extract the first markdown title in README.md
|
||||||
|
with open(readme_path, 'r') as readme_file:
|
||||||
|
first_title = None
|
||||||
|
for line in readme_file:
|
||||||
|
if line.startswith("#"):
|
||||||
|
first_title = line.strip().lstrip("#").strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
# If title starts with "eBPF", remove the part before the colon
|
||||||
|
if first_title and first_title.startswith("eBPF"):
|
||||||
|
if ":" in first_title:
|
||||||
|
first_title = first_title.split(":", 1)[1].strip()
|
||||||
|
|
||||||
|
# Get the relative path for the lesson
|
||||||
|
lesson_rel_path = os.path.relpath(readme_path, project_root)
|
||||||
|
|
||||||
|
# Prepare lesson data
|
||||||
|
lesson_number = directory.split('-')[0]
|
||||||
|
lesson_name = directory.split('-', 1)[1]
|
||||||
|
link_text = f"lesson {lesson_number}-{lesson_name}"
|
||||||
|
link = f"{lesson_rel_path}"
|
||||||
|
# Use description if available, else use first title
|
||||||
|
lesson_desc = desc if desc else first_title
|
||||||
|
|
||||||
|
lesson_entry = {
|
||||||
|
'link_text': link_text,
|
||||||
|
'link': link,
|
||||||
|
'desc': lesson_desc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Organize lessons into sections and subsections
|
||||||
|
sections.setdefault(level, {}).setdefault(lesson_type, []).append(lesson_entry)
|
||||||
|
|
||||||
|
# Now, output the TOC in the desired order
|
||||||
|
section_order = ['Basic', 'Advance', 'Depth']
|
||||||
|
|
||||||
|
for level in section_order:
|
||||||
|
if level in sections:
|
||||||
|
toc += section_headers.get(level, "")
|
||||||
|
# For Basic and Advance sections, no subsections
|
||||||
|
if level != 'Depth':
|
||||||
|
for lesson in sum(sections[level].values(), []): # Flatten the list
|
||||||
|
toc += f"- [{lesson['link_text']}]({lesson['link']}) {lesson['desc']}\n"
|
||||||
|
else:
|
||||||
|
# For Depth section, output subsections in the desired order
|
||||||
|
for subsection in subsection_order:
|
||||||
|
if subsection in sections[level]:
|
||||||
|
toc += subsection_titles.get(subsection, "")
|
||||||
|
for lesson in sections[level][subsection]:
|
||||||
|
toc += f"- [{lesson['link_text']}]({lesson['link']}) {lesson['desc']}\n"
|
||||||
|
|
||||||
|
toc += "\n持续更新中..."
|
||||||
|
return toc
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
base_directory = "/root/bpf-developer-tutorial/src/" # Replace with the actual base directory
|
||||||
|
project_root = "/root/bpf-developer-tutorial/src/" # The root of the project
|
||||||
|
toc_output = generate_toc(base_directory, project_root)
|
||||||
|
|
||||||
|
# Output the TOC
|
||||||
|
print(toc_output)
|
||||||
23
src/scripts/rename.py
Normal file
23
src/scripts/rename.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
def rename_readme_files(base_dir):
|
||||||
|
# Walk through all directories and files starting from base_dir
|
||||||
|
for root, dirs, files in os.walk(base_dir):
|
||||||
|
for file in files:
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
|
||||||
|
# Rename README.md to README.zh.md if README.md exists after the previous rename
|
||||||
|
if file == "README.md":
|
||||||
|
zh_file_path = os.path.join(root, "README.zh.md")
|
||||||
|
os.rename(file_path, zh_file_path)
|
||||||
|
print(f"Renamed {file_path} to {zh_file_path}")
|
||||||
|
|
||||||
|
# Rename README_en.md to README.md
|
||||||
|
elif file == "README_en.md":
|
||||||
|
new_file_path = os.path.join(root, "README.md")
|
||||||
|
os.rename(file_path, new_file_path)
|
||||||
|
print(f"Renamed {file_path} to {new_file_path}")
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
base_directory = "/root/bpf-developer-tutorial/src" # Replace with the actual base directory
|
||||||
|
rename_readme_files(base_directory)
|
||||||
Reference in New Issue
Block a user