| 1 | |
| 2 | |
| 3 |
|
| 4 | ================================================
|
| 5 | BPF_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
|
| 13 | storage. The key type is an unsigned 32-bit integer (4 bytes) and the map is
|
| 14 | of constant size. The size of the array is defined in ``max_entries`` at
|
| 15 | creation time. All array elements are pre-allocated and zero initialized when
|
| 16 | created. ``BPF_MAP_TYPE_PERCPU_ARRAY`` uses a different memory region for each
|
| 17 | CPU whereas ``BPF_MAP_TYPE_ARRAY`` uses the same memory region. The value
|
| 18 | stored 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
|
| 20 | array elements are aligned to 8 bytes.
|
| 21 |
|
| 22 | Since kernel 5.5, memory mapping may be enabled for ``BPF_MAP_TYPE_ARRAY`` by
|
| 23 | setting the flag ``BPF_F_MMAPABLE``. The map definition is page-aligned and
|
| 24 | starts on the first page. Sufficient page-sized and page-aligned blocks of
|
| 25 | memory are allocated to store all array values, starting on the second page,
|
| 26 | which in some cases will result in over-allocation of memory. The benefit of
|
| 27 | using this is increased performance and ease of use since userspace programs
|
| 28 | would not be required to use helper functions to access and mutate data.
|
| 29 |
|
| 30 | Usage
|
| 31 | =====
|
| 32 |
|
| 33 | Kernel BPF
|
| 34 | ----------
|
| 35 |
|
| 36 | bpf_map_lookup_elem()
|
| 37 | ~~~~~~~~~~~~~~~~~~~~~
|
| 38 |
|
| 39 | .. code-block:: c
|
| 40 |
|
| 41 | void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
|
| 42 |
|
| 43 | Array elements can be retrieved using the ``bpf_map_lookup_elem()`` helper.
|
| 44 | This helper returns a pointer into the array element, so to avoid data races
|
| 45 | with userspace reading the value, the user must use primitives like
|
| 46 | ``__sync_fetch_and_add()`` when updating the value in-place.
|
| 47 |
|
| 48 | bpf_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 |
|
| 55 | Array 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
|
| 58 | failure.
|
| 59 |
|
| 60 | Since the array is of constant size, ``bpf_map_delete_elem()`` is not supported.
|
| 61 | To clear an array element, you may use ``bpf_map_update_elem()`` to insert a
|
| 62 | zero value to that index.
|
| 63 |
|
| 64 | Per CPU Array
|
| 65 | -------------
|
| 66 |
|
| 67 | Values stored in ``BPF_MAP_TYPE_ARRAY`` can be accessed by multiple programs
|
| 68 | across different CPUs. To restrict storage to a single CPU, you may use a
|
| 69 | ``BPF_MAP_TYPE_PERCPU_ARRAY``.
|
| 70 |
|
| 71 | When 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
|
| 73 | CPU.
|
| 74 |
|
| 75 | bpf_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 |
|
| 82 | The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the array
|
| 83 | value for a specific CPU. Returns value on success , or ``NULL`` if no entry was
|
| 84 | found or ``cpu`` is invalid.
|
| 85 |
|
| 86 | Concurrency
|
| 87 | -----------
|
| 88 |
|
| 89 | Since kernel version 5.1, the BPF infrastructure provides ``struct bpf_spin_lock``
|
| 90 | to synchronize access.
|
| 91 |
|
| 92 | Userspace
|
| 93 | ---------
|
| 94 |
|
| 95 | Access from userspace uses libbpf APIs with the same names as above, with
|
| 96 | the map identified by its ``fd``.
|
| 97 |
|
| 98 | Examples
|
| 99 | ========
|
| 100 |
|
| 101 | Please see the ``tools/testing/selftests/bpf`` directory for functional
|
| 102 | examples. The code samples below demonstrate API usage.
|
| 103 |
|
| 104 | Kernel BPF
|
| 105 | ----------
|
| 106 |
|
| 107 | This 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 |
|
| 119 | This 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 |
|
| 140 | Userspace
|
| 141 | ---------
|
| 142 |
|
| 143 | BPF_MAP_TYPE_ARRAY
|
| 144 | ~~~~~~~~~~~~~~~~~~
|
| 145 |
|
| 146 | This snippet shows how to create an array, using ``bpf_map_create_opts`` to
|
| 147 | set 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 |
|
| 168 | This 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 |
|
| 188 | This 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 |
|
| 208 | BPF_MAP_TYPE_PERCPU_ARRAY
|
| 209 | ~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 210 |
|
| 211 | This 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 |
|
| 233 | This 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 |
|
| 256 | Semantics
|
| 257 | =========
|
| 258 |
|
| 259 | As shown in the example above, when accessing a ``BPF_MAP_TYPE_PERCPU_ARRAY``
|
| 260 | in userspace, each value is an array with ``ncpus`` elements.
|
| 261 |
|
| 262 | When calling ``bpf_map_update_elem()`` the flag ``BPF_NOEXIST`` can not be used
|
| 263 | for these maps.
|