在上篇文章 eBPF初见(入门篇)我们介绍了eBPF的发展历程和强大的能力,同时也介绍了在内核中的运行时组件,以及为用户空间提供的系统调用bpf API,这些细节能够帮助更好的理解eBPF程序的运行机制,但在实际使用时有一定难度,本篇将介绍eBPF的生态,了解有哪些可以帮助我们以更简单的方式使用eBPF,以及有哪些热门开源项目。 下面我们将从开发、工具、应用等多个方面介绍相关生态:开发 编译器 由于 eBPF 程序被设计为在用 C 编写的 Linux 内核中运行,因此 eBPF 定义了与两种最常用的架构 x64 和 arm64 兼容的指令集(并考虑了其他架构的重要怪癖),并定义了与这些架构上 Linux 内核的 C 调用约定兼容的调用约定。 LLVM和GCC支持将C/C++代码编译为eBPF字节码,目前LLVM的支持最好。 原生Linux系统调用接口和内核函数 用户态 根据上一篇的介绍已经了解到eBPF程序的开发是分为用户空间和内核空间两部分,不同空间中需要实现的功能和能够使用的能力是不一样的。 在用户态,linux提供了有且只有一个系统调用bpf API,根据参数不同主要提供加载编译好的eBPF字节码以及访问eBPF maps。#includeint bpf(int cmd, union bpf_attr *attr, unsigned int size); cmd(目前有37种) 功能描述 BPF_MAP_* maps CRUD遍历等操作 BPF_PROG_ATTACH/DETACH 附加或接触某个数据源 BPF_LINK_* LINK相关操作 BPF_BTF_* BTF相关操作 BPF_OBJ_* 对象相关操作 BPF_PROG_LOAD 验证并加载BPF程序 每个调用的返回都是一个文件描述符(可以代表maps或者某个eBPF程序),可以基于这个文件描述符修改一些属性(比如附加eBPF程序到特定事件源)。 以上eBPF maps的CRUD和遍历,操作都比较简单,不过需要注意应该区分不同的maps 类型,这里不展开讲,具体参考上一篇的eBPF maps部分。 最重要的就是验证并加载eBPF程序BPF_PROG_LOAD这个操作,不同的eBPF程序是分类型的,类型信息需要在第二个参数*attr中明确给出。 通过以上系统调用和不同参数,可以在用户态与内核交互,实现eBPF程序加载和maps操作。 内核态 不同类型的eBPF决定内核中可用的辅助函数集和被调用时的输入信息。通常eBPF分为跟踪类和网络类,跟踪类的eBPF程序能用的辅助函数集与网络类eBPF的函数集差异很大,跟踪类eBPF程序的输入信息通常是内核中已有的注册值,而网络类的输入信息是网络包数据。 在内核中,eBPF程序可以使用受限的C语言(不支持循环、全局变量、浮点数、函数参数等),配合内核提供的辅助函数和映射(maps)来实现较复杂的执行逻辑,而且使用JIT编译(kernel 4.15开始默认开启),在内核中执行效率很高。 不同类型的eBPF的内核辅助函数还是很多的,具体开发时需要查阅具体的清单(https://www.man7.org/linux/man-pages/man7/bpf-helpers.7.html)。# bpftool feautre # 可以列出所有eBPF maps和程序的类型,以及每个不同类型的辅助函数列表 libbpf 直接基于系统调用和内核函数开发是可行的,但现实总会遇到一些与逻辑无关的细节问题,如需要考虑不同内核版本细微变化的兼容性、总是编写类似的代码、缓存、错误处理等,同时需要兼顾内核的变化和追求代码的通用性、可移植性,为了克服这些问题通常会抽象出一层常用的函数库,于是libbpf就诞生了,类似libc库的作用,目前libbpf已经是内核的一部分。 libbpf提了以下更好的能力:封装并简化使用bpf系统调用的能力和数据结构提供一致的错误处理提供额外的扩展的辅助函数联合多个系统调用实现更高的服务能力内核版本兼容支持编译一次到处运行能力 具体API参考:https://libbpf.readthedocs.io/en/latest/api.html BCC BCC(eBPF compiler collection)是最早用于开发eBFP跟踪程序的高级框架,不仅提供了基于C语言开发eBPF程序的开发环境,还同时提供了Python、Lua、C++来实现用户态接口,是libbcc和libbpf的前身,最开始添加到Linux 3.15中,目前大部分内容都需要 Linux 4.1 及更高版本。 BCC还自带了70多种已经写好的可以直接使用的eBPF工具,可以用来支持性能分析和排障工作。 bpftrace bpftrace是由Alastair Robertson创建的一个新的开发工具,提供了专门用于创建eBPF工具的高级语言支持,在最近的 Linux 内核 (4.x) 中可用。bpftrace使用LLVM作为后端将脚本编译为eBPF 字节码,并利用 BCC与Linux BPF系统以及现有的Linux跟踪功能进行交互:内核动态跟踪 (kprobes)、用户级动态跟踪 (uprobes) 和跟踪点。bpftrace 语言的灵感来自 awk 和 C 以及 DTrace 和 SystemTap 等前身跟踪器。 BCC、bpftrace和libbpf的关系如下,libbpf作为ebpf的函数库,BCC和bpftrace基于libbpf实现了自己的一些工具和高级自定义语法,简化eBPF的使用难度。 bcc、bpftrace与libbpf的关系 从目前的趋势看,BCC这个项目实现了大量好用的工具,但其实现方式比较臃肿,且兼容性不太好,会逐步被bpftrace+libbpf取代,目前已经有大量的BCC工具用bpftrace重构。 在5.15 kernel中被bpftrace重构的bcc工具 还有一些其他语言的eBPF开发库:golang:ebpf-go(cilium项目维护)、 goebpf、libbpfgorust:libbpf-rs、redbpf、ayaeBPF衍生引擎 ply — 一个简化版的bpftrace ply是一个用于嵌入式Linux的轻量化eBPF前端工具,适用于 Linux 的轻量级动态跟踪器。它利用内核的 eBPF VM 与 kprobes 和跟踪点配合使用,将探测器附加到内核中的任意点。大多数生成 BPF 字节码的跟踪器都基于基于 LLVM 的 BCC 工具链。另一方面,除了libc之外,Ply没有必需的外部依赖项。 ubpf ubpf项目旨在创建一个 Apache 许可的库来执行 eBPF 程序。eBPF的主要实现存在于Linux内核中,但由于其GPL许可证,它不能在许多项目中使用。 该项目包括 eBPF 汇编器、反汇编器、解释器(适用于所有平台)和 JIT 编译器(适用于 x86-64 和 Arm64 目标)。 eBPF for Windows eBPF for Windows项目是一个正在进行的工作,它允许使用eBPF生态系统中熟悉的现有eBPF工具链和API在Windows之上使用。也就是说,该项目将现有的 eBPF 项目作为子模块,并在两者之间添加层以使它们在 Windows 上运行。 hBPF – eBPF in hardware hBPF设计为在FPGA硬件中实现的扩展Berkley Packet Filter CPU。与Verilog或VHDL等经典HDL语言相比,Migen/LiteX(均基于Python)使用。支持"调用"操作码的自定义扩展,并为包含的仿真器和模拟器以及包含的硬件目标的每个操作码提供完整的测试套件。 XDP eXpress 数据路径 (XDP) 是一个框架,可以在 BPF 应用程序中执行高速数据包处理。为了更快地响应网络操作,XDP 会尽快运行 BPF 程序,通常在网络接口收到数据包后立即运行。应用 kubectl-trace kubectl trace 是一个 kubectl 插件,它允许您在 Kubernetes 集群中调度 bpftrace 程序的执行,可以用于在kubernetes中临时运行eBPF排查问题。 kubectl trace支持node、pod、container三种维度的观测,可以自动识别k8s集群中对应node或者pod所在node,然后自动部署bpftrace程序进行trace。 trace node trace pod Cilium Cilium 是一个开源项目,提供 eBPF 驱动的网络、安全性和可观察性。它是从头开始专门设计的,旨在将 eBPF 的优势带到 Kubernetes 领域,并满足容器工作负载的新可扩展性、安全性和可见性要求。 Cilium为Kubernetes网络提供了极致的性能优化体验,后续有机会会重点解析一下。 Hubble Hubble是一个完全分布式的网络和安全可观测性平台,适用于云原生工作负载。它建立在Cilium和eBPF之上,能够以完全透明的方式深入了解服务的通信和行为以及网络基础设施。 Tetragon Cilium 的新 Tetragon 组件支持强大的实时、基于 eBPF 的安全可观测性和运行时实施。 Tetragon 检测并能够对安全重大事件做出反应,例如流程执行事件系统调用活动I/O 活动,包括网络和文件访问 当在 Kubernetes 环境中使用时,它能理解 Kubernetes 身份,如命名空间、pod 等——因此可以根据单个工作负载配置安全事件检测。 Falco Falco是一种行为活动监测器,旨在检测应用程序中的异常活动。Falco在eBPF的帮助下在Linux内核层审计系统。它使用其他输入流(如容器运行时指标和 Kubernetes 指标)丰富收集的数据,并允许持续监控和检测容器、应用程序、主机和网络活动。 Katran Katran 是一个C++库和 eBPF 程序,用于构建高性能的第 4 层负载平衡转发平面。Katran 利用 Linux 内核中的 XDP 基础架构为快速数据包处理提供内核内设施。其性能与 NIC 的接收队列数量呈线性关系,并使用 RSS 友好封装转发到 L7 负载均衡器。 KubeArmor KubeArmor 是一个容器感知运行时安全强制系统,它使用 LSM 和 eBPF 在系统级别限制容器的行为(例如进程执行、文件访问、网络操作和资源利用率)。 Pixie Pixie 是一个用于 Kubernetes 应用程序的开源可观测性工具。Pixie 使用 eBPF 自动捕获遥测数据,无需手动检测。开发人员可以使用 Pixie 查看其集群的高级状态(服务映射、集群资源、应用程序流量),还可以向下钻取到更详细的视图(pod 状态、火焰图、单个全身应用程序请求)。 Tracee Tracee 使用 eBPF 技术来检测和筛选操作系统事件,帮助您公开安全见解、检测可疑行为并捕获取证指标。 DeepFlow DeepFlow 是 云杉网络 (opens new window)开源的一款 高度自动化 的可观测性平台,是为云原生应用开发者建设可观测性能力而量身打造的全栈、全链路、高性能数据引擎。DeepFlow 使用 eBPF、WASM、OpenTelemetry 等新技术,创新的实现了 AutoTracing、AutoMetrics、AutoTagging、SmartEncoding 等核心机制,帮助开发者提升埋点插码的自动化水平,降低可观测性平台的运维复杂度。利用 DeepFlow 的可编程能力和开放接口,开发者可以快速将其融入到自己的可观测性技术栈中。 Github start统计 这里简单统计今天各个项目在github start的数量以反应各个项目的活跃度: 项目 start count kubectl-trace 1.7k Katran 3.9k Cilium 13.6k Hubble 2.3k Tetragon 1.9k KubeArmor 526
Falco 5.4k Pixie 4k Tracee 2.3k DeepFlow 458
其中Cilium、Hubble、Tetragon都隶属于cilium项目,一起提供在云环境下的基于 eBPF 的网络、可观测性和安全性,覆盖了其他各个项目的能力,是一个非常值得关注的组合。 参考 https://github.com/iovisor/bpf-docs/blob/master/eBPF.md https://www.man7.org/linux/man-pages/man2/bpf.2.html https://www.man7.org/linux/man-pages/man7/bpf-helpers.7.html https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L840 https://libbpf.readthedocs.io/en/latest/api.html https://github.com/libbpf/libbpf https://ebpf.foundation/projects/ https://deepflow.yunshan.net/docs/about/architecture/ https://github.com/cilium