1161939abSMaryam Tahhan.. SPDX-License-Identifier: GPL-2.0-only 2161939abSMaryam Tahhan.. Copyright (C) 2022 Red Hat, Inc. 3161939abSMaryam Tahhan 4161939abSMaryam Tahhan=================== 5161939abSMaryam TahhanBPF_MAP_TYPE_CPUMAP 6161939abSMaryam Tahhan=================== 7161939abSMaryam Tahhan 8161939abSMaryam Tahhan.. note:: 9161939abSMaryam Tahhan - ``BPF_MAP_TYPE_CPUMAP`` was introduced in kernel version 4.15 10161939abSMaryam Tahhan 11161939abSMaryam Tahhan.. kernel-doc:: kernel/bpf/cpumap.c 12161939abSMaryam Tahhan :doc: cpu map 13161939abSMaryam Tahhan 14161939abSMaryam TahhanAn example use-case for this map type is software based Receive Side Scaling (RSS). 15161939abSMaryam Tahhan 16161939abSMaryam TahhanThe CPUMAP represents the CPUs in the system indexed as the map-key, and the 17161939abSMaryam Tahhanmap-value is the config setting (per CPUMAP entry). Each CPUMAP entry has a dedicated 18161939abSMaryam Tahhankernel thread bound to the given CPU to represent the remote CPU execution unit. 19161939abSMaryam Tahhan 20161939abSMaryam TahhanStarting from Linux kernel version 5.9 the CPUMAP can run a second XDP program 21161939abSMaryam Tahhanon the remote CPU. This allows an XDP program to split its processing across 22161939abSMaryam Tahhanmultiple CPUs. For example, a scenario where the initial CPU (that sees/receives 23161939abSMaryam Tahhanthe packets) needs to do minimal packet processing and the remote CPU (to which 24161939abSMaryam Tahhanthe packet is directed) can afford to spend more cycles processing the frame. The 25161939abSMaryam Tahhaninitial CPU is where the XDP redirect program is executed. The remote CPU 26161939abSMaryam Tahhanreceives raw ``xdp_frame`` objects. 27161939abSMaryam Tahhan 28161939abSMaryam TahhanUsage 29161939abSMaryam Tahhan===== 30161939abSMaryam Tahhan 31161939abSMaryam TahhanKernel BPF 32161939abSMaryam Tahhan---------- 33*3685b0dcSMaryam Tahhanbpf_redirect_map() 34*3685b0dcSMaryam Tahhan^^^^^^^^^^^^^^^^^^ 35*3685b0dcSMaryam Tahhan.. code-block:: c 36*3685b0dcSMaryam Tahhan 37161939abSMaryam Tahhan long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags) 38161939abSMaryam Tahhan 39161939abSMaryam TahhanRedirect the packet to the endpoint referenced by ``map`` at index ``key``. 40161939abSMaryam TahhanFor ``BPF_MAP_TYPE_CPUMAP`` this map contains references to CPUs. 41161939abSMaryam Tahhan 42161939abSMaryam TahhanThe lower two bits of ``flags`` are used as the return code if the map lookup 43161939abSMaryam Tahhanfails. This is so that the return value can be one of the XDP program return 44161939abSMaryam Tahhancodes up to ``XDP_TX``, as chosen by the caller. 45161939abSMaryam Tahhan 46161939abSMaryam TahhanUser space 47*3685b0dcSMaryam Tahhan---------- 48161939abSMaryam Tahhan.. note:: 49161939abSMaryam Tahhan CPUMAP entries can only be updated/looked up/deleted from user space and not 50161939abSMaryam Tahhan from an eBPF program. Trying to call these functions from a kernel eBPF 51161939abSMaryam Tahhan program will result in the program failing to load and a verifier warning. 52161939abSMaryam Tahhan 53*3685b0dcSMaryam Tahhanbpf_map_update_elem() 54*3685b0dcSMaryam Tahhan^^^^^^^^^^^^^^^^^^^^^ 55*3685b0dcSMaryam Tahhan.. code-block:: c 56*3685b0dcSMaryam Tahhan 57e662c775SMaryam Tahhan int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags); 58161939abSMaryam Tahhan 59161939abSMaryam TahhanCPU entries can be added or updated using the ``bpf_map_update_elem()`` 60161939abSMaryam Tahhanhelper. This helper replaces existing elements atomically. The ``value`` parameter 61161939abSMaryam Tahhancan be ``struct bpf_cpumap_val``. 62161939abSMaryam Tahhan 63161939abSMaryam Tahhan .. code-block:: c 64161939abSMaryam Tahhan 65161939abSMaryam Tahhan struct bpf_cpumap_val { 66161939abSMaryam Tahhan __u32 qsize; /* queue size to remote target CPU */ 67161939abSMaryam Tahhan union { 68161939abSMaryam Tahhan int fd; /* prog fd on map write */ 69161939abSMaryam Tahhan __u32 id; /* prog id on map read */ 70161939abSMaryam Tahhan } bpf_prog; 71161939abSMaryam Tahhan }; 72161939abSMaryam Tahhan 73161939abSMaryam TahhanThe flags argument can be one of the following: 74161939abSMaryam Tahhan - BPF_ANY: Create a new element or update an existing element. 75161939abSMaryam Tahhan - BPF_NOEXIST: Create a new element only if it did not exist. 76161939abSMaryam Tahhan - BPF_EXIST: Update an existing element. 77161939abSMaryam Tahhan 78*3685b0dcSMaryam Tahhanbpf_map_lookup_elem() 79*3685b0dcSMaryam Tahhan^^^^^^^^^^^^^^^^^^^^^ 80*3685b0dcSMaryam Tahhan.. code-block:: c 81*3685b0dcSMaryam Tahhan 82161939abSMaryam Tahhan int bpf_map_lookup_elem(int fd, const void *key, void *value); 83161939abSMaryam Tahhan 84161939abSMaryam TahhanCPU entries can be retrieved using the ``bpf_map_lookup_elem()`` 85161939abSMaryam Tahhanhelper. 86161939abSMaryam Tahhan 87*3685b0dcSMaryam Tahhanbpf_map_delete_elem() 88*3685b0dcSMaryam Tahhan^^^^^^^^^^^^^^^^^^^^^ 89*3685b0dcSMaryam Tahhan.. code-block:: c 90*3685b0dcSMaryam Tahhan 91161939abSMaryam Tahhan int bpf_map_delete_elem(int fd, const void *key); 92161939abSMaryam Tahhan 93161939abSMaryam TahhanCPU entries can be deleted using the ``bpf_map_delete_elem()`` 94161939abSMaryam Tahhanhelper. This helper will return 0 on success, or negative error in case of 95161939abSMaryam Tahhanfailure. 96161939abSMaryam Tahhan 97161939abSMaryam TahhanExamples 98161939abSMaryam Tahhan======== 99161939abSMaryam TahhanKernel 100161939abSMaryam Tahhan------ 101161939abSMaryam Tahhan 102161939abSMaryam TahhanThe following code snippet shows how to declare a ``BPF_MAP_TYPE_CPUMAP`` called 103161939abSMaryam Tahhan``cpu_map`` and how to redirect packets to a remote CPU using a round robin scheme. 104161939abSMaryam Tahhan 105161939abSMaryam Tahhan.. code-block:: c 106161939abSMaryam Tahhan 107161939abSMaryam Tahhan struct { 108161939abSMaryam Tahhan __uint(type, BPF_MAP_TYPE_CPUMAP); 109161939abSMaryam Tahhan __type(key, __u32); 110161939abSMaryam Tahhan __type(value, struct bpf_cpumap_val); 111161939abSMaryam Tahhan __uint(max_entries, 12); 112161939abSMaryam Tahhan } cpu_map SEC(".maps"); 113161939abSMaryam Tahhan 114161939abSMaryam Tahhan struct { 115161939abSMaryam Tahhan __uint(type, BPF_MAP_TYPE_ARRAY); 116161939abSMaryam Tahhan __type(key, __u32); 117161939abSMaryam Tahhan __type(value, __u32); 118161939abSMaryam Tahhan __uint(max_entries, 12); 119161939abSMaryam Tahhan } cpus_available SEC(".maps"); 120161939abSMaryam Tahhan 121161939abSMaryam Tahhan struct { 122161939abSMaryam Tahhan __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 123161939abSMaryam Tahhan __type(key, __u32); 124161939abSMaryam Tahhan __type(value, __u32); 125161939abSMaryam Tahhan __uint(max_entries, 1); 126161939abSMaryam Tahhan } cpus_iterator SEC(".maps"); 127161939abSMaryam Tahhan 128161939abSMaryam Tahhan SEC("xdp") 129161939abSMaryam Tahhan int xdp_redir_cpu_round_robin(struct xdp_md *ctx) 130161939abSMaryam Tahhan { 131161939abSMaryam Tahhan __u32 key = 0; 132161939abSMaryam Tahhan __u32 cpu_dest = 0; 133161939abSMaryam Tahhan __u32 *cpu_selected, *cpu_iterator; 134161939abSMaryam Tahhan __u32 cpu_idx; 135161939abSMaryam Tahhan 136161939abSMaryam Tahhan cpu_iterator = bpf_map_lookup_elem(&cpus_iterator, &key); 137161939abSMaryam Tahhan if (!cpu_iterator) 138161939abSMaryam Tahhan return XDP_ABORTED; 139161939abSMaryam Tahhan cpu_idx = *cpu_iterator; 140161939abSMaryam Tahhan 141161939abSMaryam Tahhan *cpu_iterator += 1; 142161939abSMaryam Tahhan if (*cpu_iterator == bpf_num_possible_cpus()) 143161939abSMaryam Tahhan *cpu_iterator = 0; 144161939abSMaryam Tahhan 145161939abSMaryam Tahhan cpu_selected = bpf_map_lookup_elem(&cpus_available, &cpu_idx); 146161939abSMaryam Tahhan if (!cpu_selected) 147161939abSMaryam Tahhan return XDP_ABORTED; 148161939abSMaryam Tahhan cpu_dest = *cpu_selected; 149161939abSMaryam Tahhan 150161939abSMaryam Tahhan if (cpu_dest >= bpf_num_possible_cpus()) 151161939abSMaryam Tahhan return XDP_ABORTED; 152161939abSMaryam Tahhan 153161939abSMaryam Tahhan return bpf_redirect_map(&cpu_map, cpu_dest, 0); 154161939abSMaryam Tahhan } 155161939abSMaryam Tahhan 156161939abSMaryam TahhanUser space 157*3685b0dcSMaryam Tahhan---------- 158161939abSMaryam Tahhan 159161939abSMaryam TahhanThe following code snippet shows how to dynamically set the max_entries for a 160161939abSMaryam TahhanCPUMAP to the max number of cpus available on the system. 161161939abSMaryam Tahhan 162161939abSMaryam Tahhan.. code-block:: c 163161939abSMaryam Tahhan 164161939abSMaryam Tahhan int set_max_cpu_entries(struct bpf_map *cpu_map) 165161939abSMaryam Tahhan { 166161939abSMaryam Tahhan if (bpf_map__set_max_entries(cpu_map, libbpf_num_possible_cpus()) < 0) { 167161939abSMaryam Tahhan fprintf(stderr, "Failed to set max entries for cpu_map map: %s", 168161939abSMaryam Tahhan strerror(errno)); 169161939abSMaryam Tahhan return -1; 170161939abSMaryam Tahhan } 171161939abSMaryam Tahhan return 0; 172161939abSMaryam Tahhan } 173161939abSMaryam Tahhan 174161939abSMaryam TahhanReferences 175161939abSMaryam Tahhan=========== 176161939abSMaryam Tahhan 177161939abSMaryam Tahhan- https://developers.redhat.com/blog/2021/05/13/receive-side-scaling-rss-with-ebpf-and-cpumap#redirecting_into_a_cpumap 178