聊聊最近很火的eBPF

若是非要说当前计算机领域最有前途的两个基础软件技术,那非eBPF和wasm莫属了。前端

什么是eBPF?

Linux内核一直是实现监视/可观察性,网络和安全性的理想场所。不幸的是,这一般是不切实际的,由于它须要更改内核源代码或加载内核模块,并致使彼此堆叠的抽象层。 eBPF是一项革命性的技术,能够在Linux内核中运行沙盒程序,而无需更改内核源代码或加载内核模块。经过使Linux内核可编程,基础架构软件能够利用现有的层,从而使它们更加智能和功能丰富,而无需继续为系统增长额外的复杂性层。ios

eBPF致使了网络,安全性,应用程序配置/跟踪和性能故障排除等领域的新一代工具的开发,这些工具再也不依赖现有的内核功能,而是在不影响执行效率或安全性的状况下主动从新编程运行时行为。git

若是直接解释eBPF,有点不明因此。那咱们就看看有哪些基于eBPF的工程,这些工程或许你已经知道,或是已经常用,也许你会明白eBPF距离咱们并不遥远。github

基于eBPF的项目

1:bcc编程

BCC是用于建立基于eBPF的高效内核跟踪和操做程序的工具包,其中包括一些有用的命令行工具和示例。 BCC简化了用C进行内核检测的eBPF程序的编写,包括LLVM的包装器以及Python和Lua的前端。它还提供了用于直接集成到应用程序中的高级库。后端

2:bpftrace数组

bpftrace是Linux eBPF的高级跟踪语言。它的语言受awk和C以及DTrace和SystemTap等之前的跟踪程序的启发。 bpftrace使用LLVM做为后端将脚本编译为eBPF字节码,并利用BCC做为与Linux eBPF子系统以及现有Linux跟踪功能和链接点进行交互的库。安全

3:Cilium网络

Cilium是一个开源项目,提供基于eBPF的联网,安全性和可观察性。它是从头开始专门设计的,旨在将eBPF的优点带入Kubernetes的世界,并知足容器工做负载的新可伸缩性,安全性和可见性要求。架构

4:Falco

Falco是一种行为活动监视器,旨在检测应用程序中的异常活动。 Falco在eBPF的帮助下审核Linux内核层的系统。它使用其余输入流(例如容器运行时度量标准和Kubernetes度量标准)丰富了收集的数据,并容许连续监视和检测容器,应用程序,主机和网络活动。

5:Katran

Katran是一个C ++库和eBPF程序,用于构建高性能的第4层负载平衡转发平面。 Katran利用Linux内核中的XDP基础结构来提供用于快速数据包处理的内核功能。它的性能与NIC接收队列的数量成线性比例,而且使用RSS友好的封装转发到L7负载平衡器。

6:Sysdig

Sysdig是提供深层系统可见性的简单工具,并具备对容器的原生支持。

其余基于eBPF技术的项目还有不少,好比kubectl-traceply 等,这里再也不赘述。

如何编写一个eBPF程序?

在不少状况下,不是直接使用eBPF,而是经过Cilium,bcc或bpftrace等项目间接使用eBPF,这些项目在eBPF之上提供了抽象,而且不须要直接编写程序,而是提供了指定基于意图的定义的功能,而后使用eBPF实施。

若是不存在更高级别的抽象,则须要直接编写程序。 Linux内核但愿eBPF程序以字节码的形式加载。虽然固然能够直接编写字节码,但更常见的开发实践是利用LLVM之类的编译器套件将伪C代码编译为eBPF字节码。

在编写eBPF程序以前,须要简单了解几个概念。

1)map(映射) :BPF最使人着迷的方面之一是,内核上运行的代码和加载了该代码的程序能够在运行时使用消息传递相互通讯。

BPF映射是驻留在内核中的键/值存储。任何BPF程序均可以访问它们。在用户态中运行的程序也可使用文件描述符访问这些映射。只要事先正确指定数据大小,就能够在映射中存储任何类型的数据。内核将键和值视为二进制 blobs,它并不关心您在映射中保留的内容。

BPF验证程序包括多种保护措施,以确保您建立和访问映射的方式是安全的。当咱们解释如何访问这些映射中的数据时,咱们也将解释这些保护措施。

固然BPF映射类型有不少,好比哈希表映射,数组映射,Cgroup 数组映射等,分别知足不一样的场景。

2)验证器

BPF验证程序也是在您的系统上运行的程序,所以,对其进行严格审查是确保其正确执行工做的目标。

验证程序执行的第一项检查是对VM即将加载的代码的静态分析。第一次检查的目的是确保程序有预期的结果。为此,验证程序将使用代码建立有向循环图(DAG)。验证程序分析的每一个指令将成为图中的一个节点,而且每一个节点都连接到下一条指令。验证程序生成此图后,它将执行深度优先搜索(DFS),以确保程序完成而且代码不包含危险路径。这意味着它将遍历图的每一个分支,一直到分支的底部,以确保没有递归循环。

这些是验证器在第一次检查期间可能拒绝您的代码的情形,要求有如下几个方面:

  • 该程序不包含控制循环。为确保程序不会陷入无限循环,验证程序会拒绝任何类型的控制循环。已经提出了在BPF程序中容许循环的建议,可是截至撰写本文时,没有一个被采用。
  • 该程序不会尝试执行超过内核容许的最大指令数的指令。此时,可执行的最大指令数为4,096。此限制是为了防止BPF永远运行。在第3章,咱们讨论如何嵌套不一样的BPF程序,以安全的方式解决此限制。
  • 该程序不包含任何没法访问的指令,例如从未执行过的条件或功能。这样能够防止在VM中加载无效代码,这也会延迟BPF程序的终止。
  • 该程序不会尝试越界。

验证者执行的第二项检查是BPF程序的空运行。这意味着验证者将尝试分析程序将要执行的每条指令,以确保它不会执行任何无效的指令。此执行还将检查全部内存指针是否均已正确访问和取消引用。最后,空运行向验证程序通知程序中的控制流,以确保不管程序采用哪一个控制路径,它都会到达BPF_EXIT指令。为此,验证程序会跟踪堆栈中全部访问过的分支路径,并在采用新路径以前对其进行评估,以确保它不会屡次访问特定路径。通过这两项检查后,验证者认为程序能够安全执行。

3) hook : 因为eBPF是事件驱动的,因此ebpf是做用于具体的hook的。根据不一样的做用,经常使用的有XDP,trace,套接字等。

4)帮助函数:eBPF程序没法调用任意内核功能。容许这样作会将eBPF程序绑定到特定的内核版本,并使程序的兼容性复杂化。取而代之的是,eBPF程序能够调用帮助函数,该函数是内核提供的众所周知且稳定的API。

总结

安全,网络,负载均衡,故障分析,追踪等领域都是eBPF的主战场。

对于云原生领域,Cilium 已经使用eBPF 实现了无kube-proxy的容器网络。利用eBPF解决iptables带来的性能问题。

整个eBPF生态发展比较好,社区已经提供了诸多工具方便你们编写本身的eBPF程序。

相关文章
相关标签/搜索