1.. SPDX-License-Identifier: GPL-2.0-only 2.. Copyright (C) 2022 Red Hat, Inc. 3 4================================================ 5BPF_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 13storage. The key type is an unsigned 32-bit integer (4 bytes) and the map is 14of constant size. The size of the array is defined in ``max_entries`` at 15creation time. All array elements are pre-allocated and zero initialized when 16created. ``BPF_MAP_TYPE_PERCPU_ARRAY`` uses a different memory region for each 17CPU whereas ``BPF_MAP_TYPE_ARRAY`` uses the same memory region. The value 18stored can be of any size, however, all array elements are aligned to 8 19bytes. 20 21Since kernel 5.5, memory mapping may be enabled for ``BPF_MAP_TYPE_ARRAY`` by 22setting the flag ``BPF_F_MMAPABLE``. The map definition is page-aligned and 23starts on the first page. Sufficient page-sized and page-aligned blocks of 24memory are allocated to store all array values, starting on the second page, 25which in some cases will result in over-allocation of memory. The benefit of 26using this is increased performance and ease of use since userspace programs 27would not be required to use helper functions to access and mutate data. 28 29Usage 30===== 31 32Kernel BPF 33---------- 34 35.. c:function:: 36 void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) 37 38Array elements can be retrieved using the ``bpf_map_lookup_elem()`` helper. 39This helper returns a pointer into the array element, so to avoid data races 40with userspace reading the value, the user must use primitives like 41``__sync_fetch_and_add()`` when updating the value in-place. 42 43.. c:function:: 44 long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) 45 46Array elements can be updated using the ``bpf_map_update_elem()`` helper. 47 48``bpf_map_update_elem()`` returns 0 on success, or negative error in case of 49failure. 50 51Since the array is of constant size, ``bpf_map_delete_elem()`` is not supported. 52To clear an array element, you may use ``bpf_map_update_elem()`` to insert a 53zero value to that index. 54 55Per CPU Array 56~~~~~~~~~~~~~ 57 58Values stored in ``BPF_MAP_TYPE_ARRAY`` can be accessed by multiple programs 59across different CPUs. To restrict storage to a single CPU, you may use a 60``BPF_MAP_TYPE_PERCPU_ARRAY``. 61 62When using a ``BPF_MAP_TYPE_PERCPU_ARRAY`` the ``bpf_map_update_elem()`` and 63``bpf_map_lookup_elem()`` helpers automatically access the slot for the current 64CPU. 65 66.. c:function:: 67 void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) 68 69The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the array 70value for a specific CPU. Returns value on success , or ``NULL`` if no entry was 71found or ``cpu`` is invalid. 72 73Concurrency 74----------- 75 76Since kernel version 5.1, the BPF infrastructure provides ``struct bpf_spin_lock`` 77to synchronize access. 78 79Userspace 80--------- 81 82Access from userspace uses libbpf APIs with the same names as above, with 83the map identified by its ``fd``. 84 85Examples 86======== 87 88Please see the ``tools/testing/selftests/bpf`` directory for functional 89examples. The code samples below demonstrate API usage. 90 91Kernel BPF 92---------- 93 94This snippet shows how to declare an array in a BPF program. 95 96.. code-block:: c 97 98 struct { 99 __uint(type, BPF_MAP_TYPE_ARRAY); 100 __type(key, u32); 101 __type(value, long); 102 __uint(max_entries, 256); 103 } my_map SEC(".maps"); 104 105 106This example BPF program shows how to access an array element. 107 108.. code-block:: c 109 110 int bpf_prog(struct __sk_buff *skb) 111 { 112 struct iphdr ip; 113 int index; 114 long *value; 115 116 if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip, sizeof(ip)) < 0) 117 return 0; 118 119 index = ip.protocol; 120 value = bpf_map_lookup_elem(&my_map, &index); 121 if (value) 122 __sync_fetch_and_add(&value, skb->len); 123 124 return 0; 125 } 126 127Userspace 128--------- 129 130BPF_MAP_TYPE_ARRAY 131~~~~~~~~~~~~~~~~~~ 132 133This snippet shows how to create an array, using ``bpf_map_create_opts`` to 134set flags. 135 136.. code-block:: c 137 138 #include <bpf/libbpf.h> 139 #include <bpf/bpf.h> 140 141 int create_array() 142 { 143 int fd; 144 LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE); 145 146 fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, 147 "example_array", /* name */ 148 sizeof(__u32), /* key size */ 149 sizeof(long), /* value size */ 150 256, /* max entries */ 151 &opts); /* create opts */ 152 return fd; 153 } 154 155This snippet shows how to initialize the elements of an array. 156 157.. code-block:: c 158 159 int initialize_array(int fd) 160 { 161 __u32 i; 162 long value; 163 int ret; 164 165 for (i = 0; i < 256; i++) { 166 value = i; 167 ret = bpf_map_update_elem(fd, &i, &value, BPF_ANY); 168 if (ret < 0) 169 return ret; 170 } 171 172 return ret; 173 } 174 175This snippet shows how to retrieve an element value from an array. 176 177.. code-block:: c 178 179 int lookup(int fd) 180 { 181 __u32 index = 42; 182 long value; 183 int ret; 184 185 ret = bpf_map_lookup_elem(fd, &index, &value); 186 if (ret < 0) 187 return ret; 188 189 /* use value here */ 190 assert(value == 42); 191 192 return ret; 193 } 194 195BPF_MAP_TYPE_PERCPU_ARRAY 196~~~~~~~~~~~~~~~~~~~~~~~~~ 197 198This snippet shows how to initialize the elements of a per CPU array. 199 200.. code-block:: c 201 202 int initialize_array(int fd) 203 { 204 int ncpus = libbpf_num_possible_cpus(); 205 long values[ncpus]; 206 __u32 i, j; 207 int ret; 208 209 for (i = 0; i < 256 ; i++) { 210 for (j = 0; j < ncpus; j++) 211 values[j] = i; 212 ret = bpf_map_update_elem(fd, &i, &values, BPF_ANY); 213 if (ret < 0) 214 return ret; 215 } 216 217 return ret; 218 } 219 220This snippet shows how to access the per CPU elements of an array value. 221 222.. code-block:: c 223 224 int lookup(int fd) 225 { 226 int ncpus = libbpf_num_possible_cpus(); 227 __u32 index = 42, j; 228 long values[ncpus]; 229 int ret; 230 231 ret = bpf_map_lookup_elem(fd, &index, &values); 232 if (ret < 0) 233 return ret; 234 235 for (j = 0; j < ncpus; j++) { 236 /* Use per CPU value here */ 237 assert(values[j] == 42); 238 } 239 240 return ret; 241 } 242 243Semantics 244========= 245 246As shown in the example above, when accessing a ``BPF_MAP_TYPE_PERCPU_ARRAY`` 247in userspace, each value is an array with ``ncpus`` elements. 248 249When calling ``bpf_map_update_elem()`` the flag ``BPF_NOEXIST`` can not be used 250for these maps. 251