| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- .. SPDX-License-Identifier: GPL-2.0-only
- .. Copyright (C) 2022 Red Hat, Inc.
- ================================================
- BPF_MAP_TYPE_ARRAY and BPF_MAP_TYPE_PERCPU_ARRAY
- ================================================
- .. note::
- - ``BPF_MAP_TYPE_ARRAY`` was introduced in kernel version 3.19
- - ``BPF_MAP_TYPE_PERCPU_ARRAY`` was introduced in version 4.6
- ``BPF_MAP_TYPE_ARRAY`` and ``BPF_MAP_TYPE_PERCPU_ARRAY`` provide generic array
- storage. The key type is an unsigned 32-bit integer (4 bytes) and the map is
- of constant size. The size of the array is defined in ``max_entries`` at
- creation time. All array elements are pre-allocated and zero initialized when
- created. ``BPF_MAP_TYPE_PERCPU_ARRAY`` uses a different memory region for each
- CPU whereas ``BPF_MAP_TYPE_ARRAY`` uses the same memory region. The value
- stored can be of any size, however, all array elements are aligned to 8
- bytes.
- Since kernel 5.5, memory mapping may be enabled for ``BPF_MAP_TYPE_ARRAY`` by
- setting the flag ``BPF_F_MMAPABLE``. The map definition is page-aligned and
- starts on the first page. Sufficient page-sized and page-aligned blocks of
- memory are allocated to store all array values, starting on the second page,
- which in some cases will result in over-allocation of memory. The benefit of
- using this is increased performance and ease of use since userspace programs
- would not be required to use helper functions to access and mutate data.
- Usage
- =====
- Kernel BPF
- ----------
- bpf_map_lookup_elem()
- ~~~~~~~~~~~~~~~~~~~~~
- .. code-block:: c
- void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
- Array elements can be retrieved using the ``bpf_map_lookup_elem()`` helper.
- This helper returns a pointer into the array element, so to avoid data races
- with userspace reading the value, the user must use primitives like
- ``__sync_fetch_and_add()`` when updating the value in-place.
- bpf_map_update_elem()
- ~~~~~~~~~~~~~~~~~~~~~
- .. code-block:: c
- long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)
- Array elements can be updated using the ``bpf_map_update_elem()`` helper.
- ``bpf_map_update_elem()`` returns 0 on success, or negative error in case of
- failure.
- Since the array is of constant size, ``bpf_map_delete_elem()`` is not supported.
- To clear an array element, you may use ``bpf_map_update_elem()`` to insert a
- zero value to that index.
- Per CPU Array
- -------------
- Values stored in ``BPF_MAP_TYPE_ARRAY`` can be accessed by multiple programs
- across different CPUs. To restrict storage to a single CPU, you may use a
- ``BPF_MAP_TYPE_PERCPU_ARRAY``.
- When using a ``BPF_MAP_TYPE_PERCPU_ARRAY`` the ``bpf_map_update_elem()`` and
- ``bpf_map_lookup_elem()`` helpers automatically access the slot for the current
- CPU.
- bpf_map_lookup_percpu_elem()
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. code-block:: c
- void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu)
- The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the array
- value for a specific CPU. Returns value on success , or ``NULL`` if no entry was
- found or ``cpu`` is invalid.
- Concurrency
- -----------
- Since kernel version 5.1, the BPF infrastructure provides ``struct bpf_spin_lock``
- to synchronize access.
- Userspace
- ---------
- Access from userspace uses libbpf APIs with the same names as above, with
- the map identified by its ``fd``.
- Examples
- ========
- Please see the ``tools/testing/selftests/bpf`` directory for functional
- examples. The code samples below demonstrate API usage.
- Kernel BPF
- ----------
- This snippet shows how to declare an array in a BPF program.
- .. code-block:: c
- struct {
- __uint(type, BPF_MAP_TYPE_ARRAY);
- __type(key, u32);
- __type(value, long);
- __uint(max_entries, 256);
- } my_map SEC(".maps");
- This example BPF program shows how to access an array element.
- .. code-block:: c
- int bpf_prog(struct __sk_buff *skb)
- {
- struct iphdr ip;
- int index;
- long *value;
- if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip, sizeof(ip)) < 0)
- return 0;
- index = ip.protocol;
- value = bpf_map_lookup_elem(&my_map, &index);
- if (value)
- __sync_fetch_and_add(value, skb->len);
- return 0;
- }
- Userspace
- ---------
- BPF_MAP_TYPE_ARRAY
- ~~~~~~~~~~~~~~~~~~
- This snippet shows how to create an array, using ``bpf_map_create_opts`` to
- set flags.
- .. code-block:: c
- #include <bpf/libbpf.h>
- #include <bpf/bpf.h>
- int create_array()
- {
- int fd;
- LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE);
- fd = bpf_map_create(BPF_MAP_TYPE_ARRAY,
- "example_array", /* name */
- sizeof(__u32), /* key size */
- sizeof(long), /* value size */
- 256, /* max entries */
- &opts); /* create opts */
- return fd;
- }
- This snippet shows how to initialize the elements of an array.
- .. code-block:: c
- int initialize_array(int fd)
- {
- __u32 i;
- long value;
- int ret;
- for (i = 0; i < 256; i++) {
- value = i;
- ret = bpf_map_update_elem(fd, &i, &value, BPF_ANY);
- if (ret < 0)
- return ret;
- }
- return ret;
- }
- This snippet shows how to retrieve an element value from an array.
- .. code-block:: c
- int lookup(int fd)
- {
- __u32 index = 42;
- long value;
- int ret;
- ret = bpf_map_lookup_elem(fd, &index, &value);
- if (ret < 0)
- return ret;
- /* use value here */
- assert(value == 42);
- return ret;
- }
- BPF_MAP_TYPE_PERCPU_ARRAY
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- This snippet shows how to initialize the elements of a per CPU array.
- .. code-block:: c
- int initialize_array(int fd)
- {
- int ncpus = libbpf_num_possible_cpus();
- long values[ncpus];
- __u32 i, j;
- int ret;
- for (i = 0; i < 256 ; i++) {
- for (j = 0; j < ncpus; j++)
- values[j] = i;
- ret = bpf_map_update_elem(fd, &i, &values, BPF_ANY);
- if (ret < 0)
- return ret;
- }
- return ret;
- }
- This snippet shows how to access the per CPU elements of an array value.
- .. code-block:: c
- int lookup(int fd)
- {
- int ncpus = libbpf_num_possible_cpus();
- __u32 index = 42, j;
- long values[ncpus];
- int ret;
- ret = bpf_map_lookup_elem(fd, &index, &values);
- if (ret < 0)
- return ret;
- for (j = 0; j < ncpus; j++) {
- /* Use per CPU value here */
- assert(values[j] == 42);
- }
- return ret;
- }
- Semantics
- =========
- As shown in the example above, when accessing a ``BPF_MAP_TYPE_PERCPU_ARRAY``
- in userspace, each value is an array with ``ncpus`` elements.
- When calling ``bpf_map_update_elem()`` the flag ``BPF_NOEXIST`` can not be used
- for these maps.
|