mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-29 03:34:44 +08:00
Fix bilingual tutorial indexes and internal links (#209)
* Fix bilingual tutorial index generation * Check relative Markdown links in CI * Harden documentation regression checks * Reduce link parser complexity * Run link checks for every repository change --------- Co-authored-by: LinuxDev9002 <i@littlefisher.me>
This commit is contained in:
23
.github/workflows/check-docs.yml
vendored
Normal file
23
.github/workflows/check-docs.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: Check documentation
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- name: Test documentation scripts
|
||||||
|
run: python3 -m unittest scripts.test_check_internal_links scripts.test_generate_toc
|
||||||
|
- name: Regenerate documentation indexes
|
||||||
|
run: python3 scripts/generate_toc.py
|
||||||
|
- name: Verify generated documentation is current
|
||||||
|
run: git diff --exit-code -- README.md README.zh.md src/SUMMARY.md src/SUMMARY.zh.md
|
||||||
|
- name: Check relative Markdown links
|
||||||
|
run: python3 scripts/check_internal_links.py
|
||||||
@@ -56,9 +56,9 @@ This section covers advanced topics related to eBPF, including using eBPF progra
|
|||||||
GPU:
|
GPU:
|
||||||
|
|
||||||
- [lesson 47-cuda-events](src/47-cuda-events/README.md) Tracing CUDA GPU Operations
|
- [lesson 47-cuda-events](src/47-cuda-events/README.md) Tracing CUDA GPU Operations
|
||||||
- [lesson xpu/npu-kernel-driver](src/xpu/npu-kernel-driver/README.md) Tracing Intel NPU Kernel Driver Operations
|
|
||||||
- [xpu flamegraph](src/xpu/flamegraph/README.md) Building a GPU Flamegraph Profiler with CUPTI
|
- [xpu flamegraph](src/xpu/flamegraph/README.md) Building a GPU Flamegraph Profiler with CUPTI
|
||||||
- [lesson xpu/gpu-kernel-driver](src/xpu/gpu-kernel-driver/README.md) Monitoring GPU Driver Activity with Kernel Tracepoints
|
- [lesson xpu/gpu-kernel-driver](src/xpu/gpu-kernel-driver/README.md) Monitoring GPU Driver Activity with Kernel Tracepoints
|
||||||
|
- [lesson xpu/npu-kernel-driver](src/xpu/npu-kernel-driver/README.md) Tracing Intel NPU Kernel Driver Operations
|
||||||
|
|
||||||
|
|
||||||
Scheduler:
|
Scheduler:
|
||||||
@@ -104,11 +104,11 @@ Features:
|
|||||||
- [lesson 36-userspace-ebpf](src/36-userspace-ebpf/README.md) Userspace eBPF Runtimes: Overview and Applications
|
- [lesson 36-userspace-ebpf](src/36-userspace-ebpf/README.md) Userspace eBPF Runtimes: Overview and Applications
|
||||||
- [lesson 38-btf-uprobe](src/38-btf-uprobe/README.md) Expanding eBPF Compile Once, Run Everywhere(CO-RE) to Userspace Compatibility
|
- [lesson 38-btf-uprobe](src/38-btf-uprobe/README.md) Expanding eBPF Compile Once, Run Everywhere(CO-RE) to Userspace Compatibility
|
||||||
- [lesson 43-kfuncs](src/43-kfuncs/README.md) Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules
|
- [lesson 43-kfuncs](src/43-kfuncs/README.md) Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules
|
||||||
|
- [features bpf_arena](src/features/bpf_arena/README.md) BPF Arena for Zero-Copy Shared Memory
|
||||||
- [features bpf_iters](src/features/bpf_iters/README.md) BPF Iterators for Kernel Data Export
|
- [features bpf_iters](src/features/bpf_iters/README.md) BPF Iterators for Kernel Data Export
|
||||||
- [features bpf_token](src/features/bpf_token/README.md) BPF Token for Delegated Privilege and Secure Program Loading
|
- [features bpf_token](src/features/bpf_token/README.md) BPF Token for Delegated Privilege and Secure Program Loading
|
||||||
- [features dynptr](src/features/dynptr/README.md) BPF Dynamic Pointers for Variable-Length Data
|
|
||||||
- [features bpf_wq](src/features/bpf_wq/README.md) BPF Workqueues for Asynchronous Sleepable Tasks
|
- [features bpf_wq](src/features/bpf_wq/README.md) BPF Workqueues for Asynchronous Sleepable Tasks
|
||||||
- [features bpf_arena](src/features/bpf_arena/README.md) BPF Arena for Zero-Copy Shared Memory
|
- [features dynptr](src/features/dynptr/README.md) BPF Dynamic Pointers for Variable-Length Data
|
||||||
- [features struct_ops](src/features/struct_ops/README.md) Extending Kernel Subsystems with BPF struct_ops
|
- [features struct_ops](src/features/struct_ops/README.md) Extending Kernel Subsystems with BPF struct_ops
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
@@ -125,7 +125,7 @@ Continuously updating...
|
|||||||
|
|
||||||
## Why write this tutorial?
|
## Why write this tutorial?
|
||||||
|
|
||||||
In the process of learning eBPF, we have been inspired and helped by the [bcc python developer tutorial](src/bcc-documents/tutorial_bcc_python_developer.md). However, from the current perspective, using `libbpf` to develop eBPF applications is a relatively better choice.
|
In the process of learning eBPF, we have been inspired and helped by the [bcc Python developer tutorial](https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md). However, from the current perspective, using `libbpf` to develop eBPF applications is a relatively better choice.
|
||||||
|
|
||||||
This project is mainly based on [libbpf](https://github.com/libbpf/libbpf) frameworks.
|
This project is mainly based on [libbpf](https://github.com/libbpf/libbpf) frameworks.
|
||||||
|
|
||||||
|
|||||||
39
README.zh.md
39
README.zh.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
[GitHub](https://github.com/eunomia-bpf/bpf-developer-tutorial)
|
[GitHub](https://github.com/eunomia-bpf/bpf-developer-tutorial)
|
||||||
[Gitee 镜像](https://gitee.com/yunwei37/bpf-developer-tutorial)
|
[Gitee 镜像](https://gitee.com/yunwei37/bpf-developer-tutorial)
|
||||||
[English Version](README_en.md)
|
[English Version](README.md)
|
||||||
|
|
||||||
#### [**Check out the English version here**](README.md)
|
#### [**Check out the English version here**](README.md)
|
||||||
|
|
||||||
@@ -50,16 +50,22 @@
|
|||||||
|
|
||||||
这一部分涵盖了与 eBPF 相关的高级主题,包括在 Android 上使用 eBPF 程序、利用 eBPF 程序进行的潜在攻击和防御以及复杂的追踪。结合用户模式和内核模式的 eBPF 可以带来强大的能力(也可能带来安全风险)。
|
这一部分涵盖了与 eBPF 相关的高级主题,包括在 Android 上使用 eBPF 程序、利用 eBPF 程序进行的潜在攻击和防御以及复杂的追踪。结合用户模式和内核模式的 eBPF 可以带来强大的能力(也可能带来安全风险)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GPU:
|
GPU:
|
||||||
|
|
||||||
- [lesson 47-cuda-events](src/47-cuda-events/README.zh.md) eBPF 教程:追踪 CUDA GPU 操作
|
- [lesson 47-cuda-events](src/47-cuda-events/README.zh.md) eBPF 教程:追踪 CUDA GPU 操作
|
||||||
- [lesson xpu/npu-kernel-driver](src/xpu/npu-kernel-driver/README.zh.md) eBPF 实例教程:跟踪 Intel NPU 内核驱动操作
|
|
||||||
- [xpu flamegraph](src/xpu/flamegraph/README.zh.md) eBPF 示例:使用 CUPTI 构建 GPU 火焰图分析器
|
- [xpu flamegraph](src/xpu/flamegraph/README.zh.md) eBPF 示例:使用 CUPTI 构建 GPU 火焰图分析器
|
||||||
- [lesson xpu/gpu-kernel-driver](src/xpu/gpu-kernel-driver/README.zh.md) eBPF 实例教程:使用内核跟踪点监控 GPU 驱动活动
|
- [lesson xpu/gpu-kernel-driver](src/xpu/gpu-kernel-driver/README.zh.md) eBPF 实例教程:使用内核跟踪点监控 GPU 驱动活动
|
||||||
|
- [lesson xpu/npu-kernel-driver](src/xpu/npu-kernel-driver/README.zh.md) eBPF 实例教程:跟踪 Intel NPU 内核驱动操作
|
||||||
|
|
||||||
|
|
||||||
调度器:
|
调度器:
|
||||||
|
|
||||||
- [lesson 44-scx-simple](src/44-scx-simple/README.zh.md) eBPF 教程:BPF 调度器入门
|
- [lesson 44-scx-simple](src/44-scx-simple/README.zh.md) eBPF 教程:BPF 调度器入门
|
||||||
- [lesson 45-scx-nest](src/45-scx-nest/README.zh.md) eBPF 示例教程:实现 `scx_nest` 调度器
|
- [lesson 45-scx-nest](src/45-scx-nest/README.zh.md) eBPF 示例教程:实现 `scx_nest` 调度器
|
||||||
|
|
||||||
|
|
||||||
网络:
|
网络:
|
||||||
|
|
||||||
- [lesson 23-http](src/23-http/README.zh.md) 通过 eBPF socket filter 或 syscall trace 追踪 HTTP 请求等七层协议 - eBPF 实践教程
|
- [lesson 23-http](src/23-http/README.zh.md) 通过 eBPF socket filter 或 syscall trace 追踪 HTTP 请求等七层协议 - eBPF 实践教程
|
||||||
@@ -68,6 +74,19 @@ GPU:
|
|||||||
- [lesson 42-xdp-loadbalancer](src/42-xdp-loadbalancer/README.zh.md) eBPF 开发者教程: 简单的 XDP 负载均衡器
|
- [lesson 42-xdp-loadbalancer](src/42-xdp-loadbalancer/README.zh.md) eBPF 开发者教程: 简单的 XDP 负载均衡器
|
||||||
- [lesson 46-xdp-test](src/46-xdp-test/README.zh.md) eBPF 实例教程:构建高性能 XDP 数据包生成器
|
- [lesson 46-xdp-test](src/46-xdp-test/README.zh.md) eBPF 实例教程:构建高性能 XDP 数据包生成器
|
||||||
- [lesson 50-tcx](src/50-tcx/README.zh.md) eBPF 入门实践教程第五十篇:使用 TCX Link 实现可组合的流量控制
|
- [lesson 50-tcx](src/50-tcx/README.zh.md) eBPF 入门实践教程第五十篇:使用 TCX Link 实现可组合的流量控制
|
||||||
|
|
||||||
|
|
||||||
|
追踪:
|
||||||
|
|
||||||
|
- [lesson 30-sslsniff](src/30-sslsniff/README.zh.md) eBPF 实践教程:使用 uprobe 捕获多种库的 SSL/TLS 明文数据
|
||||||
|
- [lesson 31-goroutine](src/31-goroutine/README.zh.md) eBPF 实践教程:使用 eBPF 跟踪 Go 协程状态
|
||||||
|
- [lesson 33-funclatency](src/33-funclatency/README.zh.md) 使用 eBPF 测量函数延迟
|
||||||
|
- [lesson 37-uprobe-rust](src/37-uprobe-rust/README.zh.md) eBPF 实践:使用 Uprobe 追踪用户态 Rust 应用
|
||||||
|
- [lesson 39-nginx](src/39-nginx/README.zh.md) 使用 eBPF 跟踪 Nginx 请求
|
||||||
|
- [lesson 40-mysql](src/40-mysql/README.zh.md) 使用 eBPF 跟踪 MySQL 查询
|
||||||
|
- [lesson 48-energy](src/48-energy/README.zh.md) eBPF 教程:进程级能源监控与功耗分析
|
||||||
|
|
||||||
|
|
||||||
安全:
|
安全:
|
||||||
|
|
||||||
- [lesson 24-hide](src/24-hide/README.zh.md) eBPF 开发实践:使用 eBPF 隐藏进程或文件信息
|
- [lesson 24-hide](src/24-hide/README.zh.md) eBPF 开发实践:使用 eBPF 隐藏进程或文件信息
|
||||||
@@ -76,22 +95,28 @@ GPU:
|
|||||||
- [lesson 27-replace](src/27-replace/README.zh.md) 替换任意程序读取或者写入的文本
|
- [lesson 27-replace](src/27-replace/README.zh.md) 替换任意程序读取或者写入的文本
|
||||||
- [lesson 28-detach](src/28-detach/README.zh.md) 在应用程序退出后运行 eBPF 程序:eBPF 程序的生命周期
|
- [lesson 28-detach](src/28-detach/README.zh.md) 在应用程序退出后运行 eBPF 程序:eBPF 程序的生命周期
|
||||||
- [lesson 34-syscall](src/34-syscall/README.zh.md) eBPF 开发实践:使用 eBPF 修改系统调用参数
|
- [lesson 34-syscall](src/34-syscall/README.zh.md) eBPF 开发实践:使用 eBPF 修改系统调用参数
|
||||||
|
|
||||||
|
|
||||||
特性:
|
特性:
|
||||||
|
|
||||||
- [lesson 35-user-ringbuf](src/35-user-ringbuf/README.zh.md) eBPF开发实践:使用 user ring buffer 向内核异步发送信息
|
- [lesson 35-user-ringbuf](src/35-user-ringbuf/README.zh.md) eBPF开发实践:使用 user ring buffer 向内核异步发送信息
|
||||||
- [lesson 36-userspace-ebpf](src/36-userspace-ebpf/README.zh.md) 用户空间 eBPF 运行时:深度解析与应用实践
|
- [lesson 36-userspace-ebpf](src/36-userspace-ebpf/README.zh.md) 用户空间 eBPF 运行时:深度解析与应用实践
|
||||||
- [lesson 38-btf-uprobe](src/38-btf-uprobe/README.zh.md) 借助 eBPF 和 BTF,让用户态也能一次编译、到处运行
|
- [lesson 38-btf-uprobe](src/38-btf-uprobe/README.zh.md) 借助 eBPF 和 BTF,让用户态也能一次编译、到处运行
|
||||||
- [lesson 43-kfuncs](src/43-kfuncs/README.zh.md) 超越 eBPF 的极限:在内核模块中定义自定义 kfunc
|
- [lesson 43-kfuncs](src/43-kfuncs/README.zh.md) 超越 eBPF 的极限:在内核模块中定义自定义 kfunc
|
||||||
|
- [features bpf_arena](src/features/bpf_arena/README.zh.md) eBPF 实例教程:BPF Arena 零拷贝共享内存
|
||||||
- [features bpf_iters](src/features/bpf_iters/README.zh.md) eBPF 教程:BPF 迭代器用于内核数据导出
|
- [features bpf_iters](src/features/bpf_iters/README.zh.md) eBPF 教程:BPF 迭代器用于内核数据导出
|
||||||
- [features bpf_token](src/features/bpf_token/README.zh.md) eBPF 入门实践教程:BPF Token,安全的委托式权限与程序加载
|
- [features bpf_token](src/features/bpf_token/README.zh.md) eBPF 入门实践教程:BPF Token,安全的委托式权限与程序加载
|
||||||
- [features dynptr](src/features/dynptr/README.zh.md) BPF Dynamic Pointers for Variable-Length Data
|
|
||||||
- [features bpf_wq](src/features/bpf_wq/README.zh.md) eBPF 教程:BPF 工作队列用于异步可睡眠任务
|
- [features bpf_wq](src/features/bpf_wq/README.zh.md) eBPF 教程:BPF 工作队列用于异步可睡眠任务
|
||||||
- [features bpf_arena](src/features/bpf_arena/README.zh.md) eBPF 实例教程:BPF Arena 零拷贝共享内存
|
- [features dynptr](src/features/dynptr/README.zh.md) BPF Dynamic Pointers for Variable-Length Data
|
||||||
- [features struct_ops](src/features/struct_ops/README.zh.md) eBPF 教程:使用 BPF struct_ops 扩展内核子系统
|
- [features struct_ops](src/features/struct_ops/README.zh.md) eBPF 教程:使用 BPF struct_ops 扩展内核子系统
|
||||||
特性:
|
|
||||||
|
|
||||||
|
其他:
|
||||||
|
|
||||||
- [lesson 49-hid](src/49-hid/README.zh.md) eBPF 教程:无需内核补丁修复故障的 HID 设备
|
- [lesson 49-hid](src/49-hid/README.zh.md) eBPF 教程:无需内核补丁修复故障的 HID 设备
|
||||||
- [cgroup](src/cgroup/README.zh.md) eBPF 实例教程:基于 cgroup 的策略控制
|
- [cgroup](src/cgroup/README.zh.md) eBPF 实例教程:基于 cgroup 的策略控制
|
||||||
|
|
||||||
|
|
||||||
Android:
|
Android:
|
||||||
|
|
||||||
- [lesson 22-android](src/22-android/README.zh.md) 在 Android 上使用 eBPF 程序
|
- [lesson 22-android](src/22-android/README.zh.md) 在 Android 上使用 eBPF 程序
|
||||||
@@ -100,7 +125,7 @@ Android:
|
|||||||
|
|
||||||
## 为什么要写这个教程?
|
## 为什么要写这个教程?
|
||||||
|
|
||||||
在学习 eBPF 的过程中,我们受到了 [bcc python developer tutorial](src/bcc-documents/tutorial_bcc_python_developer.md) 的许多启发和帮助,但从当下的角度出发,使用 libbpf 开发 eBPF 的应用是目前相对更好的选择。但目前似乎很少有基于 libbpf 和 BPF CO-RE 出发的、通过案例和工具介绍 eBPF 开发的教程,因此我们发起了这个项目,采用类似 bcc python developer tutorial 的组织方式,但使用 CO-RE 的 libbpf 进行开发。
|
在学习 eBPF 的过程中,我们受到了 [bcc Python developer tutorial](https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md) 的许多启发和帮助,但从当下的角度出发,使用 libbpf 开发 eBPF 的应用是目前相对更好的选择。但目前似乎很少有基于 libbpf 和 BPF CO-RE 出发的、通过案例和工具介绍 eBPF 开发的教程,因此我们发起了这个项目,采用类似 bcc Python developer tutorial 的组织方式,但使用 CO-RE 的 libbpf 进行开发。
|
||||||
|
|
||||||
本项目主要基于 [libbpf-boostrap](https://github.com/libbpf/libbpf-bootstrap) 和 [eunomia-bpf](https://github.com/eunomia-bpf/eunomia-bpf) 两个框架完成,并使用 eunomia-bpf 帮助简化一部分 libbpf eBPF 用户态代码的编写,让开发者专注于内核态的 eBPF 代码的开发。
|
本项目主要基于 [libbpf-boostrap](https://github.com/libbpf/libbpf-bootstrap) 和 [eunomia-bpf](https://github.com/eunomia-bpf/eunomia-bpf) 两个框架完成,并使用 eunomia-bpf 帮助简化一部分 libbpf eBPF 用户态代码的编写,让开发者专注于内核态的 eBPF 代码的开发。
|
||||||
|
|
||||||
@@ -228,8 +253,6 @@ eunomia-bpf 由一个编译工具链和一个运行时库组成, 对比传统的
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
完整的对话记录可以在这里找到: [ChatGPT.md](src/ChatGPT.md)
|
|
||||||
|
|
||||||
我们也构建了一个命令行工具的 demo ,通过本教程的训练, 让它通过自然语言描述即可自动编写 eBPF 程序,追踪 Linux 系统:<https://github.com/eunomia-bpf/GPTtrace>
|
我们也构建了一个命令行工具的 demo ,通过本教程的训练, 让它通过自然语言描述即可自动编写 eBPF 程序,追踪 Linux 系统:<https://github.com/eunomia-bpf/GPTtrace>
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -19,7 +19,7 @@ The tutorial focuses on eBPF examples in observability, networking, security, an
|
|||||||
|
|
||||||
## Why write this tutorial?
|
## Why write this tutorial?
|
||||||
|
|
||||||
In the process of learning eBPF, we have been inspired and helped by the [bcc python developer tutorial](src/bcc-documents/tutorial_bcc_python_developer.md). However, from the current perspective, using `libbpf` to develop eBPF applications is a relatively better choice.
|
In the process of learning eBPF, we have been inspired and helped by the [bcc Python developer tutorial](https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md). However, from the current perspective, using `libbpf` to develop eBPF applications is a relatively better choice.
|
||||||
|
|
||||||
This project is mainly based on [libbpf](https://github.com/libbpf/libbpf) frameworks.
|
This project is mainly based on [libbpf](https://github.com/libbpf/libbpf) frameworks.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
[GitHub](https://github.com/eunomia-bpf/bpf-developer-tutorial)
|
[GitHub](https://github.com/eunomia-bpf/bpf-developer-tutorial)
|
||||||
[Gitee 镜像](https://gitee.com/yunwei37/bpf-developer-tutorial)
|
[Gitee 镜像](https://gitee.com/yunwei37/bpf-developer-tutorial)
|
||||||
[English Version](README_en.md)
|
[English Version](README.md)
|
||||||
|
|
||||||
#### [**Check out the English version here**](README.md)
|
#### [**Check out the English version here**](README.md)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
## 为什么要写这个教程?
|
## 为什么要写这个教程?
|
||||||
|
|
||||||
在学习 eBPF 的过程中,我们受到了 [bcc python developer tutorial](src/bcc-documents/tutorial_bcc_python_developer.md) 的许多启发和帮助,但从当下的角度出发,使用 libbpf 开发 eBPF 的应用是目前相对更好的选择。但目前似乎很少有基于 libbpf 和 BPF CO-RE 出发的、通过案例和工具介绍 eBPF 开发的教程,因此我们发起了这个项目,采用类似 bcc python developer tutorial 的组织方式,但使用 CO-RE 的 libbpf 进行开发。
|
在学习 eBPF 的过程中,我们受到了 [bcc Python developer tutorial](https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md) 的许多启发和帮助,但从当下的角度出发,使用 libbpf 开发 eBPF 的应用是目前相对更好的选择。但目前似乎很少有基于 libbpf 和 BPF CO-RE 出发的、通过案例和工具介绍 eBPF 开发的教程,因此我们发起了这个项目,采用类似 bcc Python developer tutorial 的组织方式,但使用 CO-RE 的 libbpf 进行开发。
|
||||||
|
|
||||||
本项目主要基于 [libbpf-boostrap](https://github.com/libbpf/libbpf-bootstrap) 和 [eunomia-bpf](https://github.com/eunomia-bpf/eunomia-bpf) 两个框架完成,并使用 eunomia-bpf 帮助简化一部分 libbpf eBPF 用户态代码的编写,让开发者专注于内核态的 eBPF 代码的开发。
|
本项目主要基于 [libbpf-boostrap](https://github.com/libbpf/libbpf-bootstrap) 和 [eunomia-bpf](https://github.com/eunomia-bpf/eunomia-bpf) 两个框架完成,并使用 eunomia-bpf 帮助简化一部分 libbpf eBPF 用户态代码的编写,让开发者专注于内核态的 eBPF 代码的开发。
|
||||||
|
|
||||||
@@ -146,8 +146,6 @@ eunomia-bpf 由一个编译工具链和一个运行时库组成, 对比传统的
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
完整的对话记录可以在这里找到: [ChatGPT.md](src/ChatGPT.md)
|
|
||||||
|
|
||||||
我们也构建了一个命令行工具的 demo ,通过本教程的训练, 让它通过自然语言描述即可自动编写 eBPF 程序,追踪 Linux 系统:<https://github.com/eunomia-bpf/GPTtrace>
|
我们也构建了一个命令行工具的 demo ,通过本教程的训练, 让它通过自然语言描述即可自动编写 eBPF 程序,追踪 Linux 系统:<https://github.com/eunomia-bpf/GPTtrace>
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
205
scripts/check_internal_links.py
Normal file
205
scripts/check_internal_links.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Check relative Markdown links and images without making network requests."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from urllib.parse import unquote, urlsplit
|
||||||
|
|
||||||
|
|
||||||
|
INLINE_LINK_PATTERN = re.compile(r"(?<!\\)\]\(")
|
||||||
|
REFERENCE_DEFINITION_PATTERN = re.compile(r"^ {0,3}\[[^]]+\]:[ \t]*(.*)$")
|
||||||
|
FENCE_PATTERN = re.compile(r"^ {0,3}(`{3,}|~{3,})(.*)$")
|
||||||
|
MARKDOWN_ESCAPE_PATTERN = re.compile(r"\\([!\"#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~])")
|
||||||
|
IGNORED_SCHEMES = {"data", "http", "https", "javascript", "mailto"}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BrokenLink:
|
||||||
|
source: Path
|
||||||
|
line: int
|
||||||
|
destination: str
|
||||||
|
|
||||||
|
|
||||||
|
def markdown_files(root: Path) -> list[Path]:
|
||||||
|
return sorted(
|
||||||
|
path
|
||||||
|
for path in root.rglob("*.md")
|
||||||
|
if not {".git", "build", "node_modules", "site"}.intersection(path.parts)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def strip_code_spans(line: str) -> str:
|
||||||
|
"""Blank inline code while preserving character offsets."""
|
||||||
|
result = list(line)
|
||||||
|
position = 0
|
||||||
|
while position < len(line):
|
||||||
|
if line[position] != "`":
|
||||||
|
position += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
delimiter_end = position
|
||||||
|
while delimiter_end < len(line) and line[delimiter_end] == "`":
|
||||||
|
delimiter_end += 1
|
||||||
|
delimiter_length = delimiter_end - position
|
||||||
|
closing = delimiter_end
|
||||||
|
while closing < len(line):
|
||||||
|
if line[closing] != "`":
|
||||||
|
closing += 1
|
||||||
|
continue
|
||||||
|
closing_end = closing
|
||||||
|
while closing_end < len(line) and line[closing_end] == "`":
|
||||||
|
closing_end += 1
|
||||||
|
if closing_end - closing == delimiter_length:
|
||||||
|
break
|
||||||
|
closing = closing_end
|
||||||
|
if closing >= len(line):
|
||||||
|
position = delimiter_end
|
||||||
|
continue
|
||||||
|
|
||||||
|
result[position : closing + delimiter_length] = " " * (
|
||||||
|
closing + delimiter_length - position
|
||||||
|
)
|
||||||
|
position = closing + delimiter_length
|
||||||
|
return "".join(result)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_angle_destination(text: str, position: int) -> str:
|
||||||
|
destination: list[str] = []
|
||||||
|
while position < len(text):
|
||||||
|
if text[position] == "\\" and position + 1 < len(text):
|
||||||
|
destination.extend(text[position : position + 2])
|
||||||
|
position += 2
|
||||||
|
elif text[position] == ">":
|
||||||
|
return "".join(destination)
|
||||||
|
else:
|
||||||
|
destination.append(text[position])
|
||||||
|
position += 1
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def parse_bare_destination(text: str, position: int) -> str:
|
||||||
|
destination = []
|
||||||
|
parentheses = 0
|
||||||
|
while position < len(text):
|
||||||
|
character = text[position]
|
||||||
|
if character == "\\" and position + 1 < len(text):
|
||||||
|
destination.extend(text[position : position + 2])
|
||||||
|
position += 2
|
||||||
|
continue
|
||||||
|
if character == "(":
|
||||||
|
parentheses += 1
|
||||||
|
elif character == ")":
|
||||||
|
if parentheses == 0:
|
||||||
|
break
|
||||||
|
parentheses -= 1
|
||||||
|
elif character.isspace() and parentheses == 0:
|
||||||
|
break
|
||||||
|
destination.append(character)
|
||||||
|
position += 1
|
||||||
|
return "".join(destination) if parentheses == 0 else ""
|
||||||
|
|
||||||
|
|
||||||
|
def parse_destination(text: str, start: int = 0) -> str:
|
||||||
|
"""Parse one CommonMark-style link destination from text."""
|
||||||
|
position = start
|
||||||
|
while position < len(text) and text[position] in " \t":
|
||||||
|
position += 1
|
||||||
|
if position >= len(text):
|
||||||
|
return ""
|
||||||
|
if text[position] == "<":
|
||||||
|
return parse_angle_destination(text, position + 1)
|
||||||
|
return parse_bare_destination(text, position)
|
||||||
|
|
||||||
|
|
||||||
|
def destinations_in_line(line: str) -> list[str]:
|
||||||
|
without_code = strip_code_spans(line)
|
||||||
|
destinations = [
|
||||||
|
parse_destination(without_code, match.end())
|
||||||
|
for match in INLINE_LINK_PATTERN.finditer(without_code)
|
||||||
|
]
|
||||||
|
reference = REFERENCE_DEFINITION_PATTERN.match(without_code)
|
||||||
|
if reference:
|
||||||
|
destinations.append(parse_destination(reference.group(1)))
|
||||||
|
return destinations
|
||||||
|
|
||||||
|
|
||||||
|
def is_ignored(destination: str) -> bool:
|
||||||
|
parsed = urlsplit(destination)
|
||||||
|
return (
|
||||||
|
not destination
|
||||||
|
or destination.startswith(("#", "/"))
|
||||||
|
or parsed.scheme.lower() in IGNORED_SCHEMES
|
||||||
|
or any(marker in destination for marker in ("${", "{{", "}}"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def filesystem_path(destination: str) -> str:
|
||||||
|
decoded = unquote(urlsplit(destination).path)
|
||||||
|
return MARKDOWN_ESCAPE_PATTERN.sub(r"\1", decoded)
|
||||||
|
|
||||||
|
|
||||||
|
def find_broken_links(root: Path) -> list[BrokenLink]:
|
||||||
|
root = root.resolve()
|
||||||
|
broken: list[BrokenLink] = []
|
||||||
|
|
||||||
|
for source in markdown_files(root):
|
||||||
|
fence: tuple[str, int] | None = None
|
||||||
|
for line_number, line in enumerate(source.read_text(encoding="utf-8").splitlines(), 1):
|
||||||
|
match = FENCE_PATTERN.match(line)
|
||||||
|
if fence is not None:
|
||||||
|
marker, minimum_length = fence
|
||||||
|
if re.fullmatch(
|
||||||
|
rf" {{0,3}}{re.escape(marker)}{{{minimum_length},}}[ \t]*", line
|
||||||
|
):
|
||||||
|
fence = None
|
||||||
|
continue
|
||||||
|
if match:
|
||||||
|
marker = match.group(1)
|
||||||
|
if not (marker[0] == "`" and "`" in match.group(2)):
|
||||||
|
fence = (marker[0], len(marker))
|
||||||
|
continue
|
||||||
|
|
||||||
|
for destination in destinations_in_line(line):
|
||||||
|
if is_ignored(destination):
|
||||||
|
continue
|
||||||
|
relative_path = filesystem_path(destination)
|
||||||
|
if relative_path and not (source.parent / relative_path).exists():
|
||||||
|
broken.append(
|
||||||
|
BrokenLink(source.relative_to(root), line_number, destination)
|
||||||
|
)
|
||||||
|
|
||||||
|
return broken
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument(
|
||||||
|
"root",
|
||||||
|
nargs="?",
|
||||||
|
type=Path,
|
||||||
|
default=Path(__file__).resolve().parent.parent,
|
||||||
|
help="repository root (defaults to the parent of scripts/)",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
broken = find_broken_links(args.root)
|
||||||
|
if not broken:
|
||||||
|
print("All relative Markdown links resolve.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print(f"Found {len(broken)} broken relative Markdown link(s):", file=sys.stderr)
|
||||||
|
for item in broken:
|
||||||
|
print(
|
||||||
|
f"{item.source}:{item.line}: {item.destination}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -25,7 +25,8 @@ def generate_toc(base_dir, project_root, output_file_dir):
|
|||||||
|
|
||||||
# To ensure numeric sorting of directories
|
# To ensure numeric sorting of directories
|
||||||
def sort_key(directory_name):
|
def sort_key(directory_name):
|
||||||
return list(map(int, re.findall(r'\d+', directory_name)))
|
numbers = tuple(map(int, re.findall(r'\d+', directory_name)))
|
||||||
|
return (0, numbers, directory_name) if numbers else (1, (), directory_name)
|
||||||
|
|
||||||
sections = {} # {section_level: {subsection_type: [lessons]}}
|
sections = {} # {section_level: {subsection_type: [lessons]}}
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ def generate_toc(base_dir, project_root, output_file_dir):
|
|||||||
all_dirs.append(os.path.join(item, subitem))
|
all_dirs.append(os.path.join(item, subitem))
|
||||||
|
|
||||||
# Sort directories properly by numeric order (non-numeric dirs go to end)
|
# Sort directories properly by numeric order (non-numeric dirs go to end)
|
||||||
all_dirs = sorted(all_dirs, key=lambda d: sort_key(d) if re.search(r'\d+', d) else [999999])
|
all_dirs = sorted(all_dirs, key=sort_key)
|
||||||
|
|
||||||
# Loop over the sorted directories
|
# Loop over the sorted directories
|
||||||
for directory in all_dirs:
|
for directory in all_dirs:
|
||||||
@@ -142,21 +143,22 @@ def generate_toc_cn(base_dir, project_root, output_file_dir):
|
|||||||
}
|
}
|
||||||
|
|
||||||
subsection_titles = {
|
subsection_titles = {
|
||||||
"Android": "Android:\n\n",
|
"Android": "\n\nAndroid:\n\n",
|
||||||
"GPU": "GPU:\n\n",
|
"GPU": "\n\nGPU:\n\n",
|
||||||
"Scheduler": "调度器:\n\n",
|
"Scheduler": "\n\n调度器:\n\n",
|
||||||
"Networking": "网络:\n\n",
|
"Networking": "\n\n网络:\n\n",
|
||||||
"tracing": "Tracing:\n\n",
|
"Tracing": "\n\n追踪:\n\n",
|
||||||
"Security": "安全:\n\n",
|
"Security": "\n\n安全:\n\n",
|
||||||
"Features": "特性:\n\n",
|
"Features": "\n\n特性:\n\n",
|
||||||
"Other": "特性:\n\n"
|
"Other": "\n\n其他:\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
subsection_order = ['GPU', 'Scheduler', 'Networking', 'tracing', 'Security', 'Features', 'Other', 'Android']
|
subsection_order = ['GPU', 'Scheduler', 'Networking', 'Tracing', 'Security', 'Features', 'Other', 'Android']
|
||||||
|
|
||||||
# To ensure numeric sorting of directories
|
# To ensure numeric sorting of directories
|
||||||
def sort_key(directory_name):
|
def sort_key(directory_name):
|
||||||
return list(map(int, re.findall(r'\d+', directory_name)))
|
numbers = tuple(map(int, re.findall(r'\d+', directory_name)))
|
||||||
|
return (0, numbers, directory_name) if numbers else (1, (), directory_name)
|
||||||
|
|
||||||
sections = {} # {section_level: {subsection_type: [lessons]}}
|
sections = {} # {section_level: {subsection_type: [lessons]}}
|
||||||
|
|
||||||
@@ -179,7 +181,7 @@ def generate_toc_cn(base_dir, project_root, output_file_dir):
|
|||||||
all_dirs.append(os.path.join(item, subitem))
|
all_dirs.append(os.path.join(item, subitem))
|
||||||
|
|
||||||
# Sort directories properly by numeric order (non-numeric dirs go to end)
|
# Sort directories properly by numeric order (non-numeric dirs go to end)
|
||||||
all_dirs = sorted(all_dirs, key=lambda d: sort_key(d) if re.search(r'\d+', d) else [999999])
|
all_dirs = sorted(all_dirs, key=sort_key)
|
||||||
|
|
||||||
# Loop over the sorted directories
|
# Loop over the sorted directories
|
||||||
for directory in all_dirs:
|
for directory in all_dirs:
|
||||||
|
|||||||
94
scripts/test_check_internal_links.py
Normal file
94
scripts/test_check_internal_links.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from scripts.check_internal_links import find_broken_links
|
||||||
|
|
||||||
|
|
||||||
|
class InternalLinkCheckerTest(unittest.TestCase):
|
||||||
|
def test_accepts_existing_paths_and_ignores_non_file_links(self):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
(root / "guide").mkdir()
|
||||||
|
(root / "guide" / "target file.md").write_text("# Target\n", encoding="utf-8")
|
||||||
|
(root / "guide_(v1).md").write_text("# Target\n", encoding="utf-8")
|
||||||
|
(root / "README.md").write_text(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"[guide](guide/)",
|
||||||
|
"[encoded](guide/target%20file.md)",
|
||||||
|
"[with title](guide/target%20file.md \"Target\")",
|
||||||
|
"[parentheses](guide_(v1).md)",
|
||||||
|
"[reference][target]",
|
||||||
|
"[target]: guide/target%20file.md \"Target\"",
|
||||||
|
"[anchor](#section)",
|
||||||
|
"[site route](/tutorials/)",
|
||||||
|
"[external](https://example.com/missing)",
|
||||||
|
"```markdown",
|
||||||
|
"[example](missing-example.md)",
|
||||||
|
"```",
|
||||||
|
"`[inline example](missing-inline.md)`",
|
||||||
|
"````markdown",
|
||||||
|
"```",
|
||||||
|
"[nested example](missing-nested.md)",
|
||||||
|
"```",
|
||||||
|
"````",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(find_broken_links(root), [])
|
||||||
|
|
||||||
|
def test_reports_missing_relative_link_with_source_line(self):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
(root / "README.md").write_text(
|
||||||
|
"# Guide\n\n[missing](docs/missing.md)\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
broken = find_broken_links(root)
|
||||||
|
|
||||||
|
self.assertEqual(len(broken), 1)
|
||||||
|
self.assertEqual(broken[0].source, Path("README.md"))
|
||||||
|
self.assertEqual(broken[0].line, 3)
|
||||||
|
self.assertEqual(broken[0].destination, "docs/missing.md")
|
||||||
|
|
||||||
|
def test_reports_missing_reference_destination(self):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
(root / "README.md").write_text(
|
||||||
|
"[guide][docs]\n[docs]: missing_(v1).md\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
broken = find_broken_links(root)
|
||||||
|
|
||||||
|
self.assertEqual(len(broken), 1)
|
||||||
|
self.assertEqual(broken[0].line, 2)
|
||||||
|
self.assertEqual(broken[0].destination, "missing_(v1).md")
|
||||||
|
|
||||||
|
def test_closes_fence_only_with_a_long_enough_matching_delimiter(self):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
(root / "README.md").write_text(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"````markdown",
|
||||||
|
"```",
|
||||||
|
"[example](ignored.md)",
|
||||||
|
"````",
|
||||||
|
"[missing](reported.md)",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
broken = find_broken_links(root)
|
||||||
|
|
||||||
|
self.assertEqual(len(broken), 1)
|
||||||
|
self.assertEqual(broken[0].line, 5)
|
||||||
|
self.assertEqual(broken[0].destination, "reported.md")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
49
scripts/test_generate_toc.py
Normal file
49
scripts/test_generate_toc.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from scripts.generate_toc import generate_toc, generate_toc_cn
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
LINK_PATTERN = re.compile(r"\]\((src/.+?)/README(?:\.zh)?\.md\)")
|
||||||
|
TRACING_LESSONS = {
|
||||||
|
"src/30-sslsniff",
|
||||||
|
"src/31-goroutine",
|
||||||
|
"src/33-funclatency",
|
||||||
|
"src/37-uprobe-rust",
|
||||||
|
"src/39-nginx",
|
||||||
|
"src/40-mysql",
|
||||||
|
"src/48-energy",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def lesson_links(markdown: str) -> set[str]:
|
||||||
|
return set(LINK_PATTERN.findall(markdown))
|
||||||
|
|
||||||
|
|
||||||
|
def subsection(markdown: str, heading: str, next_heading: str) -> str:
|
||||||
|
return markdown.split(f"\n\n{heading}:\n\n", 1)[1].split(
|
||||||
|
f"\n\n{next_heading}:\n\n", 1
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
|
||||||
|
class TocParityTest(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.english = generate_toc(ROOT / "src", ROOT, ROOT)
|
||||||
|
cls.chinese = generate_toc_cn(ROOT / "src", ROOT, ROOT)
|
||||||
|
|
||||||
|
def test_english_and_chinese_indexes_contain_the_same_lessons(self):
|
||||||
|
self.assertSetEqual(lesson_links(self.english), lesson_links(self.chinese))
|
||||||
|
|
||||||
|
def test_chinese_tracing_subsection_contains_all_tracing_lessons(self):
|
||||||
|
english_tracing = lesson_links(subsection(self.english, "Tracing", "Security"))
|
||||||
|
chinese_tracing = lesson_links(subsection(self.chinese, "追踪", "安全"))
|
||||||
|
|
||||||
|
self.assertSetEqual(english_tracing, TRACING_LESSONS)
|
||||||
|
self.assertSetEqual(chinese_tracing, TRACING_LESSONS)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -47,9 +47,9 @@ This section covers advanced topics related to eBPF, including using eBPF progra
|
|||||||
GPU:
|
GPU:
|
||||||
|
|
||||||
- [lesson 47-cuda-events](47-cuda-events/README.md) Tracing CUDA GPU Operations
|
- [lesson 47-cuda-events](47-cuda-events/README.md) Tracing CUDA GPU Operations
|
||||||
- [lesson xpu/npu-kernel-driver](xpu/npu-kernel-driver/README.md) Tracing Intel NPU Kernel Driver Operations
|
|
||||||
- [xpu flamegraph](xpu/flamegraph/README.md) Building a GPU Flamegraph Profiler with CUPTI
|
- [xpu flamegraph](xpu/flamegraph/README.md) Building a GPU Flamegraph Profiler with CUPTI
|
||||||
- [lesson xpu/gpu-kernel-driver](xpu/gpu-kernel-driver/README.md) Monitoring GPU Driver Activity with Kernel Tracepoints
|
- [lesson xpu/gpu-kernel-driver](xpu/gpu-kernel-driver/README.md) Monitoring GPU Driver Activity with Kernel Tracepoints
|
||||||
|
- [lesson xpu/npu-kernel-driver](xpu/npu-kernel-driver/README.md) Tracing Intel NPU Kernel Driver Operations
|
||||||
|
|
||||||
|
|
||||||
Scheduler:
|
Scheduler:
|
||||||
@@ -95,11 +95,11 @@ Features:
|
|||||||
- [lesson 36-userspace-ebpf](36-userspace-ebpf/README.md) Userspace eBPF Runtimes: Overview and Applications
|
- [lesson 36-userspace-ebpf](36-userspace-ebpf/README.md) Userspace eBPF Runtimes: Overview and Applications
|
||||||
- [lesson 38-btf-uprobe](38-btf-uprobe/README.md) Expanding eBPF Compile Once, Run Everywhere(CO-RE) to Userspace Compatibility
|
- [lesson 38-btf-uprobe](38-btf-uprobe/README.md) Expanding eBPF Compile Once, Run Everywhere(CO-RE) to Userspace Compatibility
|
||||||
- [lesson 43-kfuncs](43-kfuncs/README.md) Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules
|
- [lesson 43-kfuncs](43-kfuncs/README.md) Extending eBPF Beyond Its Limits: Custom kfuncs in Kernel Modules
|
||||||
|
- [features bpf_arena](features/bpf_arena/README.md) BPF Arena for Zero-Copy Shared Memory
|
||||||
- [features bpf_iters](features/bpf_iters/README.md) BPF Iterators for Kernel Data Export
|
- [features bpf_iters](features/bpf_iters/README.md) BPF Iterators for Kernel Data Export
|
||||||
- [features bpf_token](features/bpf_token/README.md) BPF Token for Delegated Privilege and Secure Program Loading
|
- [features bpf_token](features/bpf_token/README.md) BPF Token for Delegated Privilege and Secure Program Loading
|
||||||
- [features dynptr](features/dynptr/README.md) BPF Dynamic Pointers for Variable-Length Data
|
|
||||||
- [features bpf_wq](features/bpf_wq/README.md) BPF Workqueues for Asynchronous Sleepable Tasks
|
- [features bpf_wq](features/bpf_wq/README.md) BPF Workqueues for Asynchronous Sleepable Tasks
|
||||||
- [features bpf_arena](features/bpf_arena/README.md) BPF Arena for Zero-Copy Shared Memory
|
- [features dynptr](features/dynptr/README.md) BPF Dynamic Pointers for Variable-Length Data
|
||||||
- [features struct_ops](features/struct_ops/README.md) Extending Kernel Subsystems with BPF struct_ops
|
- [features struct_ops](features/struct_ops/README.md) Extending Kernel Subsystems with BPF struct_ops
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
|
|||||||
@@ -42,16 +42,22 @@
|
|||||||
|
|
||||||
这一部分涵盖了与 eBPF 相关的高级主题,包括在 Android 上使用 eBPF 程序、利用 eBPF 程序进行的潜在攻击和防御以及复杂的追踪。结合用户模式和内核模式的 eBPF 可以带来强大的能力(也可能带来安全风险)。
|
这一部分涵盖了与 eBPF 相关的高级主题,包括在 Android 上使用 eBPF 程序、利用 eBPF 程序进行的潜在攻击和防御以及复杂的追踪。结合用户模式和内核模式的 eBPF 可以带来强大的能力(也可能带来安全风险)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GPU:
|
GPU:
|
||||||
|
|
||||||
- [lesson 47-cuda-events](47-cuda-events/README.zh.md) eBPF 教程:追踪 CUDA GPU 操作
|
- [lesson 47-cuda-events](47-cuda-events/README.zh.md) eBPF 教程:追踪 CUDA GPU 操作
|
||||||
- [lesson xpu/npu-kernel-driver](xpu/npu-kernel-driver/README.zh.md) eBPF 实例教程:跟踪 Intel NPU 内核驱动操作
|
|
||||||
- [xpu flamegraph](xpu/flamegraph/README.zh.md) eBPF 示例:使用 CUPTI 构建 GPU 火焰图分析器
|
- [xpu flamegraph](xpu/flamegraph/README.zh.md) eBPF 示例:使用 CUPTI 构建 GPU 火焰图分析器
|
||||||
- [lesson xpu/gpu-kernel-driver](xpu/gpu-kernel-driver/README.zh.md) eBPF 实例教程:使用内核跟踪点监控 GPU 驱动活动
|
- [lesson xpu/gpu-kernel-driver](xpu/gpu-kernel-driver/README.zh.md) eBPF 实例教程:使用内核跟踪点监控 GPU 驱动活动
|
||||||
|
- [lesson xpu/npu-kernel-driver](xpu/npu-kernel-driver/README.zh.md) eBPF 实例教程:跟踪 Intel NPU 内核驱动操作
|
||||||
|
|
||||||
|
|
||||||
调度器:
|
调度器:
|
||||||
|
|
||||||
- [lesson 44-scx-simple](44-scx-simple/README.zh.md) eBPF 教程:BPF 调度器入门
|
- [lesson 44-scx-simple](44-scx-simple/README.zh.md) eBPF 教程:BPF 调度器入门
|
||||||
- [lesson 45-scx-nest](45-scx-nest/README.zh.md) eBPF 示例教程:实现 `scx_nest` 调度器
|
- [lesson 45-scx-nest](45-scx-nest/README.zh.md) eBPF 示例教程:实现 `scx_nest` 调度器
|
||||||
|
|
||||||
|
|
||||||
网络:
|
网络:
|
||||||
|
|
||||||
- [lesson 23-http](23-http/README.zh.md) 通过 eBPF socket filter 或 syscall trace 追踪 HTTP 请求等七层协议 - eBPF 实践教程
|
- [lesson 23-http](23-http/README.zh.md) 通过 eBPF socket filter 或 syscall trace 追踪 HTTP 请求等七层协议 - eBPF 实践教程
|
||||||
@@ -60,6 +66,19 @@ GPU:
|
|||||||
- [lesson 42-xdp-loadbalancer](42-xdp-loadbalancer/README.zh.md) eBPF 开发者教程: 简单的 XDP 负载均衡器
|
- [lesson 42-xdp-loadbalancer](42-xdp-loadbalancer/README.zh.md) eBPF 开发者教程: 简单的 XDP 负载均衡器
|
||||||
- [lesson 46-xdp-test](46-xdp-test/README.zh.md) eBPF 实例教程:构建高性能 XDP 数据包生成器
|
- [lesson 46-xdp-test](46-xdp-test/README.zh.md) eBPF 实例教程:构建高性能 XDP 数据包生成器
|
||||||
- [lesson 50-tcx](50-tcx/README.zh.md) eBPF 入门实践教程第五十篇:使用 TCX Link 实现可组合的流量控制
|
- [lesson 50-tcx](50-tcx/README.zh.md) eBPF 入门实践教程第五十篇:使用 TCX Link 实现可组合的流量控制
|
||||||
|
|
||||||
|
|
||||||
|
追踪:
|
||||||
|
|
||||||
|
- [lesson 30-sslsniff](30-sslsniff/README.zh.md) eBPF 实践教程:使用 uprobe 捕获多种库的 SSL/TLS 明文数据
|
||||||
|
- [lesson 31-goroutine](31-goroutine/README.zh.md) eBPF 实践教程:使用 eBPF 跟踪 Go 协程状态
|
||||||
|
- [lesson 33-funclatency](33-funclatency/README.zh.md) 使用 eBPF 测量函数延迟
|
||||||
|
- [lesson 37-uprobe-rust](37-uprobe-rust/README.zh.md) eBPF 实践:使用 Uprobe 追踪用户态 Rust 应用
|
||||||
|
- [lesson 39-nginx](39-nginx/README.zh.md) 使用 eBPF 跟踪 Nginx 请求
|
||||||
|
- [lesson 40-mysql](40-mysql/README.zh.md) 使用 eBPF 跟踪 MySQL 查询
|
||||||
|
- [lesson 48-energy](48-energy/README.zh.md) eBPF 教程:进程级能源监控与功耗分析
|
||||||
|
|
||||||
|
|
||||||
安全:
|
安全:
|
||||||
|
|
||||||
- [lesson 24-hide](24-hide/README.zh.md) eBPF 开发实践:使用 eBPF 隐藏进程或文件信息
|
- [lesson 24-hide](24-hide/README.zh.md) eBPF 开发实践:使用 eBPF 隐藏进程或文件信息
|
||||||
@@ -68,22 +87,28 @@ GPU:
|
|||||||
- [lesson 27-replace](27-replace/README.zh.md) 替换任意程序读取或者写入的文本
|
- [lesson 27-replace](27-replace/README.zh.md) 替换任意程序读取或者写入的文本
|
||||||
- [lesson 28-detach](28-detach/README.zh.md) 在应用程序退出后运行 eBPF 程序:eBPF 程序的生命周期
|
- [lesson 28-detach](28-detach/README.zh.md) 在应用程序退出后运行 eBPF 程序:eBPF 程序的生命周期
|
||||||
- [lesson 34-syscall](34-syscall/README.zh.md) eBPF 开发实践:使用 eBPF 修改系统调用参数
|
- [lesson 34-syscall](34-syscall/README.zh.md) eBPF 开发实践:使用 eBPF 修改系统调用参数
|
||||||
|
|
||||||
|
|
||||||
特性:
|
特性:
|
||||||
|
|
||||||
- [lesson 35-user-ringbuf](35-user-ringbuf/README.zh.md) eBPF开发实践:使用 user ring buffer 向内核异步发送信息
|
- [lesson 35-user-ringbuf](35-user-ringbuf/README.zh.md) eBPF开发实践:使用 user ring buffer 向内核异步发送信息
|
||||||
- [lesson 36-userspace-ebpf](36-userspace-ebpf/README.zh.md) 用户空间 eBPF 运行时:深度解析与应用实践
|
- [lesson 36-userspace-ebpf](36-userspace-ebpf/README.zh.md) 用户空间 eBPF 运行时:深度解析与应用实践
|
||||||
- [lesson 38-btf-uprobe](38-btf-uprobe/README.zh.md) 借助 eBPF 和 BTF,让用户态也能一次编译、到处运行
|
- [lesson 38-btf-uprobe](38-btf-uprobe/README.zh.md) 借助 eBPF 和 BTF,让用户态也能一次编译、到处运行
|
||||||
- [lesson 43-kfuncs](43-kfuncs/README.zh.md) 超越 eBPF 的极限:在内核模块中定义自定义 kfunc
|
- [lesson 43-kfuncs](43-kfuncs/README.zh.md) 超越 eBPF 的极限:在内核模块中定义自定义 kfunc
|
||||||
|
- [features bpf_arena](features/bpf_arena/README.zh.md) eBPF 实例教程:BPF Arena 零拷贝共享内存
|
||||||
- [features bpf_iters](features/bpf_iters/README.zh.md) eBPF 教程:BPF 迭代器用于内核数据导出
|
- [features bpf_iters](features/bpf_iters/README.zh.md) eBPF 教程:BPF 迭代器用于内核数据导出
|
||||||
- [features bpf_token](features/bpf_token/README.zh.md) eBPF 入门实践教程:BPF Token,安全的委托式权限与程序加载
|
- [features bpf_token](features/bpf_token/README.zh.md) eBPF 入门实践教程:BPF Token,安全的委托式权限与程序加载
|
||||||
- [features dynptr](features/dynptr/README.zh.md) BPF Dynamic Pointers for Variable-Length Data
|
|
||||||
- [features bpf_wq](features/bpf_wq/README.zh.md) eBPF 教程:BPF 工作队列用于异步可睡眠任务
|
- [features bpf_wq](features/bpf_wq/README.zh.md) eBPF 教程:BPF 工作队列用于异步可睡眠任务
|
||||||
- [features bpf_arena](features/bpf_arena/README.zh.md) eBPF 实例教程:BPF Arena 零拷贝共享内存
|
- [features dynptr](features/dynptr/README.zh.md) BPF Dynamic Pointers for Variable-Length Data
|
||||||
- [features struct_ops](features/struct_ops/README.zh.md) eBPF 教程:使用 BPF struct_ops 扩展内核子系统
|
- [features struct_ops](features/struct_ops/README.zh.md) eBPF 教程:使用 BPF struct_ops 扩展内核子系统
|
||||||
特性:
|
|
||||||
|
|
||||||
|
其他:
|
||||||
|
|
||||||
- [lesson 49-hid](49-hid/README.zh.md) eBPF 教程:无需内核补丁修复故障的 HID 设备
|
- [lesson 49-hid](49-hid/README.zh.md) eBPF 教程:无需内核补丁修复故障的 HID 设备
|
||||||
- [cgroup](cgroup/README.zh.md) eBPF 实例教程:基于 cgroup 的策略控制
|
- [cgroup](cgroup/README.zh.md) eBPF 实例教程:基于 cgroup 的策略控制
|
||||||
|
|
||||||
|
|
||||||
Android:
|
Android:
|
||||||
|
|
||||||
- [lesson 22-android](22-android/README.zh.md) 在 Android 上使用 eBPF 程序
|
- [lesson 22-android](22-android/README.zh.md) 在 Android 上使用 eBPF 程序
|
||||||
|
|||||||
Reference in New Issue
Block a user