XDP RX 元数据¶
本文档描述了 eXpress Data Path (XDP) 程序如何使用一组辅助函数访问与数据包相关的硬件元数据,以及如何将该元数据传递给其他消费者。
总体设计¶
XDP 可以访问一组 kfuncs 来操作 XDP 帧中的元数据。每个希望公开额外数据包元数据的设备驱动程序都可以实现这些 kfuncs。kfuncs 的集合在 include/net/xdp.h
中通过 XDP_METADATA_KFUNC_xxx
声明。
目前,支持以下 kfuncs。未来,随着支持的元数据越来越多,这个集合将会扩大
-
__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-时间戳
-
__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) 指定了网卡硬件在计算 RSS 哈希值时使用的数据包报头的哪一部分。RSS 类型可以通过 enum xdp_rss_hash_type
解码,可以匹配单个 L3/L4 位 XDP_RSS_L*
或组合传统的 *RSS 哈希类型* XDP_RSS_TYPE_L*
。
返回
成功时返回 0,错误时返回
-errno
。-EOPNOTSUPP
:表示设备驱动程序未实现 kfunc-ENODATA
:表示此帧没有可用的 RX 哈希值
-
__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_8021Q
或 ETH_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 程序可以使用这些 kfuncs 将元数据读取到堆栈变量中以供自身使用。或者,为了将元数据传递给其他使用者,XDP 程序可以将其存储在数据包前面携带的元数据区域中。并非所有数据包都必然具有可用的请求元数据,在这种情况下,驱动程序将返回 -ENODATA
。
并非所有 kfuncs 都必须由设备驱动程序实现;如果未实现,将使用返回 -EOPNOTSUPP
的默认 kfuncs 来指示设备驱动程序未实现此 kfunc。
在 XDP 帧中,元数据布局(通过 xdp_buff
访问)如下:
+----------+-----------------+------+
| headroom | custom metadata | data |
+----------+-----------------+------+
^ ^
| |
xdp_buff->data_meta xdp_buff->data
XDP 程序可以将单独的元数据项以其选择的任何格式存储到此 data_meta
区域中。元数据的后续使用者必须通过一些带外合约(例如对于 AF_XDP 用例,请参见下文)就格式达成一致。
AF_XDP¶
AF_XDP 用例意味着将 XDP 帧重定向到 AF_XDP
套接字 (XSK
) 的 BPF 程序与最终使用者之间存在合约。因此,BPF 程序通过 bpf_xdp_adjust_meta
从元数据中手动分配固定数量的字节,并调用 kfuncs 的子集来填充它。用户空间 XSK
使用者计算 xsk_umem__get_data() - METADATA_SIZE
来定位该元数据。请注意,xsk_umem__get_data
在 libxdp
中定义,而 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
元数据,并且内核在构建 skb
时不使用 XDP 元数据。但是,TC-BPF 程序可以使用 data_meta
指针访问 XDP 元数据区域。
将来,我们希望支持这样一种情况:XDP 程序可以覆盖用于构建 skb
的某些元数据。
bpf_redirect_map¶
bpf_redirect_map
可以将帧重定向到不同的设备。某些设备(如虚拟以太网链路)支持在重定向后运行第二个 XDP 程序。但是,最终使用者无法访问原始硬件描述符,也无法访问任何原始元数据。这同样适用于安装到 devmaps 和 cpumaps 中的 XDP 程序。
这意味着对于重定向的数据包,目前仅支持自定义元数据,该元数据必须在重定向之前由初始 XDP 程序准备。如果帧最终传递给内核,则从此类帧创建的 skb
将不会在其 skb
中填充任何硬件元数据。如果这样的数据包稍后被重定向到 XSK
中,那么它也只能访问自定义元数据。
bpf_tail_call¶
目前不支持将访问元数据 kfuncs 的程序添加到 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.c
和 tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
。