Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
7.5 kB · 263 lines
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264.. 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 arraystorage. The key type is an unsigned 32-bit integer (4 bytes) and the map isof constant size. The size of the array is defined in ``max_entries`` atcreation time. All array elements are pre-allocated and zero initialized whencreated. ``BPF_MAP_TYPE_PERCPU_ARRAY`` uses a different memory region for eachCPU whereas ``BPF_MAP_TYPE_ARRAY`` uses the same memory region. The valuestored can be of any size for ``BPF_MAP_TYPE_ARRAY`` and not more than``PCPU_MIN_UNIT_SIZE`` (32 kB) for ``BPF_MAP_TYPE_PERCPU_ARRAY``. Allarray elements are aligned to 8 bytes.
Since kernel 5.5, memory mapping may be enabled for ``BPF_MAP_TYPE_ARRAY`` bysetting the flag ``BPF_F_MMAPABLE``. The map definition is page-aligned andstarts on the first page. Sufficient page-sized and page-aligned blocks ofmemory 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 ofusing this is increased performance and ease of use since userspace programswould 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 raceswith 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 offailure.
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 azero value to that index.
Per CPU Array-------------
Values stored in ``BPF_MAP_TYPE_ARRAY`` can be accessed by multiple programsacross 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 currentCPU.
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 arrayvalue for a specific CPU. Returns value on success , or ``NULL`` if no entry wasfound 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, withthe map identified by its ``fd``.
Examples========
Please see the ``tools/testing/selftests/bpf`` directory for functionalexamples. 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`` toset 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 usedfor these maps.