Overview Link to heading
eBPF(扩展伯克利包过滤器)是一项起源于 Linux 内核的革命性技术,它能够在操作系统内核等特权上下文中安全高效地运行沙盒程序。这项技术的主要目的是在无需修改内核源代码或加载内核模块的情况下,安全地扩展内核的功能。最初,计算机领域对网络数据包的捕获和过滤需求催生了伯克利包过滤器(BPF)的诞生。随着技术的发展,尤其是在 2014 年,Alexei Starovoitov 对 BPF 进行了重大扩展,使其能力远不止于网络数据包处理,由此开启了 eBPF 的时代。
eBPF 之所以被广泛认为是颠覆性技术,在于其诸多关键优势:
- 安全性: eBPF 程序运行在内核的沙盒环境中,这确保了它们无法导致系统崩溃、访问未经授权的内存区域或无限循环。内核中一个被称为“验证器”的组件会对所有加载的 eBPF 程序进行严格检查,以确保其安全性,这对于允许用户提供的代码在高度特权的内核级别运行至关重要。
- 效率与性能: eBPF 程序会被即时(Just-In-Time, JIT)编译成本地机器代码,从而实现接近原生代码的执行速度,并且与传统的用户空间监控工具或内核模块相比,开销极小。这种卓越的性能使得 eBPF 非常适合需要高速处理的任务,例如高性能网络和可观测性。
- 灵活性与动态内核编程: eBPF 允许开发者在无需重新编译内核或重启系统的情况下,动态地加载和卸载程序到内核中。这种灵活性极大地简化了部署过程,并使得在运行时扩展内核功能成为可能,从而加速了创新。
为了更好地理解 eBPF 的应用,我们需要了解其几个核心概念:
- eBPF 程序: 这些是用受限的 C 语言子集编写并编译成字节码的小型专用程序。
- 钩子(Hooks): 内核中预定义的事件触发点(例如,系统调用、网络事件、函数调用、跟踪点),eBPF 程序可以附加到这些点并在事件发生时被触发执行。
- 验证过程: 在加载到内核之前,eBPF 程序会经过严格的验证过程,以确保其安全性和防止对系统造成损害。
- eBPF映射(Maps): 这些是驻留在内核中的数据结构,用于在 eBPF 程序和用户空间应用程序之间共享信息和存储状态。eBPF 支持多种映射类型,如哈希表、数组和环形缓冲区。
- 辅助函数(Helper Functions): 内核提供的一组预定义函数,eBPF 程序可以调用这些函数以安全受控的方式与系统交互(例如,访问映射、操作网络数据包、获取进程上下文)。
- 尾调用与函数调用(Tail and Function Calls): 这些机制允许组合 eBPF 程序,使得一个程序可以调用另一个程序或替换当前的执行上下文。
从最初的网络过滤工具发展到如今通用的内核扩展机制,eBPF 代表了内核可编程性的重大转变,它使得在安全高效的前提下,扩展和定制 Linux 内核的功能成为可能,从而催生了广泛的应用场景。eBPF 对安全性的高度重视,通过严格的验证过程确保了用户提供的代码能够在特权的内核空间中安全运行,这与传统的内核模块形成了鲜明对比。此外,eBPF 结合了 JIT 编译和直接在内核中执行的特性,使其在性能上能够与内核模块媲美甚至在某些任务上超越后者,同时提供了更高的灵活性和安全性。
eBPF 在网络领域的应用 Link to heading
eBPF 在网络领域展现出强大的能力,其高效性和可编程性使其成为解决各种网络挑战的理想选择。
高性能包处理与过滤 Link to heading
eBPF 通过 XDP(eXpress Data Path)技术,实现了在网络数据包处理的早期阶段进行高性能处理与过滤。XDP 允许 eBPF 程序直接附加到网络接口卡(NIC)驱动程序,从而在数据包到达内核网络协议栈之前就对其进行处理。这种“内核旁路”的方法通过避免上下文切换、网络层处理和中断等操作,显著降低了开销。
XDP 的一个重要应用是 DDoS(分布式拒绝服务)攻击的缓解。通过监控每个源 IP 地址的传入数据包速率,XDP 程序可以快速识别并丢弃来自恶意 IP 地址的大量数据包,从而保护服务器免受过载。例如,一个 eBPF 程序可以设定一个阈值,当某个 IP 地址在一秒钟内发送的数据包数量超过该阈值时,就将其数据包丢弃。Cloudflare 等公司就利用 XDP 技术实现了实时的 DDoS 攻击防御。
除了 XDP,eBPF 还支持使用套接字过滤器(Socket Filters)进行应用程序特定的数据包过滤。套接字过滤器程序(BPF_PROG_TYPE_SOCKET_FILTER)可以附加到网络套接字,用于过滤或修改该套接字接收到的数据包。像 tcpdump
这样的工具就使用套接字过滤器来实现高效的数据包捕获。虽然套接字过滤器主要用于处理传入的数据包,但它们也可以在套接字层面提供可观测性和安全性。XDP 在 NIC 驱动层面运行,提供了更早期的包处理能力,而套接字过滤器则在更靠近应用程序的套接字层面工作,提供了更细粒度的控制。
流量控制与整形 Link to heading
Linux 的流量控制(Traffic Control, TC)子系统用于控制数据包的发送和接收,包括速率、顺序等方面。自 Linux 4.1 版本起,TC 开始支持加载 eBPF 程序作为过滤器,并可以在入口(ingress)和出口(egress)等多个挂载点进行操作。
eBPF 可以与 TC 结合使用,实现服务质量(Quality of Service, QoS)和流量整形。通过附加到 TC 的 eBPF 程序,可以对数据包进行分类,并应用诸如优先处理延迟敏感型流量(如 VoIP)等策略,而对不太重要的流量(如网页浏览)则降低优先级。eBPF 还可以用于模拟数据包丢失或增加延迟,以模拟远距离客户端的网络环境。
实际应用中,TC 与 eBPF 常用于限制带宽或进行数据包优先级排序。例如,在 Kubernetes 环境中,可以使用 cgroup 钩子和 TC 来限制容器的出口带宽。此外,eBPF 还可以用于在 Docker 容器内重定向 DNS 流量。tc-bpf
工具专门用于将 eBPF 程序附加到 TC,以实现数据包的分类和各种操作。与 XDP 侧重于早期数据包处理不同,TC 结合 eBPF 在更后期的阶段提供了更精细的流量管理能力,允许基于数据包分类制定复杂的 QoS 和流量整形策略。eBPF 与 TC 的集成还支持动态和可编程的流量控制策略,这些策略可以在不重启服务的情况下进行更新,为网络流量管理提供了极大的灵活性。
负载均衡 Link to heading
eBPF 的高效性和可编程性使其成为实现高性能四层负载均衡的理想选择。例如,Facebook 开源的 Katran 就是一个基于 XDP 和 eBPF 构建的高性能四层负载均衡器,能够每秒处理数百万个数据包。
eBPF 程序可以检查数据包的数据和元数据,以做出负载均衡的决策,然后使用诸如 XDP_TX(在同一接口上传输)或 XDP_REDIRECT(重定向到另一个接口)等动作将流量转发到后端服务器。eBPF 中的套接字查找钩子还允许基于 IP 或端口选择目标套接字来处理传入的网络数据包,从而提高了可伸缩性。通过在内核中直接执行数据包处理和转发决策,eBPF 实现了高效且可伸缩的负载均衡解决方案,最大限度地减少了延迟并提高了吞吐量。
容器网络 Link to heading
在现代容器网络解决方案中,eBPF 扮演着至关重要的角色,尤其是在像 Cilium 这样的项目中。Cilium 是一个开源项目,它大量依赖 eBPF 和 XDP 为容器(尤其是在 Kubernetes 环境中)提供快速的内核内网络、安全性和可观测性。Cilium 将数据包过滤和安全策略卸载到 XDP,从而在不牺牲可伸缩性的前提下实现了高吞吐量的流量管理。
eBPF 通过将程序附加到 cgroup 钩子,实现了对容器化环境的高效且安全的网络管理和安全策略执行。它还可以改进容器下层的负载均衡,并增强网络地址转换(NAT)中的网络性能。Cilium 使用 eBPF 实现基于主机的路由,绕过 iptables 和上层主机协议栈,从而加快了网络命名空间的切换速度。eBPF 已成为现代容器网络的核心技术,为管理复杂且动态的云原生环境(如 Kubernetes)提供了所需的性能、安全性和可观测性。