Linux bcc tool
Linux BCC(BPF Compiler Collection)是一个强大的 eBPF 工具集,用于内核动态追踪和性能分析。它构建在 eBPF(Extended Berkeley Packet Filter)技术之上,简化了开发复杂内核观察程序的过程。下面我们从 整体架构、工作流程、关键组件、原理细节 四个方面分析 BCC 的工作原理。
整体架构
BCC 是一个用户空间的框架,帮助你编写、加载和操作 eBPF 程序。它的结构如下:
+------------------+
| Python / C++ API| ← 用户写脚本
+------------------+
↓
+------------------+
| BCC Frontend | ← 将 C 代码嵌入 Python
+------------------+
↓
+------------------+
| LLVM/Clang | ← 将嵌入的 C 编译成 BPF 字节码
+------------------+
↓
+------------------+
| Kernel BPF VM | ← 加载到内核,通过 bpf() syscall 执行
+------------------+
工作流程
-
- 用户脚本
- 用户使用 Python 或 C++ API 编写分析程序(如 execsnoop, tcpconnect 等)。
- eBPF 程序以字符串形式嵌入在脚本中,通常是一个小型的 C 程序。
-
- BCC 编译器前端
- BCC 提取 eBPF C 程序,将其传递给 LLVM 的 Clang 编译器。
- Clang 目标是 BPF target(-target bpf),生成 BPF 字节码(ELF 格式)。
-
- 内核加载
- BCC 使用 bpf() 系统调用将字节码加载到内核。
- 在加载时,内核 verifier 会检查程序安全性(禁止死循环、非法内存访问等)。
- 成功后,程序绑定到内核钩子,如 kprobe、tracepoint、socket filter、XDP 等。
-
- 数据采集与回传
- eBPF 程序通过 map 将数据传回用户空间。
- 用户空间脚本读取 map 中数据并输出,如打印事件或生成性能图表。
核心组件分析
-
- eBPF 程序(内核执行)
- 使用受限的 C 编写,不能使用浮点、不支持循环(老版本),仅支持固定调用集。
- 加载时由 BPF verifier 做安全校验。
- 执行位置包括:
- kprobe / kretprobe:函数进入和返回
- tracepoint:内核事件点
- uprobe / uretprobe:用户空间函数进入/返回
- XDP:数据包入站处理
- tc:流量控制 hook
- perf_event:周期性或采样 hook
-
- map(eBPF 与用户空间通信桥梁)
- 类似共享内存结构,内核和用户空间通过它读写数据。
- 类型包括:
- Hash
- Array
- Perf Event Array(高效事件传输)
- Stack Trace
- Ring Buffer(新式高性能通信)
-
- Clang / LLVM
- BCC 调用 clang 将 C 程序编译为 eBPF 字节码(使用 BPF backend)。
- 要求代码为 eBPF 限定子集:不能递归、栈限制、结构体必须固定大小等。
-
- Python / C++ 前端 API
- 包装 bpf() syscall
- 提供易用接口,如
BPF.attach_kprobe()、BPF.trace_print()等 - 实时收集 perf 事件和 map 数据
BCC 与内核交互机制原理
-
- 加载 BPF 程序
- 使用
bpf(BPF_PROG_LOAD, ...)系统调用 - 指定类型、入口函数、依赖 map 等
- 内核 verifier 校验字节码合法性(控制流图、访问边界)
-
- 绑定事件 hook
- 如:
插入 kprobe 到b.attach_kprobe(event="do_sys_open", fn_name="trace_entry")do_sys_open,绑定 eBPF 函数trace_entry
-
- 用户态读取数据
- 通过
map的lookup,read,poll等接口读取数据 - Perf Events 或 ring buffer 用于事件通知机制
例子
from bcc import BPF
bpf_text = """
int trace_sys_clone(void *ctx) {
bpf_trace_printk("clone called\\n");
return 0;
}
"""
b = BPF(text=bpf_text)
b.attach_kprobe(event="__x64_sys_clone", fn_name="trace_sys_clone")
b.trace_print()
执行逻辑:
- bpf_text 是 eBPF C 程序。
- 被 Clang 编译为字节码。
- b.attach_kprobe() 加载字节码并附加到内核的 __x64_sys_clone。
- 每当 clone() 被调用,内核执行 BPF 程序并通过 bpf_trace_printk() 输出消息。
- 用户态 b.trace_print() 监听并打印日志。
BCC 与其它 eBPF 工具的比较
| 特性 | BCC | libbpf + BPF CO-RE | bpftrace |
|---|---|---|---|
| 语言 | Python / C++ | C | 类似 AWK 脚本 |
| 依赖 | LLVM、Python | 无 Python 依赖 | LLVM |
| 编译时依赖内核头 | 是 | 可选择 CO-RE 方式 | 是 |
| 易用性 | 高 | 中 | 最高 |
| 可移植性 | 中 | 高 | 中 |
BCC 原理优势与局限
优势:
- 编写复杂逻辑更容易(用 C)
- 用户态 Python 接口开发效率高
- 生态成熟、文档齐全
局限:
- 运行时需要 LLVM、Python 环境
- 对内核版本依赖性强(CO-RE 支持较弱)
- 较重,不适合生产嵌入式场景
总结
BCC 本质是:
将 eBPF 技术封装为可编程接口,使用户能方便地观察、分析、调试内核或用户程序行为。
它的核心是:
- 使用受限 C 编写内核动态 hook
- 用 LLVM 编译 BPF 字节码
- 借助内核 BPF VM 执行代码
- 使用 map 进行数据交换
1331

被折叠的 条评论
为什么被折叠?



