ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

eBPF 源码专题【左扬精讲】—— eBPF 概述:是什么、如何运行与发展历史

2026/8/11 22:07:43 拓冰建站 浏览量
eBPF 源码专题【左扬精讲】—— eBPF 概述:是什么、如何运行与发展历史

eBPF 源码专题【左扬精讲】—— eBPF 概述:是什么、如何运行与发展历史

本文讨论 eBPF(extended Berkeley Packet Filter)的基本概念、发展脉络、应用场景和运行流程。

eBPFBPFLinuxXDP可观测性网络安全

一、eBPF 是什么

eBPF 是 Linux 内核中的一种可编程机制:用户态程序准备 eBPF 指令,通过 bpf() 系统调用请求内核加载。

内核使用 verifier 对程序进行安全检查,验证通过后可以解释执行或经过 JIT(Just-In-Time)编译,再将程序挂载到特定的内核 hook 上。

“extended” 来自它相对于经典 BPF(cBPF)的能力扩展。经典 BPF 最初用于高效过滤网络数据包,eBPF 则逐渐支持网络、跟踪、性能分析、安全等非包过滤任务。

今天的 Linux 内核仍然保留 BPF 这一名称,但 eBPF 已经不应只理解为 packet filter。

核心心智模型
eBPF = 字节码 + verifier 安全检查 + 可选 JIT + hook 挂载点 + helper 与 map。它不是让用户态任意代码直接运行在内核中,而是让受约束的 eBPF 程序在内核提供的执行模型中工作。

二、发展历史:按用户指定年份梳理

年份可核实的代表性节点说明
1992 经典 BPF 提出 Steven McCanne 与 Van Jacobson 发表 Berkeley Packet Filter 相关论文,目标是让网络抓包工具在内核侧先过滤数据包,减少无关数据复制到用户态。
1997 BPF 进入 Linux 公开资料和相关演讲资料记载,BPF 在 Linux 2.1 系列进入内核,最初主要作为 socket filter 服务于 tcpdump/libpcap 等网络抓包场景。
2011 经典 BPF 的内核 JIT Linux 合入经典 BPF 的 in-kernel JIT 编译器,用本地机器码执行过滤程序,以改善性能。此时仍是经典 BPF,不应把它直接表述为 eBPF 的诞生。
2014 eBPF 架构进入 Linux 3.18 Linux 接受 BPF 解释器重构,内核内部引入 eBPF 指令表示,并开始把经典 BPF 转换到 eBPF 表示。eBPF 从网络过滤器向通用内核虚拟机演进。
2015 跟踪与网络挂载能力扩展;LLVM 后端合入 eBPF 支持 kprobe 等跟踪入口,tc 网络路径也开始成为重要挂载位置;LLVM 3.7 发布了 BPF 编译器后端。不同事件的具体合入时间应以对应 Linux/LLVM 提交记录为准。
2016 XDP 与 Cilium 项目出现 eBPF 可挂到网络驱动接收路径,形成后来称为 XDP(eXpress Data Path)的快速数据路径;Cilium 在 LinuxCon 期间公开,探索使用 eBPF/XDP 实现容器网络。
2017 成为独立的内核子系统 公开历史资料记载,eBPF 形成独立内核子系统,以应对不断增长的补丁、维护者和功能规模。
2018 本文未单独确认一个统一的里程碑 eBPF 生态持续演进,但本文不把某个项目发布、某个 helper 或某个特性未经一手资料核实后归为“2018 年官方节点”。
2019 BPF 书籍与生态持续成熟 Brendan Gregg 的《BPF Performance Tools》于 2019 年出版,推动性能工具知识传播。公开资料还记载 GCC 在 2019 年跟进 BPF 后端。
2020 BPF LSM 与 CO-RE 工具链继续成熟 公开资料记载,BPF LSM 支持在 Linux 内核中持续推进;同时 BTF、CO-RE 与 libbpf 逐渐成为跨内核版本开发的重要基础。本文将其表述为生态和内核能力的演进,不把单一项目的发布时间当作 eBPF 的唯一里程碑。
2021 eBPF Foundation 成立 eBPF Foundation 在 2021 年成立,目标是促进 eBPF 相关开源项目、社区协作和生态发展。这是社区组织层面的节点,不是 Linux 内核版本发布节点。
2022 libbpf 1.0 与 eBPF for Windows 公开资料记载,libbpf 在 2022 年达到 1.0 版本里程碑;微软也在 2022 年公开 eBPF for Windows 项目。后者是 Windows 平台的独立实现与项目生态,不能直接等同于 Linux 内核中的 eBPF 实现。
2023 开发体验与可移植性成为重点 公开技术资料将 BTF、CO-RE、libbpf 和 BPF skeleton 作为 eBPF 应用开发的重要基础。eBPF 的工程重点从“能否运行”进一步扩展到加载流程、跨内核版本适配和生产部署体验。
2024 eBPF 指令集规范化讨论推进 公开资料记载,eBPF Instruction Set Architecture 相关规范在 IETF 体系中推进并形成 RFC 文档。该类规范化工作描述的是指令集与生态互操作性,不代表所有 Linux 内核特性都已经由 IETF 定义。
2025 本文不指定未经一手资料确认的单一里程碑 eBPF 继续用于 Linux 网络、可观测性和安全生态;但本文当前资料没有足够可靠的一手来源,确认一个应归属于 2025 年且具有统一共识的单一历史事件,因此不强行编造具体版本、项目采用数量或性能数据。
2026 项目仍在持续演进 截至 2026 年本文生成时,libbpf 官方镜像资料显示项目仍有持续发布和维护活动,例如页面列出了 2026 年的版本发布记录。本文不据此推断整个 eBPF 生态的“最终状态”,也不把尚未核实的项目宣传内容写成事实。
历史边界
“2014 年 eBPF 进入 Linux 3.18”与“2011 年经典 BPF JIT”是两个不同节点;“1992 年 BPF 提出”也不等于 eBPF 在 1992 年已经存在。将这些年份混成一条“eBPF 从 1992 年开始”的表述,会掩盖经典 BPF 到 eBPF 的技术断层。

三、eBPF 的应用场景

3.1 网络与容器网络

在 XDP、tc、socket 等网络 hook 上,eBPF 可用于数据包过滤、重定向、负载均衡、流量统计和容器网络策略。Cilium 是公开生态中使用 eBPF 构建容器网络与网络安全能力的代表项目。

3.2 可观测性与性能分析

eBPF 可以挂接 kprobe、tracepoint、uprobe、perf event 等入口,采集系统调用、内核函数、用户态函数、调度和 I/O 等事件。BCC、bpftrace、libbpf 和 bpftool 是常见工具或库;实际可观测内容受内核版本、程序类型和权限约束。

3.3 运行时安全

eBPF 可用于系统调用与进程行为观测、网络策略、LSM(Linux Security Module)相关安全检查和运行时检测。安全程序仍要遵守 verifier、helper 权限和 Linux 能力控制,不能把 eBPF 误解为绕过内核安全边界的工具。

3.4 数据路径与内核扩展

当需求需要修改或观测内核行为,而直接修改内核源码、编写内核模块成本较高时,eBPF 提供了更细粒度的扩展路径。但可挂载的 hook、上下文、返回值语义和 helper 集合均由具体 program type 决定。

四、eBPF 如何运行

用户态源码(C/Rust 等)↓ 编译为 eBPF 字节码/ELF加载器(libbpf 等)调用 bpf() 系统调用↓内核 verifier:控制流、寄存器类型、指针边界、helper 合法性等检查↓ 验证通过解释器执行,或 JIT 编译为目标 CPU 的机器码↓ attachkprobe / tracepoint / XDP / tc / socket / LSM 等 hook 被触发↓eBPF 程序通过 helper 访问受限内核能力,通过 map/ring buffer 与用户态交换数据

4.1 编译与加载

开发者通常使用 Clang/LLVM 等工具把源代码编译为 eBPF 目标文件,再由用户态加载器解析 ELF、创建 map、加载 program 并完成 attach。CO-RE(Compile Once – Run Everywhere)依赖 BTF 等内核类型信息,目标是减少针对每个内核版本重新编译的需要;它不是“任何内核都无需检查即可运行”。

4.2 verifier 做什么

verifier 在程序执行前分析控制流和状态,检查内存访问是否可证明安全、helper 是否适用于当前 program type、寄存器类型是否满足约束,以及程序是否可能产生不可接受的执行行为。Linux 5.17 起,满足边界条件的 bounded loop 获得支持,因此“verifier 永远禁止循环”是过时说法。

4.3 JIT、helper 与 map

JIT 把 eBPF 指令翻译成目标架构机器码,以降低解释执行开销。eBPF 程序不能任意调用内核函数,而是通过当前上下文允许的 helper 与内核交互;map 是内核管理的数据对象,可用于在 eBPF 程序之间以及用户态与内核之间共享状态。具体 map 类型和 helper 能否使用,必须按内核版本与 program type 查证。

4.4 attach 后的事件路径

程序加载成功不代表它已经处理业务事件。只有 attach 到 hook 后,事件到达该 hook,内核才会按对应上下文调用程序。程序执行结果可能是返回一个动作码、更新 map、写入 ring buffer,或通过 perf event 等机制把事件送到用户态。

一段话总结
经典 BPF 解决了高效网络包过滤;eBPF 在此基础上成为 Linux 内核中的受约束可编程执行平台。它通过 verifier 保证可接受的安全边界,通过 JIT 提升执行效率,通过 hook 接入内核事件,通过 helper 和 map 完成受控交互,因此能同时服务于网络、可观测性和安全场景。

五、使用 eBPF 时需要注意什么

  • 不要用某个发行版的现象替代 Linux 内核通用事实;program type、helper、BTF 和权限都可能受版本影响。
  • 不要把“JIT 后接近本地代码”写成“零开销”;加载、验证、attach、数据采集和用户态消费都可能产生成本。
  • 不要把 verifier 描述成完整的安全证明;它是内核加载阶段的约束检查,仍需要权限控制、资源限制和程序审计。
  • 需要确认具体能力时,应查对应内核版本的 Documentation/bpf/man 7 bpf、libbpf 文档和项目官方资料。