Commit | Line | Data |
---|---|---|
f720b848 DH |
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 | ||
539886a3 DH |
48 | bpf_map_lookup_elem() |
49 | ~~~~~~~~~~~~~~~~~~~~~ | |
50 | ||
51 | .. code-block:: c | |
52 | ||
f720b848 DH |
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/ |