Linux eBPF解析


Linux eBPF解析

文章插图
 
今天,我们来了解下 linux 系统的革命性通用执行引擎-eBPF,之所以聊着玩意,因为它确实牛逼,作为一项底层技术,在现在的云原生生态领域中起着举足轻重的作用 。截至目前,业界使用范围最广的 K8S CNI 网络方案 Calico 已宣布支持 eBPF,而作为第一个实现了Kube-Proxy 所有功能的 K8S 网络方案——Cilium 也是基于 eBPF 技术 。因此,只有了解其底层机制,才能有助于更好、更易地融入容器生态中 。
作为一种颠覆性技术,eBPF 最早出现在 3.18 内核中,eBPF 新的设计针对现代硬件进行了优化,所以 eBPF 生成的指令集比旧的 BPF 解释器生成的机器码执行得更快 。扩展版本也增加了虚拟机中的寄存器数量,将原有的 2 个 32 位寄存器增加到 10 个 64 位寄存器 。由于寄存器数量和宽度的增加,开发人员可以使用函数参数自由交换更多的信息,编写更复杂的程序 。总之,这些改进使得 eBPF 版本的速度比原来的 BPF 提高了 4 倍 。
基于原本的想法,eBPF 实现的最初目标是优化处理网络过滤器的内部 BPF 指令集 。然而,作为 BPF 技术的转折点,eBPF 已经开始扩展至用户空间 。使得 eBPF 不再局限于网络栈,已经成为内核顶级的子系统 。eBPF 程序架构强调安全性和稳定性,看上去更像内核模块,但与内核模块不同,eBPF 程序不需要重新编译内核,并且可以确保 eBPF 程序运行完成,而不会造成系统的崩溃 。
具体参考如下示意图:
Linux eBPF解析

文章插图
 
eBPF 是一套通用执行引擎,提供了可基于系统或程序事件高效安全执行特定代码的通用能力,通用能力的使用者不再局限于内核开发者,除此之外,eBPF 可由执行字节码指令、存储对象和 Helper 帮助函数组成,字节码指令在内核执行前必须通过 BPF 验证器 Verfier 的验证,同时在启用 BPF JIT 模式的内核中,会直接将字节码指令转成内核可执行的本地指令运行 。
同时,eBPF 也逐渐在观测(跟踪、性能调优等)、安全和网络等领域发挥重要的角色 。Facebook、NetFlix 、CloudFlare 等知名互联网公司内部广泛采用基于 eBPF 技术的各种程序用于性能分析、问题排查、负载均衡、DDoS 攻击预防等等,据相关信息显示,在 Facebook 的机器上内置一系列基于 eBPF 的相关工具集 。
相对于系统的性能分析和观测,eBPF 技术在网络技术中的表现,更为抢眼,BPF 技术与 XDP(eXpress Data Path) 和 TC(Traffic Control) 组合可以实现功能更加强大的网络功能,更可为 SDN 软件定义网络提供基础支撑 。XDP 只作用与网络包的 Ingress 层面,BPF 钩子位于网络驱动中尽可能早的位置,无需进行原始包的复制就可以实现最佳的数据包处理性能,挂载的 BPF 程序是运行过滤的理想选择,可用于丢弃恶意或非预期的流量、进行 DDOS 攻击保护等场景;而 TC Ingress 比 XDP 技术处于更高层次的位置,BPF 程序在 L3 层之前运行,可以访问到与数据包相关的大部分元数据,是本地节点处理的理想的地方,可以用于流量监控或者 L3/L4 的端点策略控制,同时配合 TC egress 则可实现对于容器环境下更高维度和级别的网络结构 。关于 XDP 技术架构,可参考如下结构示意图:
Linux eBPF解析

文章插图
 
基于 Linux 系统生态体系,eBPF 有着得天独厚的优势,高效、生产安全且内核中内置,特别的可以在内核中完成数据分析聚合比如直方图,与将数据发送到用户空间分析聚合相比,能够节省大量的数据复制传递带来的 CPU 消耗 。在解析 eBPF 之前,首先,我们先看下BPF 架构示意图,具体如下所示:
Linux eBPF解析

文章插图
 
接下来基于上述架构图,我们可以清晰的看到,BPF 主要工作在内核层,其本质是类 Unix 系统上数据链路层的一种原始接口,提供原始链路层封包的收发 。BPF 在数据包过滤上引入了两大革新:
  • 全新的虚拟机 (VM) 设计模型,能够有效地工作在基于寄存器结构的 CPU 之上
  • 应用程序使用缓存只复制与过滤数据包相关的数据,不会复制数据包的所有信息 。这样可以最大程度地减少BPF 处理的数据量
基于这些巨大的改进,目前,几乎所有的 (类)Unix 系统都选择采用 BPF 作为网络数据包过滤技术,直到今天,许多 Unix 内核的派生系统中(包括 Linux 内核)仍基于此实现方式 。举个简单的示例,Linux 操作系统上的 Tcpdump 底层采用的就是 BPF 作为包过滤技术 。


推荐阅读