1.. SPDX-License-Identifier: GPL-2.0-only
2.. Copyright (C) 2022 Red Hat, Inc.
3
4===============================================
5BPF_MAP_TYPE_HASH, with PERCPU and LRU Variants
6===============================================
7
8.. note::
9   - ``BPF_MAP_TYPE_HASH`` was introduced in kernel version 3.19
10   - ``BPF_MAP_TYPE_PERCPU_HASH`` was introduced in version 4.6
11   - Both ``BPF_MAP_TYPE_LRU_HASH`` and ``BPF_MAP_TYPE_LRU_PERCPU_HASH``
12     were introduced in version 4.10
13
14``BPF_MAP_TYPE_HASH`` and ``BPF_MAP_TYPE_PERCPU_HASH`` provide general
15purpose hash map storage. Both the key and the value can be structs,
16allowing for composite keys and values.
17
18The kernel is responsible for allocating and freeing key/value pairs, up
19to the max_entries limit that you specify. Hash maps use pre-allocation
20of hash table elements by default. The ``BPF_F_NO_PREALLOC`` flag can be
21used to disable pre-allocation when it is too memory expensive.
22
23``BPF_MAP_TYPE_PERCPU_HASH`` provides a separate value slot per
24CPU. The per-cpu values are stored internally in an array.
25
26The ``BPF_MAP_TYPE_LRU_HASH`` and ``BPF_MAP_TYPE_LRU_PERCPU_HASH``
27variants add LRU semantics to their respective hash tables. An LRU hash
28will automatically evict the least recently used entries when the hash
29table reaches capacity. An LRU hash maintains an internal LRU list that
30is used to select elements for eviction. This internal LRU list is
31shared across CPUs but it is possible to request a per CPU LRU list with
32the ``BPF_F_NO_COMMON_LRU`` flag when calling ``bpf_map_create``.
33
34Usage
35=====
36
37.. c:function::
38   long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)
39
40Hash entries can be added or updated using the ``bpf_map_update_elem()``
41helper. This helper replaces existing elements atomically. The ``flags``
42parameter can be used to control the update behaviour:
43
44- ``BPF_ANY`` will create a new element or update an existing element
45- ``BPF_NOEXIST`` will create a new element only if one did not already
46  exist
47- ``BPF_EXIST`` will update an existing element
48
49``bpf_map_update_elem()`` returns 0 on success, or negative error in
50case of failure.
51
52.. c:function::
53   void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
54
55Hash entries can be retrieved using the ``bpf_map_lookup_elem()``
56helper. This helper returns a pointer to the value associated with
57``key``, or ``NULL`` if no entry was found.
58
59.. c:function::
60   long bpf_map_delete_elem(struct bpf_map *map, const void *key)
61
62Hash entries can be deleted using the ``bpf_map_delete_elem()``
63helper. This helper will return 0 on success, or negative error in case
64of failure.
65
66Per CPU Hashes
67--------------
68
69For ``BPF_MAP_TYPE_PERCPU_HASH`` and ``BPF_MAP_TYPE_LRU_PERCPU_HASH``
70the ``bpf_map_update_elem()`` and ``bpf_map_lookup_elem()`` helpers
71automatically access the hash slot for the current CPU.
72
73.. c:function::
74   void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu)
75
76The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the
77value in the hash slot for a specific CPU. Returns value associated with
78``key`` on ``cpu`` , or ``NULL`` if no entry was found or ``cpu`` is
79invalid.
80
81Concurrency
82-----------
83
84Values stored in ``BPF_MAP_TYPE_HASH`` can be accessed concurrently by
85programs running on different CPUs.  Since Kernel version 5.1, the BPF
86infrastructure provides ``struct bpf_spin_lock`` to synchronise access.
87See ``tools/testing/selftests/bpf/progs/test_spin_lock.c``.
88
89Userspace
90---------
91
92.. c:function::
93   int bpf_map_get_next_key(int fd, const void *cur_key, void *next_key)
94
95In userspace, it is possible to iterate through the keys of a hash using
96libbpf's ``bpf_map_get_next_key()`` function. The first key can be fetched by
97calling ``bpf_map_get_next_key()`` with ``cur_key`` set to
98``NULL``. Subsequent calls will fetch the next key that follows the
99current key. ``bpf_map_get_next_key()`` returns 0 on success, -ENOENT if
100cur_key is the last key in the hash, or negative error in case of
101failure.
102
103Note that if ``cur_key`` gets deleted then ``bpf_map_get_next_key()``
104will instead return the *first* key in the hash table which is
105undesirable. It is recommended to use batched lookup if there is going
106to be key deletion intermixed with ``bpf_map_get_next_key()``.
107
108Examples
109========
110
111Please see the ``tools/testing/selftests/bpf`` directory for functional
112examples.  The code snippets below demonstrates API usage.
113
114This example shows how to declare an LRU Hash with a struct key and a
115struct value.
116
117.. code-block:: c
118
119    #include <linux/bpf.h>
120    #include <bpf/bpf_helpers.h>
121
122    struct key {
123        __u32 srcip;
124    };
125
126    struct value {
127        __u64 packets;
128        __u64 bytes;
129    };
130
131    struct {
132            __uint(type, BPF_MAP_TYPE_LRU_HASH);
133            __uint(max_entries, 32);
134            __type(key, struct key);
135            __type(value, struct value);
136    } packet_stats SEC(".maps");
137
138This example shows how to create or update hash values using atomic
139instructions:
140
141.. code-block:: c
142
143    static void update_stats(__u32 srcip, int bytes)
144    {
145            struct key key = {
146                    .srcip = srcip,
147            };
148            struct value *value = bpf_map_lookup_elem(&packet_stats, &key);
149
150            if (value) {
151                    __sync_fetch_and_add(&value->packets, 1);
152                    __sync_fetch_and_add(&value->bytes, bytes);
153            } else {
154                    struct value newval = { 1, bytes };
155
156                    bpf_map_update_elem(&packet_stats, &key, &newval, BPF_NOEXIST);
157            }
158    }
159
160Userspace walking the map elements from the map declared above:
161
162.. code-block:: c
163
164    #include <bpf/libbpf.h>
165    #include <bpf/bpf.h>
166
167    static void walk_hash_elements(int map_fd)
168    {
169            struct key *cur_key = NULL;
170            struct key next_key;
171            struct value value;
172            int err;
173
174            for (;;) {
175                    err = bpf_map_get_next_key(map_fd, cur_key, &next_key);
176                    if (err)
177                            break;
178
179                    bpf_map_lookup_elem(map_fd, &next_key, &value);
180
181                    // Use key and value here
182
183                    cur_key = &next_key;
184            }
185    }
186