XDP RX 元数据

本文档介绍 eXpress Data Path (XDP) 程序如何使用一组辅助函数访问与数据包相关的硬件元数据,以及如何将该元数据传递给其他使用者。

通用设计

XDP 有权访问一组 kfunc 来操作 XDP 帧中的元数据。每个希望公开其他数据包元数据的设备驱动程序都可以实现这些 kfunc。kfunc 集在 include/net/xdp.h 中通过 XDP_METADATA_KFUNC_xxx 声明。

目前,支持以下 kfunc。将来,随着支持的元数据越来越多,此集合将会增加

__bpf_kfunc int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp)

读取 XDP 帧 RX 时间戳。

参数

const struct xdp_md *ctx

XDP 上下文指针。

u64 *timestamp

返回值指针。

返回

  • 成功返回 0,错误返回 -errno

  • -EOPNOTSUPP:表示设备驱动程序未实现 kfunc

  • -ENODATA:表示此帧没有 RX-timestamp 可用

__bpf_kfunc int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, u32 *hash, enum xdp_rss_hash_type *rss_type)

读取 XDP 帧 RX 哈希。

参数

const struct xdp_md *ctx

XDP 上下文指针。

u32 *hash

返回值指针。

enum xdp_rss_hash_type *rss_type

RSS 类型的返回值指针。

描述

RSS 哈希类型 (rss_type) 指定 NIC 硬件在计算 RSS 哈希值时使用的数据包标头部分。可以通过 enum xdp_rss_hash_type 解码 RSS 类型,可以匹配单个 L3/L4 位 XDP_RSS_L* 或组合的传统 _RSS 哈希类型_ XDP_RSS_TYPE_L*

返回

  • 成功返回 0,错误返回 -errno

  • -EOPNOTSUPP:表示设备驱动程序未实现 kfunc

  • -ENODATA:表示此帧没有 RX-hash 可用

__bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, __be16 *vlan_proto, u16 *vlan_tci)

获取 XDP 数据包最外层 VLAN 标签

参数

const struct xdp_md *ctx

XDP 上下文指针。

__be16 *vlan_proto

VLAN 标签协议标识符 (TPID) 的目标指针。

u16 *vlan_tci

VLAN TCI(VID + DEI + PCP)的目标指针

描述

如果成功,vlan_proto 包含 _标签协议标识符 (TPID)_,通常为 ETH_P_8021QETH_P_8021AD,但有些网络可能使用自定义 TPID。vlan_proto 以 **网络字节顺序 (BE)** 存储,应按如下方式使用:if (vlan_proto == bpf_htons(ETH_P_8021Q)) do_something();

vlan_tci 包含 VLAN 标签的其余 16 位。驱动程序应以 **主机字节顺序(通常为 LE)** 提供这些位,因此 bpf 程序不应执行字节转换。根据 802.1Q 标准,_VLAN TCI(标签控制信息)_ 是一个位字段,包含:_VLAN 标识符 (VID)_,可以使用 vlan_tci & 0xfff 读取,_丢弃资格指示符 (DEI)_ - 1 位,_优先级代码点 (PCP)_ - 3 位。有关 DEI 和 PCP 的详细含义,请参阅其他来源。

返回

  • 成功返回 0,错误返回 -errno

  • -EOPNOTSUPP:设备驱动程序未实现 kfunc

  • -ENODATA:VLAN 标签未剥离或不可用

XDP 程序可以使用这些 kfunc 将元数据读取到堆栈变量中以供自己使用。或者,要将元数据传递给其他使用者,XDP 程序可以将其存储到数据包前方的元数据区域中。并非所有数据包都一定具有所请求的元数据,在这种情况下,驱动程序会返回 -ENODATA

并非所有 kfunc 都必须由设备驱动程序实现;如果未实现,则将使用返回 -EOPNOTSUPP 的默认 kfunc 来指示设备驱动程序未实现此 kfunc。

在 XDP 帧中,元数据布局(通过 xdp_buff 访问)如下所示

+----------+-----------------+------+
| headroom | custom metadata | data |
+----------+-----------------+------+
           ^                 ^
           |                 |
 xdp_buff->data_meta   xdp_buff->data

XDP 程序可以将单个元数据项以其选择的任何格式存储到此 data_meta 区域中。元数据的后续使用者必须通过某种带外协议(例如 AF_XDP 用例,见下文)就格式达成一致。

AF_XDP

AF_XDP 用例意味着 BPF 程序与最终使用者之间存在协议,BPF 程序将 XDP 帧重定向到 AF_XDP 套接字 (XSK)。因此,BPF 程序通过 bpf_xdp_adjust_meta 手动分配固定数量的元数据字节,并调用 kfunc 子集来填充它。用户空间 XSK 使用者计算 xsk_umem__get_data() - METADATA_SIZE 来找到该元数据。请注意,xsk_umem__get_datalibxdp 中定义,METADATA_SIZE 是应用程序特定的常量(AF_XDP 接收描述符_不_显式携带元数据的大小)。

这是 AF_XDP 使用者布局(请注意缺少 data_meta 指针)

+----------+-----------------+------+
| headroom | custom metadata | data |
+----------+-----------------+------+
                             ^
                             |
                      rx_desc->address

XDP_PASS

这是 XDP 程序处理的数据包传递到内核的路径。内核从 xdp_buff 内容创建 skb。目前,每个驱动程序都有自定义内核代码来解析描述符并在执行此 xdp_buff->skb 转换时填充 skb 元数据,并且内核在构建 skbs 时不使用 XDP 元数据。但是,TC-BPF 程序可以使用 data_meta 指针访问 XDP 元数据区域。

将来,我们希望支持这样一种情况:XDP 程序可以覆盖用于构建 skbs 的某些元数据。

bpf_redirect_map

bpf_redirect_map 可以将帧重定向到其他设备。某些设备(例如虚拟以太网链接)支持在重定向后运行第二个 XDP 程序。但是,最终使用者无法访问原始硬件描述符,也无法访问任何原始元数据。这同样适用于安装到 devmap 和 cpumap 中的 XDP 程序。

这意味着对于重定向的数据包,目前仅支持自定义元数据,必须由初始 XDP 程序在重定向之前准备好。如果该帧最终传递到内核,则从此帧创建的 skb 将不会在其 skb 中填充任何硬件元数据。如果此类数据包稍后重定向到 XSK 中,则也将只能访问自定义元数据。

bpf_tail_call

目前不支持将访问元数据 kfunc 的程序添加到 BPF_MAP_TYPE_PROG_ARRAY

支持的设备

可以通过 netlink 查询特定 netdev 实现的 kfunc。请参阅 Documentation/netlink/specs/netdev.yaml 中设置的 xdp-rx-metadata-features 属性。

示例

有关处理 XDP 元数据的 BPF 程序的示例,请参阅 tools/testing/selftests/bpf/progs/xdp_metadata.ctools/testing/selftests/bpf/prog_tests/xdp_metadata.c