xref: /openbmc/linux/Documentation/bpf/map_cpumap.rst (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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