BPF_MAP_TYPE_QUEUE 和 BPF_MAP_TYPE_STACK

注意

  • BPF_MAP_TYPE_QUEUEBPF_MAP_TYPE_STACK 在内核版本 4.20 中引入

BPF_MAP_TYPE_QUEUE 为 BPF 程序提供 FIFO 存储,BPF_MAP_TYPE_STACK 为 BPF 程序提供 LIFO 存储。这些映射支持 peek、pop 和 push 操作,这些操作通过各自的助手暴露给 BPF 程序。这些操作通过以下方式使用现有的 bpf 系统调用暴露给用户空间应用程序

  • BPF_MAP_LOOKUP_ELEM -> peek

  • BPF_MAP_LOOKUP_AND_DELETE_ELEM -> pop

  • BPF_MAP_UPDATE_ELEM -> push

BPF_MAP_TYPE_QUEUEBPF_MAP_TYPE_STACK 不支持 BPF_F_NO_PREALLOC

用法

内核 BPF

bpf_map_push_elem()

long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)

可以使用 bpf_map_push_elem 助手将元素 value 添加到队列或堆栈中。flags 参数必须设置为 BPF_ANYBPF_EXIST。如果 flags 设置为 BPF_EXIST,则当队列或堆栈已满时,将删除最旧的元素,以便为要添加的 value 腾出空间。成功时返回 0,失败时返回负错误。

bpf_map_peek_elem()

long bpf_map_peek_elem(struct bpf_map *map, void *value)

此助手从队列或堆栈中获取元素 value 而不将其删除。成功时返回 0,失败时返回负错误。

bpf_map_pop_elem()

long bpf_map_pop_elem(struct bpf_map *map, void *value)

此助手将元素从队列或堆栈中移除到 value 中。成功时返回 0,失败时返回负错误。

用户空间

bpf_map_update_elem()

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

用户空间程序可以使用 libbpf 的 bpf_map_update_elem 函数将 value 推入队列或堆栈。 key 参数必须设置为 NULLflags 必须设置为 BPF_ANYBPF_EXIST,其语义与 bpf_map_push_elem 内核助手相同。成功时返回 0,失败时返回负错误。

bpf_map_lookup_elem()

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

用户空间程序可以使用 libbpf bpf_map_lookup_elem 函数查看队列或堆栈头部的 valuekey 参数必须设置为 NULL。成功时返回 0,失败时返回负错误。

bpf_map_lookup_and_delete_elem()

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

用户空间程序可以使用 libbpf bpf_map_lookup_and_delete_elem 函数从队列或堆栈的头部弹出 valuekey 参数必须设置为 NULL。成功时返回 0,失败时返回负错误。

示例

内核 BPF

此代码段显示如何在 BPF 程序中声明队列

struct {
        __uint(type, BPF_MAP_TYPE_QUEUE);
        __type(value, __u32);
        __uint(max_entries, 10);
} queue SEC(".maps");

用户空间

此代码段显示如何使用 libbpf 的低级 API 从用户空间创建队列

int create_queue()
{
        return bpf_map_create(BPF_MAP_TYPE_QUEUE,
                              "sample_queue", /* name */
                              0,              /* key size, must be zero */
                              sizeof(__u32),  /* value size */
                              10,             /* max entries */
                              NULL);          /* create options */
}

参考资料

https://lwn.net/ml/netdev/153986858555.9127.14517764371945179514.stgit@kernel/