BPF_MAP_TYPE_SK_STORAGE

注意

  • BPF_MAP_TYPE_SK_STORAGE 在内核版本 5.2 中引入

BPF_MAP_TYPE_SK_STORAGE 用于为 BPF 程序提供套接字本地存储。类型为 BPF_MAP_TYPE_SK_STORAGE 的映射声明要提供的存储类型,并作为访问套接字本地存储的句柄。类型为 BPF_MAP_TYPE_SK_STORAGE 的映射的值存储在每个套接字本地,而不是存储在映射中。内核负责在请求时为套接字分配存储空间,并在映射或套接字被删除时释放存储空间。

注意

  • 键类型必须是 intmax_entries 必须设置为 0

  • 创建套接字本地存储映射时必须使用 BPF_F_NO_PREALLOC 标志。

用法

内核 BPF

bpf_sk_storage_get()

void *bpf_sk_storage_get(struct bpf_map *map, void *sk, void *value, u64 flags)

可以使用 bpf_sk_storage_get() 助手从套接字 sk 中检索 map 的套接字本地存储。如果使用 BPF_LOCAL_STORAGE_GET_F_CREATE 标志,则 bpf_sk_storage_get() 将为 sk 创建存储(如果它尚不存在)。value 可以与 BPF_LOCAL_STORAGE_GET_F_CREATE 一起使用来初始化存储值,否则它将被零初始化。成功时返回指向存储的指针,失败时返回 NULL

注意

  • sk 是 LSM 或跟踪程序的内核 struct sock 指针。

  • sk 是其他程序类型的 struct bpf_sock 指针。

bpf_sk_storage_delete()

long bpf_sk_storage_delete(struct bpf_map *map, void *sk)

可以使用 bpf_sk_storage_delete() 助手从套接字 sk 中删除 map 的套接字本地存储。成功时返回 0,失败时返回负错误码。

用户空间

bpf_map_update_elem()

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

可以使用 bpf_map_update_elem() libbpf 函数将映射 map_fd 的套接字本地存储添加到或更新到套接字。套接字由存储在指针 key 中的 socket fd 标识。指针 value 包含要添加到或更新到套接字 fd 的数据。value 的类型和大小应与映射定义的值类型相同。

flags 参数可用于控制更新行为

  • BPF_ANY 将为 socket fd 创建存储或更新现有存储。

  • BPF_NOEXIST 将仅在 socket fd 不存在时创建存储,否则调用将以 -EEXIST 失败。

  • BPF_EXIST 将在 socket fd 已经存在时更新其现有存储,否则调用将以 -ENOENT 失败。

成功时返回 0,失败时返回负错误码。

bpf_map_lookup_elem()

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

可以使用 bpf_map_lookup_elem() libbpf 函数从套接字中检索映射 map_fd 的套接字本地存储。存储是从由存储在指针 key 中的 socket fd 标识的套接字中检索的。成功时返回 0,失败时返回负错误码。

bpf_map_delete_elem()

int bpf_map_delete_elem(int map_fd, const void *key)

可以使用 bpf_map_delete_elem() libbpf 函数从套接字中删除映射 map_fd 的套接字本地存储。存储是从由存储在指针 key 中的 socket fd 标识的套接字中删除的。成功时返回 0,失败时返回负错误码。

示例

内核 BPF

此代码片段展示了如何在 BPF 程序中声明套接字本地存储

struct {
        __uint(type, BPF_MAP_TYPE_SK_STORAGE);
        __uint(map_flags, BPF_F_NO_PREALLOC);
        __type(key, int);
        __type(value, struct my_storage);
} socket_storage SEC(".maps");

此代码片段展示了如何在 BPF 程序中检索套接字本地存储

SEC("sockops")
int _sockops(struct bpf_sock_ops *ctx)
{
        struct my_storage *storage;
        struct bpf_sock *sk;

        sk = ctx->sk;
        if (!sk)
                return 1;

        storage = bpf_sk_storage_get(&socket_storage, sk, 0,
                                     BPF_LOCAL_STORAGE_GET_F_CREATE);
        if (!storage)
                return 1;

        /* Use 'storage' here */

        return 1;
}

请参阅 tools/testing/selftests/bpf 目录以获取功能示例。

参考资料

https://lwn.net/ml/netdev/20190426171103.61892-1-kafai@fb.com/