From: Donald Hunter <donald.hunter@gmail.com>
To: bpf@vger.kernel.org, linux-doc@vger.kernel.org
Cc: dave@dtucker.co.uk, Donald Hunter <donald.hunter@gmail.com>
Subject: [PATCH bpf-next v5 1/1] bpf, docs: document BPF_MAP_TYPE_ARRAY
Date: Tue, 4 Oct 2022 17:19:29 +0100 [thread overview]
Message-ID: <20221004161929.52609-2-donald.hunter@gmail.com> (raw)
In-Reply-To: <20221004161929.52609-1-donald.hunter@gmail.com>
From: Dave Tucker <dave@dtucker.co.uk>
Add documentation for the BPF_MAP_TYPE_ARRAY including kernel version
introduced, usage and examples. Also documents BPF_MAP_TYPE_PERCPU_ARRAY
since this is similar.
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
Signed-off-by: Donald Hunter <donald.hunter@gmail.com>
---
Documentation/bpf/map_array.rst | 217 ++++++++++++++++++++++++++++++++
1 file changed, 217 insertions(+)
create mode 100644 Documentation/bpf/map_array.rst
diff --git a/Documentation/bpf/map_array.rst b/Documentation/bpf/map_array.rst
new file mode 100644
index 000000000000..5eec4c99fda5
--- /dev/null
+++ b/Documentation/bpf/map_array.rst
@@ -0,0 +1,217 @@
+.. 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. 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 maximum
+size of an array, defined in max_entries, is limited to 2^32. The value stored
+can be of any size, however, small values will be rounded up 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
+=====
+
+.. c:function::
+ 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. Access from
+userspace uses the libbpf API of the same name.
+
+.. c:function::
+ long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)
+
+Array elements can also be added using the ``bpf_map_update_elem()`` helper or
+libbpf API.
+
+``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 hash slot for the
+current CPU.
+
+.. c:function::
+ 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.
+
+Examples
+========
+
+Please see the ``tools/testing/selftests/bpf`` directory for functional
+examples. The sample code below demonstrates API usage.
+
+Kernel
+------
+
+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 shows how to access an array element.
+
+.. code-block:: c
+
+ int bpf_prog(struct __sk_buff *skb)
+ {
+ int index = load_byte(skb,
+ ETH_HLEN + offsetof(struct iphdr, protocol));
+ long *value;
+
+ if (skb->pkt_type != PACKET_OUTGOING)
+ return 0;
+
+ 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 example shows array creation, initialisation and lookup from userspace.
+
+.. code-block:: c
+
+ #include <assert.h>
+ #include <bpf/libbpf.h>
+ #include <bpf/bpf.h>
+
+ int main(int argc, char **argv)
+ {
+ int fd;
+ int ret = 0;
+ long value;
+ __u32 index = 42;
+ __u32 i;
+
+ fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "example_array",
+ sizeof(__u32), sizeof(long),
+ 256, 0);
+ if (fd < 0)
+ return fd;
+
+ /* fill the map with values from 0-255 */
+ for (i = 0; i < 256 ; i++) {
+ value = i;
+ ret = bpf_map_update_elem(fd, &i, &value, BPF_ANY);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = bpf_map_lookup_elem(fd, &index, &value);
+ if (ret < 0)
+ return ret;
+
+ assert(value == 42);
+
+ return ret;
+ }
+
+BPF_MAP_TYPE_PERCPU_ARRAY
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows per CPU array usage.
+
+.. code-block:: c
+
+ #include <assert.h>
+ #include <bpf/libbpf.h>
+ #include <bpf/bpf.h>
+
+ int main(int argc, char **argv)
+ {
+ int ncpus = libbpf_num_possible_cpus();
+ if (ncpus < 0)
+ return ncpus;
+
+ int fd;
+ int ret = 0;
+ __u32 i, j;
+ __u32 index = 42;
+ long v[ncpus], value[ncpus];
+
+ fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "example_percpu",
+ sizeof(__u32), sizeof(long), 256, 0);
+ if (fd < 0)
+ return -1;
+
+ /* fill the map with values from 0-255 for each cpu */
+ for (i = 0; i < 256 ; i++) {
+ for (j = 0; j < ncpus; j++)
+ v[j] = i;
+ ret = bpf_map_update_elem(fd, &i, &v, BPF_ANY);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = bpf_map_lookup_elem(fd, &index, &value);
+ if (ret < 0)
+ return ret;
+
+ for (j = 0; j < ncpus; j++)
+ assert(value[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.
--
2.35.1
next prev parent reply other threads:[~2022-10-04 16:20 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-04 16:19 [PATCH bpf-next v5 0/1] Document BPF_MAP_TYPE_ARRAY Donald Hunter
2022-10-04 16:19 ` Donald Hunter [this message]
2022-10-05 7:32 ` [PATCH bpf-next v5 1/1] bpf, docs: document BPF_MAP_TYPE_ARRAY Bagas Sanjaya
2022-10-05 10:12 ` Donald Hunter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221004161929.52609-2-donald.hunter@gmail.com \
--to=donald.hunter@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=dave@dtucker.co.uk \
--cc=linux-doc@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.