LWN: 实现针对Windows的eBPF!
关注了就能看到更多这么棒的文章哦~
Implementing eBPF for Windows
June 10, 2021
This article was contributed by Quentin Monnet
DeepL assisted translation
https://lwn.net/Articles/857215/
Extended BPF(eBPF)是 Linux 内核中的一个通用执行引擎(general-purpose execution engine),有助于追踪和监控系统行为、处理网络数据包、或者其他一些有助于扩展内核功能的行为。事实上,它是如此有用,以至于连其他操作系统上的开发者都在关注它。Dave Thaler 和 Poorna Gaddehosur,最近代表微软发表了一个 Windows 中的 eBPF 实现版本。一个 Linux 功能进入了 Windows,这本身就值得关注。尤其是该功能在过去几年中给 Linux 内核增加了新的编程可能性,这使得我们特别有兴趣看看这个新项目能做些什么,并思考当 eBPF 开始向 Windows 进军时,当前的生态系统会如何发展。
Gearing up with open-source components(开源组件的准备工作)
该项目直接命名为 "eBPF for Windows",希望用于 Windows 10 和 Windows Server 2016(及更高版本)。它不是从 Linux 代码直接 fork 出来的,可能是为了避免 GPL 相关担忧。因此 Windows 版本实际上是另一个不同的实现。不过并不是从头开始,而是依赖于已经存在的一些开源组件,然后增加了缺失的部分,以及必要的衔接逻辑以使这些组件相互配合并与 Windows 底层集成起来。它的代码在 GitHub 上以 Ebpf-for-windows 的名字提供了出来,采用的是 MIT 许可。
这些组件之一是 uBPF,这是一个独立的用户空间 eBPF 解释器以及 x86_64 版本的 eBPF 即时编译器(JIT,just-in-time)。在 2015 年,也就是 eBPF 初期,uBPF 作为该技术的一个非 GPL 实现被创造出来。在那之后它的开发进展很少。但还是有几个项目(包括 DPDK),重用了它的代码。Windows 项目则将 uBPF 作为一个 Git submodule,并直接用 #include 方式使用了它的代码来把解释器和 JIT 编译器嵌入进来。uBPF 只支持基本的 BPF program,ebpf-for-windows 增加的代码对其进行了扩展,例如实现 eBPF maps 以及相关的 helper 函数。
在 Windows 上处理 eBPF program 的相关工具对于 Linux 用户来说应该会感到很熟悉。Clang/LLVM 这些后端仍然被用来将 C 语言编写的代码编译为 eBPF 字节码指令。netsh 命令行工具提供了程序管理和内省(program management and introspection)在某种程度上类似于 bpftool,它依赖一个提供了与 libbpf 兼容 API 的共享库,从而确保 loader applications 可以移植。
该项目还使用的最后一个组成部分是 PREVAIL verifier,是另一个被拉入 ebpf-for-windows 项目中的 Git submodule。PREVAIL 是作为 VMware Research 参与的研究项目的一部分而开发的,在随附文档中有很好的介绍(注意,有些内容现在已经过时了)。与 Linux 的 verifier 不同,它依赖于形式化方法(formal method)来确定程序的安全性。它使用了一个抽象的解释层,在几个执行 stream 的 rejoin 之后来聚合状态,举例来说,if/else 块的不同分支的寄存器的状态在该块的最后被合并在一起,以避免产生太多的执行路径组合。
而 Linux verifier 则独立检查所有的路径:两个连续的 if/else 代码块会产生四条路径,从而迅速导致 "路径爆炸"。但 Linux 验证器会通过 "修剪(pruning)" 已知的安全路径的某些部分来缓解这个问题,假如这条路径已经完成并从另一个分支验证过了的话。
据称,PREVAIL 在识别有效程序方面比 Linux verifier 更好,也包括对带有循环语句的程序的处理。它还能更好地随着复杂性地增加来相应扩展(scale),并能验证一些 Linux 因为其超过 100 万个验证状态而导致无法验证的 program。然而,当 Linux verifier 收到一个 BPF program 时,它能更快地完成验证,而且消耗的内存也更少。而且它还经过精心定制以支持 BPF program 可以使用到的所有功能和 corner case 的,PREVAIL 则还缺乏对几种情况的检查,比如 eBPF-to-eBPF function call、数据包重新分配(当数据包的 size 改变时)、以及 32-bit subregister tracking。PREVAIL 还正在积极开发中,Thaler 目前在跟 PREVAIL 的创建者和维护者 Elazar Gershuni 一起在进行改进。他们打算共同来解决其中的一些缺陷,比如最近就支持了 eBPF program 的 termination(终止)的检查。
Taking marks(打分)
有了这些组件之后,eBPF for Windows 就具有了一个可以正常工作的 eBPF runtime。但该项目还处于起步阶段。目前只支持两个 eBPF hook,也就是 XDP(用于 fast packet processing)和 socket binding(相当于 Linux 中的 BPF_CGROUP_INET4_BIND 等相关挂载点)。它也实现了最基本的 map type:array 以及 hash maps。
代码仓库中也存储库包含一些例子。其中的 Getting Started guide 介绍了如何设置 XDP program 实现把不带有有效 payload 的 UDP 数据包丢弃从而保护 DNS 服务器免受 UDP flood 攻击。另一个示例程序是连接到 socket binding 相关的 hook 上,可以被配置为对进程可以 bind 的 socket 数量进行限制。该 program 会在 bind 和 unbind 操作过程中来对每个进程的 counter(存放在一个 map 中)进行加一或者减一操作。
Picking a direction
这些例子都很简单,不过这个项目也才刚刚开始。它的后续方向是什么?作者在他们的博文中明确表示,目标是能提供与 Linux eBPF 的良好兼容:"目的是为适用于各种操作系统生态的 common hooks 和 helper 函数的代码提供源代码兼容性。"
当然,一些现有 hook 和 helper 函数是与 Linux 底层代码紧密相关的。有些功能(如直接调用内核函数)也会是完全依赖于操作系统的。但是对于其他的功能,目标则是与 Linux 在某种程度上实现相同的功能,包括通过重用代码来实现跟踪 kernel 和 user-space 的函数,比如 Windows 的 Event Tracing 或 DTrace。而追踪(tracing)用户应用程序可能就跟 Linux 一样能支持 Windows 了。
关于 kernel tracing,毕竟 Linux 和 Windows 系统底层功能并不相同,但至少通过 eBPF,它们应该能够共享一个共同的工作流程来安装 probe。有趣的是,项目的作者已经有了一个新的 hook,是在 Windows 上用 eBPF 实现文件系统的 "mini-filters"。看来他们未来可能会增加更多的内容。在定义对内核进行 probing 的通用方法时,如果 eBPF 的工作流程、工具和 runtime 在所有系统上都具有相同的功能,从而构成该 "接口" 的核心部分,那么也许 program hok 本身最终就变成了一个实现细节而已。
目前,功能上的差异已经被作为 GitHub 上的一些 issue 而管理了起来。也还需要对不同组件的贡献和修改。作者已经将他们的一些改动推送到了 uBPF,并且已经为 PREVAIL 进行了几个月的修改。值得注意的是他们打算如何处理 map:他们希望重用 generic-ebpf 的代码,这是另一个基于 uBPF 的 runtime,主要是针对 FreeBSD。
来自微软的 Alan Jowett 将这个项目的动机总结为:"任何可以通用的代码都应该被移动到一个更通用的项目中,然后作为 sub-module 加入进来。" 这看起来表明一个方向,就是把一切可能的代码都上移到 uBPF、PREVAIL、以及未来可能的其他项目,以便只保留 ebpf-for-windows 中尽量少的支持代码,并且使通用组件可以被其他项目重用。
The road ahead
理想情况下,大多数 eBPF program 在 Linux 和 Windows 上的行为需要是一样的。要达到这一点则需要工程上的许多努力。通过重新实现一项现有的技术,微软节省了设计过程,但它将不得不补上许多具体功能。eBPF 不仅仅是一个简单的指令集:它带有许多 hook、map、helper、用户空间的操作、以及 tail calls、function calls、BPF type format(BTF)信息等等功能,其中的大部分在 uBPF 中都尚未支持。也许会在今后一段时间内获得支持,其中相当一部分应该是通用的,才能使得 eBPF 程序可以跨平台使用。为新架构添加 JIT 编译器不应该是一个大问题,DPDK 已经有了一个用于 arm64 的编译器。不过,任何依赖于内核 BTF 信息的功能都有可能是与特定操作系统绑定起来的。
verifier 的兼容性是另一个问题。在 Windows 实现方案的所有设计决策中,最有意思的一点是使用 PREVAIL,因为它比起 Linux 的方案来说已经有了某些优势。它可以接受更多的有效程序,并且受 path explosion 的影响较小,有利于性能和详尽性的检查。因此,一些程序可能只被 Linux 判定为可用的,而另一些则只在 Windows 上被判定为可用。这应该会激励我们改进 Linux verifier,使其在复杂的代码序列上能效率更高,也许也要让它能验收更多的 program。要想完全对等,肯定会有很多挑战等着我们。
人们可能会问,确保 eBPF 的跨操作系统兼容性很重要吗?首先,如果微软不能支持现有的 BPF program,那么它对该技术的兴趣可能就会变小。该公司也可以开发自己的解决方案,而不必费心去整合这些外部功能组件。可移植性对于避免生态系统分裂是很有必要的,并且更加有利于 Windows 上的采用。当 generic-ebpf 项目在曝光后得到更多关注以及开发贡献之后,就显得尤为重要了。这将能支持更多的系统,而且由于 libbpf 中正在引入静态链接(static linking),这也为创建 eBPF libraries 函数库铺平了道路。
然而,这些工作不能仅仅依靠微软。非常重要的是要与现有的 eBPF 社区保持同步,从而使这个技术能以所有系统都能支持的方式来发展。在 Linux 上,eBPF 已经在 Facebook、Google 和 Netflix 等大公司的生产系统中大规模地应用了一段时间了。在 Kubernetes 生态系统中,得益于 Cilium 等项目,它已经在网络、可观察性和安全性方面推广了更多应用场景。Linux 开发者不可能将 eBPF "搁置" 起来从而等待 Windows 赶上。Thaler 和 Gaddehosur 也知道这里需要大量的沟通工作:
我们现在宣布这个项目时,它还处于相对早期的开发阶段,因为我们的目标是与强大的 eBPF 社区合作,以确保 eBPF 在 Windows 和其他地方都能很好地工作。
该项目有一个专门的 Slack 频道,名为#ebpf-for-windows,位于在https://ebpf.io/slack 。至少在 7 月前会开始有定期会议来分发以及解决 GitHub 上的问题。随后会有一个专门的邮件列表。
Linux 开发者的参与程度对于这个项目将是决定性的,但目前还很难预测会有多大程度的参与热情。Windows 版 eBPF 也才刚刚宣布:社交网络上有一些评论(总体上很欢迎,也有一些提及了微软之前历史上出现过的 "拥抱、扩展并消灭" 做法),但目前在 Linux 世界里反响还是很小。
The journey is just starting
eBPF for Windows 项目是很有雄心的,但在这个早期阶段,它还缺乏许多在 Linux 上已经支持的功能,首先需要对于 program type、map type、helper 等方向达到跟 Linux 的同等支持程度,才能使其变得真正可行。这可以解释为什么 Linux 开发者现在还没有明显的反应了,他们可能在等着看这些实现最终是否能兑现承诺。为了证明它确实可以兑现,项目作者们需要抓紧追上开发进度,能支持 Windows 上更复杂的使用场景。如果他们想确保项目成功的话,还必须要吸引到更多微软以外的贡献者的兴趣和参与。
如果他们成功了,开发者最终可能会从 eBPF 组件中受益,这些组件会作为两个系统共同使用的库。用户空间的函数库、工具、应用程序、以及兼容性测试套件就都可以扩展到能支持在多种环境下运行。然后,eBPF 生态系统也将从来自 Windows 世界的这种另一个角度的思考中获益,而友好的竞争将有望驱动两边的性能改进。长期来说比较乐观的想法是,假设可以找到一个共同的基础来将两个系统中对等的 probe 统一表达出来,那么 eBPF 程序可能最终会成为某种形式的控制面(control-plane) API,用来管理不同类型节点上的网络和可观察性。这样的接口已经开始在云原生计算中出现,而支持多种不同环境的 eBPF 则在这种情况下会更有价值。
当然,在此之前还有很多事情需要完成,毕竟这个项目才刚刚开始。然而,就目前的情况来看,这已经是对当前 eBPF 给 Linux 带来的好处及未来潜在好处的一种强烈的认可。要想将这个潜力变为现实,很大程度上会取决于不同社区之间的对话和同步。eBPF 刚刚走出它的 Linux 家园,进入了全新的世界。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~