BPF_MAP_TYPE_CGROUP_STORAGE¶
BPF_MAP_TYPE_CGROUP_STORAGE
映射类型表示本地固定大小的存储。它仅在 CONFIG_CGROUP_BPF
中可用,并且仅适用于附加到 cgroup 的程序;这些程序由相同的 Kconfig 提供。存储由程序附加到的 cgroup 标识。
该映射在 BPF 程序附加到的 cgroup 上提供本地存储。它比通用哈希表提供更快、更简单的访问,通用哈希表执行哈希表查找,并需要用户自行跟踪活动的 cgroup。
本文档描述了 BPF_MAP_TYPE_CGROUP_STORAGE
映射类型的使用和语义。它的一些行为在 Linux 5.9 中发生了更改,本文档将描述这些差异。
用法¶
该映射使用类型为 __u64 cgroup_inode_id
或 struct bpf_cgroup_storage_key
的键,在 linux/bpf.h
中声明
struct bpf_cgroup_storage_key {
__u64 cgroup_inode_id;
__u32 attach_type;
};
cgroup_inode_id
是 cgroup 目录的 inode id。attach_type
是程序的附加类型。
Linux 5.9 添加了对 __u64 cgroup_inode_id
类型作为键类型的支持。当使用此键类型时,特定 cgroup 和映射的所有附加类型将共享相同的存储。否则,如果类型为 struct bpf_cgroup_storage_key
,则不同附加类型的程序将被隔离并看到不同的存储。
要访问程序中的存储,请使用 bpf_get_local_storage
void *bpf_get_local_storage(void *map, u64 flags)
flags
保留供将来使用,必须为 0。
没有隐式同步。BPF_MAP_TYPE_CGROUP_STORAGE
的存储可以由不同 CPU 上的多个程序访问,用户应该自己注意同步。bpf 基础设施提供 struct bpf_spin_lock
来同步存储。请参阅 tools/testing/selftests/bpf/progs/test_spin_lock.c
。
示例¶
使用键类型为 struct bpf_cgroup_storage_key
的用法
#include <bpf/bpf.h>
struct {
__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
__type(key, struct bpf_cgroup_storage_key);
__type(value, __u32);
} cgroup_storage SEC(".maps");
int program(struct __sk_buff *skb)
{
__u32 *ptr = bpf_get_local_storage(&cgroup_storage, 0);
__sync_fetch_and_add(ptr, 1);
return 0;
}
用户空间访问上面声明的映射
#include <linux/bpf.h>
#include <linux/libbpf.h>
__u32 map_lookup(struct bpf_map *map, __u64 cgrp, enum bpf_attach_type type)
{
struct bpf_cgroup_storage_key = {
.cgroup_inode_id = cgrp,
.attach_type = type,
};
__u32 value;
bpf_map_lookup_elem(bpf_map__fd(map), &key, &value);
// error checking omitted
return value;
}
或者,仅使用 __u64 cgroup_inode_id
作为键类型
#include <bpf/bpf.h>
struct {
__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
__type(key, __u64);
__type(value, __u32);
} cgroup_storage SEC(".maps");
int program(struct __sk_buff *skb)
{
__u32 *ptr = bpf_get_local_storage(&cgroup_storage, 0);
__sync_fetch_and_add(ptr, 1);
return 0;
}
以及用户空间
#include <linux/bpf.h>
#include <linux/libbpf.h>
__u32 map_lookup(struct bpf_map *map, __u64 cgrp, enum bpf_attach_type type)
{
__u32 value;
bpf_map_lookup_elem(bpf_map__fd(map), &cgrp, &value);
// error checking omitted
return value;
}
语义¶
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
是此映射类型的一个变体。此按 CPU 变体将为每个 CPU 的每个存储具有不同的内存区域。非按 CPU 将为每个存储具有相同的内存区域。
在 Linux 5.9 之前,存储的生命周期精确到每次附加,并且对于单个 CGROUP_STORAGE
映射,最多只能加载一个使用该映射的程序。一个程序可以附加到多个 cgroup 或具有多个附加类型,并且每次附加都会创建一个新的清零存储。存储在分离时释放。
在加载验证期间,每种类型(按 CPU 和非按 CPU)的映射与 BPF 程序之间存在一对一的关联。因此,每个映射只能被一个 BPF 程序使用,并且每个 BPF 程序只能使用每种类型的一个存储映射。由于映射只能被一个 BPF 程序使用,因此不可能与其他 BPF 程序共享此 cgroup 的存储。
自 Linux 5.9 以来,存储可以由多个程序共享。当程序附加到 cgroup 时,仅当映射中不存在 cgroup 和附加类型对的条目时,内核才会创建新存储,否则旧存储将重用于新的附加。如果映射是附加类型共享的,则在比较期间会简单地忽略附加类型。仅当映射或附加到的 cgroup 被释放时,才会释放存储。分离不会直接释放存储,但它可能会导致对映射的引用达到零并间接释放映射中的所有存储。
该映射不与任何 BPF 程序关联,从而使得共享成为可能。但是,BPF 程序仍然只能与每种类型的一个映射(按 CPU 和非按 CPU)关联。一个 BPF 程序不能使用多个 BPF_MAP_TYPE_CGROUP_STORAGE
或多个 BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
。
在所有版本中,用户空间都可以使用 struct bpf_cgroup_storage_key
中的 cgroup 和附加类型对的附加参数作为 BPF 映射 API 的键,以读取或更新给定附加的存储。对于 Linux 5.9 附加类型共享的存储,在比较期间仅使用结构中的第一个值 cgroup inode id,因此用户空间可以直接指定一个 __u64
。
存储在附加时绑定。即使程序附加到父级并在子级中触发,存储仍然属于父级。
用户空间无法在映射中创建新条目或删除现有条目。程序测试运行始终使用临时存储。