Red Hat Training

A Red Hat training course is available for RHEL 8

第 44 章 了解 RHEL 8 中的 eBPF 网络功能

扩展的 Berkeley Packet 过滤器(eBPF)是一个内核中的虚拟机,允许在内核空间中执行代码。此代码运行在一个受限的沙箱环境中,仅可访问有限功能集。

在网络中,您可以使用 eBPF 来补充或替换内核数据包处理。根据您使用的 hook,eBPF 程序有:

  • 对元数据的读和写的访问权限
  • 可以查找套接字和路由
  • 可以设置套接字选项
  • 可以重定向数据包

44.1. RHEL 8 中网络 eBPF 功能概述

您可以将扩展的 Berkeley 数据包过滤器(eBPF)网络程序附加到 RHEL 中的以下钩子:

  • Express Data Path(XDP):在内核网络堆栈处理它们之前,对接收的数据包提供早期的访问权限。
  • 带有直接动作标志的 tc eBPF 分类器:对入口和出口提供强大的数据包处理。
  • 控制组版本 2(cgroup v2):在控制组中,对程序所执行的基于套接字的操作启用过滤和覆盖。
  • 套接字过滤:启用对从套接字接收的数据包进行过滤。这个功能也可用于经典 Berkeley Packet Filter(cBPF),但已扩展为支持 eBPF 程序。
  • 流解析器:启用将流分成单独的消息、过滤并将其重定向到套接字。
  • SO_REUSEPORT 套接字选择:对来自 reuseport 套接字组的接收套接字提供可编程选择。
  • 流程分析器:在某些情况下,启用覆盖内核解析数据包头的方式。
  • TCP 拥塞控制回调:启用实现一个自定义 TCP 拥塞控制算法。
  • 带有封装的路由: 允许创建自定义隧道封装。

请注意,红帽并不支持 RHEL 中的所有 eBPF 功能,如下所述。如需了解更多与每个 hook 相关的信息,请参阅 RHEL 8 发行注记和以下概述。

XDP

您可以将 BPF_PROG_TYPE_XDP 类型的程序附加到网络接口。然后,在内核网络堆栈开始处理之前,内核会在接收的数据包上执行该程序。在某些情况下,这允许快速数据包转发,如快速数据包丢弃以防止分布式拒绝服务(DDoS)攻击,以及负载均衡场景的快速数据包重定向。

您还可以使用 XDP 进行不同类型的数据包监控和抽样。内核允许 XDP 程序修改数据包,并将其传送到内核网络堆栈进行进一步处理。

以下的 XDP 模式可用:

  • 原生(驱动程序)XDP:内核在数据包接收过程从最早可能的点执行程序。目前,内核无法解析数据包,因此无法使用内核提供的元数据。这个模式要求网络接口驱动程序支持 XDP,但并非所有驱动程序都支持这种原生模式。
  • 通用 XDP:内核网络栈在进程早期执行 XDP 程序。此时内核数据结构已被分配,数据包已被预先处理。如果数据包被丢弃或重定向,与原生模式相比,这需要大量开销。但是,通用模式不需要支持网络接口驱动,它可适用于所有网络接口。
  • Offloaded XDP:内核在网络接口而不是主机 CPU 上执行 XDP 程序。请注意,这需要特定的硬件,这个模式中只有某些 eBPF 功能可用。

在 RHEL 上,使用 libxdp 库加载所有 XDP 程序。这个程序库启用系统控制的 XDP 使用。

注意

目前,XDP 程序有一些系统配置限制。例如:您必须禁用接收接口中某些硬件卸载功能。另外,并非所有功能都可用于支持原生模式的所有驱动程序。

在 RHEL 8.7 中,红帽仅在满足以下条件时支持 XDP 功能:

  • 您可以在 AMD 或者 Intel 64 位构架中载入 XDP 程序。
  • 您可以使用 libxdp 库将程序加载到内核中。
  • XDP 程序不使用 XDP 硬件卸载。

另外,红帽还提供以下使用 XDP 功能作为不受支持的技术预览:

  • 在 AMD 和 Intel 64 位以外的构架中载入 XDP 程序。请注意,libxdp 库不适用于 AMD 和 Intel 64 位的构架。
  • XDP 硬件卸载。

AF_XDP

使用过滤并将数据包重定向到给定 AF_XDP 套接字的 XDP 程序,您可以使用 AF_XDP 协议系列中的一个或多个套接字快速将数据包从内核复制到用户空间。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

流量控制

流量控制(tc)子系统提供以下 eBPF 程序类型:

  • BPF_PROG_TYPE_SCHED_CLS
  • BPF_PROG_TYPE_SCHED_ACT

这些类型允许您在 eBPF 中编写自定义的 tc 分类器和 tc 操作。与 tc 生态系统的各个部分一起,这为强大的数据包处理提供了能力,是一些容器编排解决方案的核心部分。

在大多数情况下,只有类符被使用,与 direct-action 标记一样,eBPF 分类器可以直接从同一 eBPF 程序执行操作。clsact 排队规程(qdisc)被设计为在入口端启用此功能。

请注意,使用流解析器 eBPF 程序可能会影响其他 qdiscstc 分类器的操作,如 flower

RHEL 8.2 及更新的版本完全支持 tc 特性的 eBPF。

套接字过滤器

一些实用程序会使用或在过去使用了 classic Berkeley Packet Filter(cBPF)过滤套接字上接收到的数据包。例如,tcpdump 工具允许用户指定表达式,tcpdump 然后将它们转换为 cBPF 码。

作为 cBPF 的替代方案,内核允许 BPF_PROG_TYPE_SOCKET_FILTER 类型的 eBPF 程序实现相同的目的。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

控制组群

在 RHEL 中,您可以使用多种 eBPF 程序,供您附加到 cgroup。当给定 cgroup 中的某个程序执行某个操作时,内核会执行这些程序。请注意,您只能使用 cgroups 版本 2。

RHEL 中提供以下与网络相关的 cgroup eBPF 程序:

  • BPF_PROG_TYPE_SOCK_OPS :内核对各种 TCP 事件调用该程序。程序可以调整内核 TCP 堆栈的行为,包括自定义 TCP 头选项等。
  • BPF_PROG_TYPE_CGROUP_SOCK_ADDR :在 connectbindsendtorecvmsggetpeernamegetockname 操作过程中,内核调用该程序。该程序允许更改 IP 地址和端口。当您在 eBPF 中实现基于套接字的网络地址转换(NAT)时,这很有用。
  • BPF_PROG_TYPE_CGROUP_SOCKOPT :在 setockoptgetsockopt 过程中,内核调用该程序,并允许更改选项。
  • BPF_PROG_TYPE_CGROUP_SOCK :在套接字创建、套接字释放和绑定到地址的过程中,内核调用该程序。您可以使用这些程序来允许或拒绝操作,或者只检查套接字创建统计信息。
  • BPF_PROG_TYPE_CGROUP_SKB :该程序在入口和出口处过滤单个数据包,并可以接受或拒绝数据包。
  • BPF_PROG_TYPE_CGROUP_SYSCTL :该程序允许访问系统控制的过滤(sysctl)。
  • BPF_CGROUP_INET4_GETPEERNAMEBPF_CGROUP_INET6_GETPEERNAMEBPF_CGROUP_INET4_GETSOCKNAMEBPF_CGROUP_INET6_GETSOCKNAME: 使用这些程序,您可以覆盖 getocknamegetername 系统调用的结果。当您在 eBPF 中实现基于套接字的网络地址转换(NAT)时,这很有用。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

流解析器(Stream Parser)

流解析器对添加到特殊 eBPF 映射中的一组套接字进行操作。然后 eBPF 程序处理内核在那些套接字上接收或发送的数据包。

RHEL 中提供了以下流解析程序 eBPF 程序:

  • BPF_PROG_TYPE_SK_SKB :eBPF 程序将来自套接字的数据包解析为单独的消息,并指示内核丢弃这些消息或将其发送给组中的另一个套接字。
  • BPF_PROG_TYPE_SK_MSG :此程序过滤出口消息。eBPF 程序将数据包解析到单个信息中,并批准或拒绝它们。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

SO_REUSEPORT 套接字选择

使用这个套接字选项,您可以绑定多个套接字到相同的 IP 地址和端口。如果没有 eBPF,内核会根据连接散列选择接收套接字。有了 BPF_PROG_TYPE_SK_REUSEPORT 程序,接收套接字的选择是完全可编程的。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

dissector 流程

当内核需要处理数据包头,而不需要查看全部协议解码时,会对它们进行 剖析。例如,这会在 tc 子系统、多路径路由、绑定或者计算数据包哈希时发生。在这种情况下,内核解析数据包的标头,并使用数据包标头中的信息填充内部结构。您可以使用 BPF_PROG_TYPE_FLOW_DISSECTOR 程序替换此内部解析。请注意,您只能在 RHEL 的 eBPF 的 IPv4 和 IPv6 上分离 TCP 和 UDP。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

TCP 阻塞控制

您可以使用一组实现 struct tcp_congestion_oops 回调的 BPF_PROG_TYPE_STRUCT_OPS 程序来编写一个自定义的 TCP 阻塞控制算法。以这种方式实现的算法和内置的内核算法一起可提供给系统使用。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

带有封装的路由

您可以将以下 eBPF 程序类型之一附加到路由表中作为隧道封装属性的路由:

  • BPF_PROG_TYPE_LWT_IN
  • BPF_PROG_TYPE_LWT_OUT
  • BPF_PROG_TYPE_LWT_XMIT

这样的 eBPF 程序的功能仅限于特定的隧道配置,它不允许创建通用封装或封装解决方案。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。

套接字查找

要绕过 bind 系统调用的限制,请使用 BPF_PROG_TYPE_SK_LOOKUP 类型的 eBPF 程序。此类程序可以为新传入的 TCP 连接选择侦听套接字,或为 UDP 数据包选择一个未连接的套接字。

在 RHEL 8.7 中,红帽将此功能作为不受支持的技术预览提供。