土法炼钢兴趣小组的算法知识备份

【eBPF 内核实现深度拆解】从验证器到 JIT,从 BTF 到调度器

文章导航

分类入口
kernelebpf
标签入口
#ebpf#bpf-verifier#bpf-jit#btf#co-re#libbpf#xdp#bpf-maps#sched-ext#fentry#trampoline#linux-kernel

目录

eBPF 内核实现深度拆解

2014 年 Alexei Starovoitov 把 cBPF 重写为 eBPF 合入 Linux 3.18,此后十年间,eBPF 从”包过滤虚拟机的升级版”演变为 Linux 内核的通用可编程平面——覆盖网络(XDP / TC / sockmap)、追踪(kprobe / tracepoint / fentry)、安全(LSM BPF)、调度(sched_ext),以及存储、cgroup 等几乎所有内核子系统。

中文互联网不缺”用 bpftrace 一行查慢请求”的实践教程——本站的 eBPF 系列Linux 网络可观测性 系列中已有大量应用级覆盖。但缺一份把 eBPF 内核实现讲透的系统性资料:验证器为什么拒绝你的程序?JIT 编译器如何把 BPF 字节码翻译成 x86-64 本地指令?BTF 的类型信息如何驱动 CO-RE 重定位?sched_ext 的内核接口怎么设计才能让 BPF 程序安全地参与调度决策?

本系列填补这个空白。从 BPF 指令集编码到 verifier 的抽象解释算法,从 Map 数据结构的内核实现到 libbpf 的加载器工程,逐层拆解 eBPF 成为”内核第二用户态”的机制基础。

定位声明:本系列是 eBPF 的内核实现剖析,不是应用教程。如果你想学”怎么用 bpftrace 排查问题”,请从 eBPF 系列 的 01 篇开始。如果你已经会写 BPF 程序,但想理解 verifier 为什么拒绝你、JIT 在做什么、CO-RE 怎么做到一次编译到处运行——这是为你写的。

推荐入口

一、这个系列要回答的五个问题

  1. 验证器(verifier)到底做了什么?它的”安全”边界在哪里? verifier 不是黑盒——它通过抽象解释(abstract interpretation)跟踪每一个寄存器的类型和值域,用状态裁剪(state pruning)控制搜索空间,用等价状态合并(precision tracking)避免路径爆炸。理解 verifier 的内部算法,才能写出被它接受的程序,而不是猜测”加了 if 为什么还报错”。详见第一部分(第 02–04 篇)。

  2. eBPF 的 JIT 编译比内核模块的 AOT 编译差在哪?典型场景下 JIT 相对解释器能快多少? BPF JIT 编译器把 BPF 字节码翻译成本地指令,但翻译质量受限于 BPF ISA 的表达力——BPF 没有浮点、没有向量指令、寄存器数量固定、调用约定与 ABI 不直接映射。不同后端(x86-64 / ARM64 / RISC-V)的优化策略差异巨大;具体倍率取决于程序形态,需在本机 benchmark 验证。详见第一部分(第 05 篇)。

  3. BPF Map 不是简单的 key-value store——每种类型的并发模型、内存布局和扩展行为完全不同,应该怎么选? hash map 的 per-CPU 预分配、array map 的零拷贝共享、ring buffer 的 mmap 双缓冲、bloom filter 的概率位图——每种 map 类型背后是不同的数据结构和并发策略。选错 map 类型在典型高并发场景下可能带来显著性能退化(具体幅度依 workload 而定)。详见第二部分(第 06–08 篇)。

  4. CO-RE(Compile Once – Run Everywhere)不是魔法——它依赖 BTF 格式规范、clang 的 preserve_access_index 内置函数、以及 libbpf 在加载时执行的重定位修补。这套链路的每一环怎么工作?什么情况下会失效? BTF 提供了类型和布局的完整元数据,CO-RE 重定位在加载时用 BTF 信息修补指令中的偏移量。但内核的 field offset 变化、类型改名、结构体重排等都会影响 CO-RE 的适用范围。详见第三部分(第 11–13 篇)。

  5. sched_ext 是 eBPF 进入调度器的一次范式实验——它暴露了什么内核接口?BPF 调度器能否替代 CFS/EEVDF? sched_ext 把调度策略从内核的编译期决定变成运行时可编程——但它不是”随便写个 BPF 就能调度”。sched_ext 的 struct_ops 回调接口、调度类注册、CPU 独占、与 CFS 的共存策略,都需要系统理解。详见第四部分(第 18 篇)。

二、篇目依赖关系与推荐阅读路径

本系列共四部分、21 篇。每篇按「机制→源码→验证→边界」组织,源码以 Linux 6.6/6.8 LTS 为主线(verifier/JIT 等多用 6.6,map/helper 等多用 6.8),涉及最新特性时标注最低内核版本。

强依赖图

flowchart TD
  A["01 BPF 指令集与寄存器机器"] --> B["02 Verifier 框架:从 prog_load 到 do_check"]
  B --> C["03 Verifier 核心算法:抽象解释与状态裁剪"]
  B --> D["04 与验证器共舞:生产级 BPF 程序的写法约束"]
  A --> E["05 JIT 编译器后端:x86-64 / ARM64"]
  E --> F["06 Map 内核实现(上):hash / array / per-CPU"]
  F --> G["07 Map 内核实现(下):ringbuf / bloom / queue-stack / LPM"]
  G --> H["08 Helper 函数子系统:注册、类型检查与参数传递"]
  H --> I["09 程序生命周期:load / attach / detach / pin / refcount"]
  
  I --> J["10 libbpf 加载器工程:skeleton / auto-attach / map pinning"]
  J --> K["11 BTF 格式规范与内核类型系统"]
  K --> L["12 CO-RE 重定位引擎:libbpf 的运行时指令修补"]
  L --> M["13 BPF 编译工具链:clang 后端 / 目标文件布局 / 调试信息"]
  M --> N["14 BPF 程序调试与测试:verifier log / bpftool / test runner"]
  
  I --> O["15 蹦床(Trampoline)与 fentry / fexit:零开销内核追踪"]
  O --> P["16 BPF 并发模型:spinlock / RCU / per-CPU 模式"]
  P --> Q["17 eBPF 安全模型:capabilities / hardening / Spectre 缓解"]
  Q --> R["18 sched_ext 深度:用 BPF 写内核调度器"]
  
  R --> S["19 非 Linux eBPF:Windows eBPF、ubpf / rbpf 用户态运行时"]
  S --> T["20 实战:构建微型 eBPF 可观测 Agent"]
  T --> U["21 eBPF 生态与未来:标准化、社区动态、内核演进路线"]

推荐阅读路径

三、目录与每篇一句话价值

第一部分:eBPF 虚拟机核心

第二部分:eBPF 运行时机制

第三部分:编译、加载与可移植基础设施

第四部分:高级主题与前沿

四、读者定位与先修要求

维度 说明
主要读者 Linux 内核工程师、基础设施平台工程师、高性能网络/安全工程师、eBPF 工具链开发者
次要读者 对内核机制有深入兴趣的后端/SRE 工程师,已有 BPF 程序编写经验想深入理解原理的开发者
先修知识 熟悉 C 语言、基本数据结构与算法;了解 Linux 内核基础(syscall / 进程 / 内存 / 网络包收发路径);有 eBPF 基础概念(verifier / map / hook)更佳,非必须——本篇 01 从 BPF ISA 从头讲起

五、与其他系列的关联

本系列是 eBPF 的内核实现剖析,与以下已有的应用级内容互补:

已有系列/文章 与本系列关系
eBPF 系列(7 篇实战) 已有系列是 eBPF 应用大全(bpftrace / XDP / Cilium / 安全 / profiling),本系列是这些应用的内部实现
Linux 网络(XDP / eBPF hooks / netfilter) 已有系列的第 21–22 篇是 XDP 与 eBPF 网络钩子的源码解析,本系列的 Map / helper / verifier 部分是其底层依赖
操作系统百科(eBPF 核心 / RCU / 并发) 已有系列第 89 篇已对 eBPF 做概览,第 67 篇做了 RCU 深度拆解——本系列的 Map 并发模型和 verifier 部分是这些内容的延伸
可观测性(eBPF 观测全景) 已有系列第 14 篇覆盖了 bcc / bpftrace / libbpf 的应用路径,本系列的编译工具链和 CO-RE 部分是其底层基础设施
K8s 网络(Cilium / CNI) 已有系列覆盖 Cilium 的架构与应用,本系列的 Map(sockmap / devmap)和网络 hook 是其数据面基础

六、阅读建议

  1. 已在生产中使用 eBPF(Cilium / Pixie / DeepFlow):直接从第二部分(Map 实现)和第三部分(CO-RE)切入,理解你的工具在底层做了什么。
  2. 正在写 BPF 程序但被 verifier 折磨:先读 01 → 02 → 03 → 04,再跳到 14 学调试。
  3. 内核新手想系统性学 eBPF:按 01 → 02 → 05 → 06 → 09 → 10 → 13 → 20 的顺序,覆盖从 ISA 到实战的全路径。
  4. 追赶 eBPF 前沿(调度 / 安全 / 跨平台):先扫 01–04 理解核心约束,再跳到 15–19 + 21。
  5. 已有 eBPF 系列文章(eBPF 系列)的读者想深入:按 02 → 03 → 06 → 07 → 11 → 12 → 14 补足底层知识。

七、写作方法与证据策略

八、承诺与不承诺

承诺

不承诺

参考(写作时使用与遵循的核心资料)

内核源码(A 级)

规范与标准(A 级)

论文与关键文章(A/B 级)

社区项目(B 级)

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-12 · kernel / ebpf

【eBPF 内核实现深度拆解】BTF 格式规范与内核类型系统

从 BTF 的二进制编码格式(btf_header + type entries + string table)出发,讲清 BTF 如何编码基本类型、结构体、联合体、函数原型与 typedef——BTF.ext 节的 func_info/line_info 记录,以及内核 pahole 的 BTF 生成与去重算法 btf_dedup。

2026-06-12 · kernel / ebpf

【eBPF 内核实现深度拆解】实战:构建微型 eBPF 可观测 Agent

把 01--17 的知识串成一条实践线——从 libbpf skeleton 写第一个 BPF 程序、加载到内核、用 ring buffer 回传事件、用 CO-RE 实现跨内核版本兼容、map pinning 实现热升级、配上半自动化的 verifier 错误排障流程——构建一个麻雀虽小五脏俱全的 eBPF 可观测 Agent。


By .