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_idstruct 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

儲存在附加時繫結。即使程式附加到父級並在子級中觸發,儲存仍然屬於父級。

使用者空間不能在對映中建立新條目或刪除現有條目。程式測試執行總是使用臨時儲存。