BPF_MAP_TYPE_XSKMAP

注意

  • BPF_MAP_TYPE_XSKMAP 在内核版本 4.18 中引入

BPF_MAP_TYPE_XSKMAP 用作 XDP BPF 辅助调用 bpf_redirect_map()XDP_REDIRECT 操作的后端映射,例如“devmap”和“cpumap”。此映射类型将原始 XDP 帧重定向到 AF_XDP 套接字 (XSK),这是一种内核中的新型地址族,允许将帧从驱动程序重定向到用户空间,而无需遍历完整的网络堆栈。AF_XDP 套接字绑定到单个 netdev 队列。XSK 到队列的映射如下所示

+---------------------------------------------------+
|     xsk A      |     xsk B       |      xsk C     |<---+ User space
=========================================================|==========
|    Queue 0     |     Queue 1     |     Queue 2    |    |  Kernel
+---------------------------------------------------+    |
|                  Netdev eth0                      |    |
+---------------------------------------------------+    |
|                            +=============+        |    |
|                            | key |  xsk  |        |    |
|  +---------+               +=============+        |    |
|  |         |               |  0  | xsk A |        |    |
|  |         |               +-------------+        |    |
|  |         |               |  1  | xsk B |        |    |
|  | BPF     |-- redirect -->+-------------+-------------+
|  | prog    |               |  2  | xsk C |        |
|  |         |               +-------------+        |
|  |         |                                      |
|  |         |                                      |
|  +---------+                                      |
|                                                   |
+---------------------------------------------------+

注意

绑定到特定 的 AF_XDP 套接字将接受来自该 的 XDP 帧。如果 XDP 程序尝试从套接字绑定的 之外的其他 重定向,则帧将不会在套接字上接收到。

通常,每个 netdev 创建一个 XSKMAP。此映射包含 XSK 文件描述符 (FD) 的数组。数组元素的数量通常使用 max_entries 映射参数设置或调整。对于 AF_XDP,max_entries 等于 netdev 支持的队列数。

注意

映射键和映射值大小都必须为 4 个字节。

用法

内核 BPF

bpf_redirect_map()

long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)

将数据包重定向到 map 中索引为 key 的端点。对于 BPF_MAP_TYPE_XSKMAP,此映射包含对附加到 netdev 队列的套接字的 XSK FD 的引用。

注意

如果映射在索引处为空,则数据包将被丢弃。这意味着必须加载 XDP 程序,并且 XSKMAP 中至少有一个 XSK,才能通过套接字将任何流量发送到用户空间。

bpf_map_lookup_elem()

void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)

可以使用 bpf_map_lookup_elem() 辅助函数检索类型为 struct xdp_sock * 的 XSK 条目引用。

用户空间

注意

XSK 条目只能从用户空间更新/删除,而不能从 BPF 程序更新/删除。尝试从内核 BPF 程序调用这些函数将导致程序加载失败和验证器警告。

bpf_map_update_elem()

int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags)

可以使用 bpf_map_update_elem() 辅助函数添加或更新 XSK 条目。key 参数等于 XSK 附加到的队列的 queue_id。value 参数是该套接字的 FD 值。

在底层,XSKMAP 更新函数使用 XSK FD 值来检索关联的 struct xdp_sock 实例。

flags 参数可以是以下值之一

  • BPF_ANY:创建新元素或更新现有元素。

  • BPF_NOEXIST:仅当新元素不存在时才创建新元素。

  • BPF_EXIST:更新现有元素。

bpf_map_lookup_elem()

int bpf_map_lookup_elem(int fd, const void *key, void *value)

返回 struct xdp_sock *,如果失败,则返回负错误。

bpf_map_delete_elem()

int bpf_map_delete_elem(int fd, const void *key)

可以使用 bpf_map_delete_elem() 辅助函数删除 XSK 条目。此辅助函数在成功时返回 0,如果失败,则返回负错误。

注意

libxdp 删除 XSK 时,它还会从 XSKMAP 中删除关联的套接字条目。

示例

内核

以下代码片段显示如何声明名为 xsks_mapBPF_MAP_TYPE_XSKMAP 以及如何将数据包重定向到 XSK。

struct {
        __uint(type, BPF_MAP_TYPE_XSKMAP);
        __type(key, __u32);
        __type(value, __u32);
        __uint(max_entries, 64);
} xsks_map SEC(".maps");


SEC("xdp")
int xsk_redir_prog(struct xdp_md *ctx)
{
        __u32 index = ctx->rx_queue_index;

        if (bpf_map_lookup_elem(&xsks_map, &index))
                return bpf_redirect_map(&xsks_map, index, 0);
        return XDP_PASS;
}

用户空间

以下代码片段显示如何使用 XSK 条目更新 XSKMAP。

int update_xsks_map(struct bpf_map *xsks_map, int queue_id, int xsk_fd)
{
        int ret;

        ret = bpf_map_update_elem(bpf_map__fd(xsks_map), &queue_id, &xsk_fd, 0);
        if (ret < 0)
                fprintf(stderr, "Failed to update xsks_map: %s\n", strerror(errno));

        return ret;
}

有关如何创建 AF_XDP 套接字的示例,请参阅 bpf-examples 目录中的 AF_XDP-example 和 AF_XDP-forwarding 程序,该目录位于 libxdp 存储库中。有关 AF_XDP 接口的详细说明,请参阅

注意

使用 XSKMAP 和 AF_XDP 最全面的资源是 libxdp