← Documents Documentation/bpf/map_of_maps.rst GitHub 원문 ↗

Linux 6.18.37 · BPF

BPF_MAP_TYPE_ARRAY_OF_MAPS and BPF_MAP_TYPE_HASH_OF_MAPS

Array/hash outer map의 inner-map metadata와 lifetime, nesting 제한, kernel lookup 및 userspace 생성·삽입 예제를 설명합니다.

Source pathDocumentation/bpf/map_of_maps.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

map_of_maps.rst:1-130

Map-in-map은 outer map에서 동일한 type의 inner map을 한 단계까지 참조합니다. Outer map 생성 시 template inner map으로 schema metadata를 고정하지만 template 자체의 lifetime은 독립적입니다.

BPF program은 outer map을 lookup만 할 수 있고 update와 delete는 userspace가 수행합니다. `BPF_MAP_TYPE_PROG_ARRAY`는 inner map으로 사용할 수 없습니다.

Array outer map은 고정된 32-bit index를 사용하고 hash outer map은 key type을 선택할 수 있습니다. Userspace는 inner map fd를 outer map value로 update해 runtime 구성을 바꿉니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0-only
2 .. Copyright (C) 2022 Red Hat, Inc.
3
4 ========================================================
5 BPF_MAP_TYPE_ARRAY_OF_MAPS and BPF_MAP_TYPE_HASH_OF_MAPS
6 ========================================================
7
8 .. note::
9 - ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` and ``BPF_MAP_TYPE_HASH_OF_MAPS`` were
10 introduced in kernel version 4.12
11
12 ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` and ``BPF_MAP_TYPE_HASH_OF_MAPS`` provide general
13 purpose support for map in map storage. One level of nesting is supported, where
14 an outer map contains instances of a single type of inner map, for example
15 ``array_of_maps->sock_map``.
16
17 When creating an outer map, an inner map instance is used to initialize the
18 metadata that the outer map holds about its inner maps. This inner map has a
19 separate lifetime from the outer map and can be deleted after the outer map has
20 been created.
21
22 The outer map supports element lookup, update and delete from user space using
23 the syscall API. A BPF program is only allowed to do element lookup in the outer
24 map.
25
26 .. note::
27 - Multi-level nesting is not supported.
28 - Any BPF map type can be used as an inner map, except for
29 ``BPF_MAP_TYPE_PROG_ARRAY``.
30 - A BPF program cannot update or delete outer map entries.
31
32 For ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` the key is an unsigned 32-bit integer index
33 into the array. The array is a fixed size with ``max_entries`` elements that are
34 zero initialized when created.
35
36 For ``BPF_MAP_TYPE_HASH_OF_MAPS`` the key type can be chosen when defining the
37 map. The kernel is responsible for allocating and freeing key/value pairs, up to
38 the max_entries limit that you specify. Hash maps use pre-allocation of hash
39 table elements by default. The ``BPF_F_NO_PREALLOC`` flag can be used to disable
40 pre-allocation when it is too memory expensive.
41
42 Usage
43 =====
44
45 Kernel BPF Helper
46 -----------------
47
48 bpf_map_lookup_elem()
49 ~~~~~~~~~~~~~~~~~~~~~
50
51 .. code-block:: c
52
53 void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
54
55 Inner maps can be retrieved using the ``bpf_map_lookup_elem()`` helper. This
56 helper returns a pointer to the inner map, or ``NULL`` if no entry was found.
57
58 Examples
59 ========
60
61 Kernel BPF Example
62 ------------------
63
64 This snippet shows how to create and initialise an array of devmaps in a BPF
65 program. Note that the outer array can only be modified from user space using
66 the syscall API.
67
68 .. code-block:: c
69
70 struct inner_map {
71 __uint(type, BPF_MAP_TYPE_DEVMAP);
72 __uint(max_entries, 10);
73 __type(key, __u32);
74 __type(value, __u32);
75 } inner_map1 SEC(".maps"), inner_map2 SEC(".maps");
76
77 struct {
78 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
79 __uint(max_entries, 2);
80 __type(key, __u32);
81 __array(values, struct inner_map);
82 } outer_map SEC(".maps") = {
83 .values = { &inner_map1,
84 &inner_map2 }
85 };
86
87 See ``progs/test_btf_map_in_map.c`` in ``tools/testing/selftests/bpf`` for more
88 examples of declarative initialisation of outer maps.
89
90 User Space
91 ----------
92
93 This snippet shows how to create an array based outer map:
94
95 .. code-block:: c
96
97 int create_outer_array(int inner_fd) {
98 LIBBPF_OPTS(bpf_map_create_opts, opts, .inner_map_fd = inner_fd);
99 int fd;
100
101 fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS,
102 "example_array", /* name */
103 sizeof(__u32), /* key size */
104 sizeof(__u32), /* value size */
105 256, /* max entries */
106 &opts); /* create opts */
107 return fd;
108 }
109
110
111 This snippet shows how to add an inner map to an outer map:
112
113 .. code-block:: c
114
115 int add_devmap(int outer_fd, int index, const char *name) {
116 int fd;
117
118 fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, name,
119 sizeof(__u32), sizeof(__u32), 256, NULL);
120 if (fd < 0)
121 return fd;
122
123 return bpf_map_update_elem(outer_fd, &index, &fd, BPF_ANY);
124 }
125
126 References
127 ==========
128
129 - https://lore.kernel.org/netdev/20170322170035.923581-3-kafai@fb.com/
130 - https://lore.kernel.org/netdev/20170322170035.923581-4-kafai@fb.com/
131

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Outer map과 inner map 규칙

1-41

`BPF_MAP_TYPE_ARRAY_OF_MAPS`와 `BPF_MAP_TYPE_HASH_OF_MAPS` 문서는 `GPL-2.0-only` 라이선스와 `Copyright (C) 2022 Red Hat, Inc.`를 명시합니다.

`BPF_MAP_TYPE_ARRAY_OF_MAPS`와 `BPF_MAP_TYPE_HASH_OF_MAPS`는 `kernel version 4.12`에 도입되었습니다.

두 map type은 general-purpose map-in-map storage를 제공합니다. Nesting은 한 level만 지원하며 outer map은 한 가지 type의 inner map instance를 담습니다. 예를 들어 `array_of_maps->sock_map` 형태로 구성할 수 있습니다.

Outer map을 만들 때 inner map instance 하나로 outer map이 inner map에 대해 보관할 metadata를 initialize합니다. 이 template inner map의 lifetime은 outer map과 별개이므로 outer map 생성 후 삭제할 수 있습니다.

Userspace는 syscall API로 outer map element를 lookup, update, delete할 수 있습니다. BPF program은 outer map에서 element lookup만 할 수 있습니다.

Multi-level nesting은 지원되지 않습니다. `BPF_MAP_TYPE_PROG_ARRAY`를 제외한 모든 BPF map type을 inner map으로 사용할 수 있으며, BPF program은 outer map entry를 update하거나 delete할 수 없습니다.

`BPF_MAP_TYPE_ARRAY_OF_MAPS`의 key는 array index인 unsigned 32-bit integer입니다. Array는 `max_entries`개의 고정 크기이며 생성할 때 zero-initialize됩니다.

`BPF_MAP_TYPE_HASH_OF_MAPS`의 key type은 map 정의 시 선택할 수 있습니다. Kernel은 지정된 `max_entries`까지 key/value pair를 할당하고 해제합니다. Hash element는 기본적으로 pre-allocation되며 memory 비용이 너무 크면 `BPF_F_NO_PREALLOC`로 끌 수 있습니다.

Kernel BPF inner map lookup

42-57

BPF program에서 inner map을 가져올 때는 다음 `bpf_map_lookup_elem()` helper를 사용합니다.

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

Helper는 key에 연결된 inner map pointer를 반환하며 entry가 없으면 `NULL`을 반환합니다.

Declarative array-of-devmaps 예제

58-89

다음 BPF code는 devmap array를 만들고 initialize합니다. Outer array는 userspace의 syscall API로만 수정할 수 있습니다.

struct inner_map {
        __uint(type, BPF_MAP_TYPE_DEVMAP);
        __uint(max_entries, 10);
        __type(key, __u32);
        __type(value, __u32);
} inner_map1 SEC(".maps"), inner_map2 SEC(".maps");

struct {
        __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
        __uint(max_entries, 2);
        __type(key, __u32);
        __array(values, struct inner_map);
} outer_map SEC(".maps") = {
        .values = { &inner_map1,
                    &inner_map2 }
};

`inner_map1`과 `inner_map2`는 같은 `struct inner_map` schema의 `BPF_MAP_TYPE_DEVMAP`입니다. `outer_map`은 `BPF_MAP_TYPE_ARRAY_OF_MAPS`이며 `.values` initializer에서 두 inner map의 address를 연결합니다.

Outer map의 declarative initialization example은 `tools/testing/selftests/bpf`의 `progs/test_btf_map_in_map.c`에서 더 확인할 수 있습니다.

Userspace 생성·삽입과 참고 자료

90-130

다음 code는 `LIBBPF_OPTS(bpf_map_create_opts, ...)`의 `inner_map_fd`에 template inner map fd를 설정한 뒤 array-based outer map을 만듭니다.

int create_outer_array(int inner_fd) {
        LIBBPF_OPTS(bpf_map_create_opts, opts, .inner_map_fd = inner_fd);
        int fd;

        fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS,
                            "example_array",       /* name */
                            sizeof(__u32),         /* key size */
                            sizeof(__u32),         /* value size */
                            256,                   /* max entries */
                            &opts);                /* create opts */
        return fd;
}

`bpf_map_create()`에는 `BPF_MAP_TYPE_ARRAY_OF_MAPS`, map name, key/value size, max entries 256, create option을 전달합니다.

다음 code는 새 `BPF_MAP_TYPE_DEVMAP`을 만든 뒤 해당 fd를 `BPF_ANY` semantics로 outer map의 지정된 index에 추가합니다.

int add_devmap(int outer_fd, int index, const char *name) {
        int fd;

        fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, name,
                            sizeof(__u32), sizeof(__u32), 256, NULL);
        if (fd < 0)
                return fd;

        return bpf_map_update_elem(outer_fd, &index, &fd, BPF_ANY);
}

Map-in-map 도입 배경과 patch discussion은 다음 자료에 있습니다.

  • [https://lore.kernel.org/netdev/20170322170035.923581-3-kafai@fb.com/](https://lore.kernel.org/netdev/20170322170035.923581-3-kafai@fb.com/)
  • [https://lore.kernel.org/netdev/20170322170035.923581-4-kafai@fb.com/](https://lore.kernel.org/netdev/20170322170035.923581-4-kafai@fb.com/)