Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1.. SPDX-License-Identifier: GPL-2.0-only
2.. Copyright (C) 2022 Red Hat, Inc.
3
4================================================
5BPF_MAP_TYPE_ARRAY and BPF_MAP_TYPE_PERCPU_ARRAY
6================================================
7
8.. note::
9 - ``BPF_MAP_TYPE_ARRAY`` was introduced in kernel version 3.19
10 - ``BPF_MAP_TYPE_PERCPU_ARRAY`` was introduced in version 4.6
11
12``BPF_MAP_TYPE_ARRAY`` and ``BPF_MAP_TYPE_PERCPU_ARRAY`` provide generic array
13storage. The key type is an unsigned 32-bit integer (4 bytes) and the map is
14of constant size. The size of the array is defined in ``max_entries`` at
15creation time. All array elements are pre-allocated and zero initialized when
16created. ``BPF_MAP_TYPE_PERCPU_ARRAY`` uses a different memory region for each
17CPU whereas ``BPF_MAP_TYPE_ARRAY`` uses the same memory region. The value
18stored can be of any size for ``BPF_MAP_TYPE_ARRAY`` and not more than
19``PCPU_MIN_UNIT_SIZE`` (32 kB) for ``BPF_MAP_TYPE_PERCPU_ARRAY``. All
20array elements are aligned to 8 bytes.
21
22Since kernel 5.5, memory mapping may be enabled for ``BPF_MAP_TYPE_ARRAY`` by
23setting the flag ``BPF_F_MMAPABLE``. The map definition is page-aligned and
24starts on the first page. Sufficient page-sized and page-aligned blocks of
25memory are allocated to store all array values, starting on the second page,
26which in some cases will result in over-allocation of memory. The benefit of
27using this is increased performance and ease of use since userspace programs
28would not be required to use helper functions to access and mutate data.
29
30Usage
31=====
32
33Kernel BPF
34----------
35
36bpf_map_lookup_elem()
37~~~~~~~~~~~~~~~~~~~~~
38
39.. code-block:: c
40
41 void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
42
43Array elements can be retrieved using the ``bpf_map_lookup_elem()`` helper.
44This helper returns a pointer into the array element, so to avoid data races
45with userspace reading the value, the user must use primitives like
46``__sync_fetch_and_add()`` when updating the value in-place.
47
48bpf_map_update_elem()
49~~~~~~~~~~~~~~~~~~~~~
50
51.. code-block:: c
52
53 long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)
54
55Array elements can be updated using the ``bpf_map_update_elem()`` helper.
56
57``bpf_map_update_elem()`` returns 0 on success, or negative error in case of
58failure.
59
60Since the array is of constant size, ``bpf_map_delete_elem()`` is not supported.
61To clear an array element, you may use ``bpf_map_update_elem()`` to insert a
62zero value to that index.
63
64Per CPU Array
65-------------
66
67Values stored in ``BPF_MAP_TYPE_ARRAY`` can be accessed by multiple programs
68across different CPUs. To restrict storage to a single CPU, you may use a
69``BPF_MAP_TYPE_PERCPU_ARRAY``.
70
71When using a ``BPF_MAP_TYPE_PERCPU_ARRAY`` the ``bpf_map_update_elem()`` and
72``bpf_map_lookup_elem()`` helpers automatically access the slot for the current
73CPU.
74
75bpf_map_lookup_percpu_elem()
76~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
78.. code-block:: c
79
80 void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu)
81
82The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the array
83value for a specific CPU. Returns value on success , or ``NULL`` if no entry was
84found or ``cpu`` is invalid.
85
86Concurrency
87-----------
88
89Since kernel version 5.1, the BPF infrastructure provides ``struct bpf_spin_lock``
90to synchronize access.
91
92Userspace
93---------
94
95Access from userspace uses libbpf APIs with the same names as above, with
96the map identified by its ``fd``.
97
98Examples
99========
100
101Please see the ``tools/testing/selftests/bpf`` directory for functional
102examples. The code samples below demonstrate API usage.
103
104Kernel BPF
105----------
106
107This snippet shows how to declare an array in a BPF program.
108
109.. code-block:: c
110
111 struct {
112 __uint(type, BPF_MAP_TYPE_ARRAY);
113 __type(key, u32);
114 __type(value, long);
115 __uint(max_entries, 256);
116 } my_map SEC(".maps");
117
118
119This example BPF program shows how to access an array element.
120
121.. code-block:: c
122
123 int bpf_prog(struct __sk_buff *skb)
124 {
125 struct iphdr ip;
126 int index;
127 long *value;
128
129 if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip, sizeof(ip)) < 0)
130 return 0;
131
132 index = ip.protocol;
133 value = bpf_map_lookup_elem(&my_map, &index);
134 if (value)
135 __sync_fetch_and_add(value, skb->len);
136
137 return 0;
138 }
139
140Userspace
141---------
142
143BPF_MAP_TYPE_ARRAY
144~~~~~~~~~~~~~~~~~~
145
146This snippet shows how to create an array, using ``bpf_map_create_opts`` to
147set flags.
148
149.. code-block:: c
150
151 #include <bpf/libbpf.h>
152 #include <bpf/bpf.h>
153
154 int create_array()
155 {
156 int fd;
157 LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE);
158
159 fd = bpf_map_create(BPF_MAP_TYPE_ARRAY,
160 "example_array", /* name */
161 sizeof(__u32), /* key size */
162 sizeof(long), /* value size */
163 256, /* max entries */
164 &opts); /* create opts */
165 return fd;
166 }
167
168This snippet shows how to initialize the elements of an array.
169
170.. code-block:: c
171
172 int initialize_array(int fd)
173 {
174 __u32 i;
175 long value;
176 int ret;
177
178 for (i = 0; i < 256; i++) {
179 value = i;
180 ret = bpf_map_update_elem(fd, &i, &value, BPF_ANY);
181 if (ret < 0)
182 return ret;
183 }
184
185 return ret;
186 }
187
188This snippet shows how to retrieve an element value from an array.
189
190.. code-block:: c
191
192 int lookup(int fd)
193 {
194 __u32 index = 42;
195 long value;
196 int ret;
197
198 ret = bpf_map_lookup_elem(fd, &index, &value);
199 if (ret < 0)
200 return ret;
201
202 /* use value here */
203 assert(value == 42);
204
205 return ret;
206 }
207
208BPF_MAP_TYPE_PERCPU_ARRAY
209~~~~~~~~~~~~~~~~~~~~~~~~~
210
211This snippet shows how to initialize the elements of a per CPU array.
212
213.. code-block:: c
214
215 int initialize_array(int fd)
216 {
217 int ncpus = libbpf_num_possible_cpus();
218 long values[ncpus];
219 __u32 i, j;
220 int ret;
221
222 for (i = 0; i < 256 ; i++) {
223 for (j = 0; j < ncpus; j++)
224 values[j] = i;
225 ret = bpf_map_update_elem(fd, &i, &values, BPF_ANY);
226 if (ret < 0)
227 return ret;
228 }
229
230 return ret;
231 }
232
233This snippet shows how to access the per CPU elements of an array value.
234
235.. code-block:: c
236
237 int lookup(int fd)
238 {
239 int ncpus = libbpf_num_possible_cpus();
240 __u32 index = 42, j;
241 long values[ncpus];
242 int ret;
243
244 ret = bpf_map_lookup_elem(fd, &index, &values);
245 if (ret < 0)
246 return ret;
247
248 for (j = 0; j < ncpus; j++) {
249 /* Use per CPU value here */
250 assert(values[j] == 42);
251 }
252
253 return ret;
254 }
255
256Semantics
257=========
258
259As shown in the example above, when accessing a ``BPF_MAP_TYPE_PERCPU_ARRAY``
260in userspace, each value is an array with ``ncpus`` elements.
261
262When calling ``bpf_map_update_elem()`` the flag ``BPF_NOEXIST`` can not be used
263for these maps.