[sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget"/translations/zh_CN/bpf/map_cpumapmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget"/translations/zh_TW/bpf/map_cpumapmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget"/translations/it_IT/bpf/map_cpumapmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget"/translations/ja_JP/bpf/map_cpumapmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget"/translations/ko_KR/bpf/map_cpumapmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget"/translations/sp_SP/bpf/map_cpumapmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhcomment)}(h%SPDX-License-Identifier: GPL-2.0-onlyh]h%SPDX-License-Identifier: GPL-2.0-only}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhhlong bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)h]h>long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)}hjsbah}(h]h ]h"]h$]h&]hhforcelanguagechighlight_args}uh1jhhhK#hjhhubh)}(hRedirect the packet to the endpoint referenced by ``map`` at index ``key``. For ``BPF_MAP_TYPE_CPUMAP`` this map contains references to CPUs.h](h2Redirect the packet to the endpoint referenced by }(hjhhhNhNubh)}(h``map``h]hmap}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh at index }(hjhhhNhNubh)}(h``key``h]hkey}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh. For }(hjhhhNhNubh)}(h``BPF_MAP_TYPE_CPUMAP``h]hBPF_MAP_TYPE_CPUMAP}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh& this map contains references to CPUs.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK'hjhhubh)}(hThe lower two bits of ``flags`` are used as the return code if the map lookup fails. This is so that the return value can be one of the XDP program return codes up to ``XDP_TX``, as chosen by the caller.h](hThe lower two bits of }(hjhhhNhNubh)}(h ``flags``h]hflags}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh are used as the return code if the map lookup fails. This is so that the return value can be one of the XDP program return codes up to }(hjhhhNhNubh)}(h ``XDP_TX``h]hXDP_TX}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh, as chosen by the caller.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK*hjhhubeh}(h]bpf-redirect-mapah ]h"]bpf_redirect_map()ah$]h&]uh1hhjhhhhhK"ubeh}(h] kernel-bpfah ]h"] kernel bpfah$]h&]uh1hhjuhhhhhK ubh)}(hhh](h)}(h User spaceh]h User space}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjChhhhhK/ubh)}(hCPUMAP entries can only be updated/looked up/deleted from user space and not from an eBPF program. Trying to call these functions from a kernel eBPF program will result in the program failing to load and a verifier warning.h]h)}(hCPUMAP entries can only be updated/looked up/deleted from user space and not from an eBPF program. Trying to call these functions from a kernel eBPF program will result in the program failing to load and a verifier warning.h]hCPUMAP entries can only be updated/looked up/deleted from user space and not from an eBPF program. Trying to call these functions from a kernel eBPF program will result in the program failing to load and a verifier warning.}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK1hjTubah}(h]h ]h"]h$]h&]uh1hhjChhhhhNubh)}(hhh](h)}(hbpf_map_update_elem()h]hbpf_map_update_elem()}(hjohhhNhNubah}(h]h ]h"]h$]h&]uh1hhjlhhhhhK6ubj)}(hQint bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags);h]hQint bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags);}hj}sbah}(h]h ]h"]h$]h&]hhjjjj}uh1jhhhK7hjlhhubh)}(hCPU entries can be added or updated using the ``bpf_map_update_elem()`` helper. This helper replaces existing elements atomically. The ``value`` parameter can be ``struct bpf_cpumap_val``.h](h.CPU entries can be added or updated using the }(hjhhhNhNubh)}(h``bpf_map_update_elem()``h]hbpf_map_update_elem()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh@ helper. This helper replaces existing elements atomically. The }(hjhhhNhNubh)}(h ``value``h]hvalue}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh parameter can be }(hjhhhNhNubh)}(h``struct bpf_cpumap_val``h]hstruct bpf_cpumap_val}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK;hjlhhubh block_quote)}(h.. code-block:: c struct bpf_cpumap_val { __u32 qsize; /* queue size to remote target CPU */ union { int fd; /* prog fd on map write */ __u32 id; /* prog id on map read */ } bpf_prog; }; h]j)}(hstruct bpf_cpumap_val { __u32 qsize; /* queue size to remote target CPU */ union { int fd; /* prog fd on map write */ __u32 id; /* prog id on map read */ } bpf_prog; };h]hstruct bpf_cpumap_val { __u32 qsize; /* queue size to remote target CPU */ union { int fd; /* prog fd on map write */ __u32 id; /* prog id on map read */ } bpf_prog; };}hjsbah}(h]h ]h"]h$]h&]hhjjjj}uh1jhhhK?hjubah}(h]h ]h"]h$]h&]uh1jhhhK?hjlhhubhdefinition_list)}(hhh]hdefinition_list_item)}(hThe flags argument can be one of the following: - BPF_ANY: Create a new element or update an existing element. - BPF_NOEXIST: Create a new element only if it did not exist. - BPF_EXIST: Update an existing element. h](hterm)}(h/The flags argument can be one of the following:h]h/The flags argument can be one of the following:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKLhjubh definition)}(hhh]h)}(hhh](h)}(hint bpf_map_lookup_elem(int fd, const void *key, void *value);h]h>int bpf_map_lookup_elem(int fd, const void *key, void *value);}hjsbah}(h]h ]h"]h$]h&]hhjjjj}uh1jhhhKPhjthhubh)}(hHCPU entries can be retrieved using the ``bpf_map_lookup_elem()`` helper.h](h'CPU entries can be retrieved using the }(hjhhhNhNubh)}(h``bpf_map_lookup_elem()``h]hbpf_map_lookup_elem()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubh helper.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKThjthhubeh}(h]bpf-map-lookup-elemah ]h"]bpf_map_lookup_elem()ah$]h&]uh1hhjChhhhhKOubh)}(hhh](h)}(hbpf_map_delete_elem()h]hbpf_map_delete_elem()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKXubj)}(h1int bpf_map_delete_elem(int fd, const void *key);h]h1int bpf_map_delete_elem(int fd, const void *key);}hjsbah}(h]h ]h"]h$]h&]hhjjjj}uh1jhhhKYhjhhubh)}(hCPU entries can be deleted using the ``bpf_map_delete_elem()`` helper. This helper will return 0 on success, or negative error in case of failure.h](h%CPU entries can be deleted using the }(hjhhhNhNubh)}(h``bpf_map_delete_elem()``h]hbpf_map_delete_elem()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubhT helper. This helper will return 0 on success, or negative error in case of failure.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK]hjhhubeh}(h]bpf-map-delete-elemah ]h"]bpf_map_delete_elem()ah$]h&]uh1hhjChhhhhKXubeh}(h] user-spaceah ]h"]h$] user spaceah&]uh1hhjuhhhhhK/ referencedKubeh}(h]usageah ]h"]usageah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hExamplesh]hExamples}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKbubh)}(hhh](h)}(hKernelh]hKernel}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj&hhhhhKdubh)}(hThe following code snippet shows how to declare a ``BPF_MAP_TYPE_CPUMAP`` called ``cpu_map`` and how to redirect packets to a remote CPU using a round robin scheme.h](h2The following code snippet shows how to declare a }(hj7hhhNhNubh)}(h``BPF_MAP_TYPE_CPUMAP``h]hBPF_MAP_TYPE_CPUMAP}(hj?hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj7ubh called }(hj7hhhNhNubh)}(h ``cpu_map``h]hcpu_map}(hjQhhhNhNubah}(h]h ]h"]h$]h&]uh1hhj7ubhH and how to redirect packets to a remote CPU using a round robin scheme.}(hj7hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKfhj&hhubj)}(hXstruct { __uint(type, BPF_MAP_TYPE_CPUMAP); __type(key, __u32); __type(value, struct bpf_cpumap_val); __uint(max_entries, 12); } cpu_map SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_ARRAY); __type(key, __u32); __type(value, __u32); __uint(max_entries, 12); } cpus_available SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __type(key, __u32); __type(value, __u32); __uint(max_entries, 1); } cpus_iterator SEC(".maps"); SEC("xdp") int xdp_redir_cpu_round_robin(struct xdp_md *ctx) { __u32 key = 0; __u32 cpu_dest = 0; __u32 *cpu_selected, *cpu_iterator; __u32 cpu_idx; cpu_iterator = bpf_map_lookup_elem(&cpus_iterator, &key); if (!cpu_iterator) return XDP_ABORTED; cpu_idx = *cpu_iterator; *cpu_iterator += 1; if (*cpu_iterator == bpf_num_possible_cpus()) *cpu_iterator = 0; cpu_selected = bpf_map_lookup_elem(&cpus_available, &cpu_idx); if (!cpu_selected) return XDP_ABORTED; cpu_dest = *cpu_selected; if (cpu_dest >= bpf_num_possible_cpus()) return XDP_ABORTED; return bpf_redirect_map(&cpu_map, cpu_dest, 0); }h]hXstruct { __uint(type, BPF_MAP_TYPE_CPUMAP); __type(key, __u32); __type(value, struct bpf_cpumap_val); __uint(max_entries, 12); } cpu_map SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_ARRAY); __type(key, __u32); __type(value, __u32); __uint(max_entries, 12); } cpus_available SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __type(key, __u32); __type(value, __u32); __uint(max_entries, 1); } cpus_iterator SEC(".maps"); SEC("xdp") int xdp_redir_cpu_round_robin(struct xdp_md *ctx) { __u32 key = 0; __u32 cpu_dest = 0; __u32 *cpu_selected, *cpu_iterator; __u32 cpu_idx; cpu_iterator = bpf_map_lookup_elem(&cpus_iterator, &key); if (!cpu_iterator) return XDP_ABORTED; cpu_idx = *cpu_iterator; *cpu_iterator += 1; if (*cpu_iterator == bpf_num_possible_cpus()) *cpu_iterator = 0; cpu_selected = bpf_map_lookup_elem(&cpus_available, &cpu_idx); if (!cpu_selected) return XDP_ABORTED; cpu_dest = *cpu_selected; if (cpu_dest >= bpf_num_possible_cpus()) return XDP_ABORTED; return bpf_redirect_map(&cpu_map, cpu_dest, 0); }}hjisbah}(h]h ]h"]h$]h&]hhjjjj}uh1jhhhKihj&hhubeh}(h]kernelah ]h"]kernelah$]h&]uh1hhjhhhhhKdubh)}(hhh](h)}(h User spaceh]h User space}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hThe following code snippet shows how to dynamically set the max_entries for a CPUMAP to the max number of cpus available on the system.h]hThe following code snippet shows how to dynamically set the max_entries for a CPUMAP to the max number of cpus available on the system.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hXint set_max_cpu_entries(struct bpf_map *cpu_map) { if (bpf_map__set_max_entries(cpu_map, libbpf_num_possible_cpus()) < 0) { fprintf(stderr, "Failed to set max entries for cpu_map map: %s", strerror(errno)); return -1; } return 0; }h]hXint set_max_cpu_entries(struct bpf_map *cpu_map) { if (bpf_map__set_max_entries(cpu_map, libbpf_num_possible_cpus()) < 0) { fprintf(stderr, "Failed to set max entries for cpu_map map: %s", strerror(errno)); return -1; } return 0; }}hjsbah}(h]h ]h"]h$]h&]hhjjjj}uh1jhhhKhjhhubeh}(h]id1ah ]h"]h$]j ah&]uh1hhjhhhhhKj Kubeh}(h]examplesah ]h"]examplesah$]h&]uh1hhhhhhhhKbubh)}(hhh](h)}(h Referencesh]h References}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hhh]h)}(huhttps://developers.redhat.com/blog/2021/05/13/receive-side-scaling-rss-with-ebpf-and-cpumap#redirecting_into_a_cpumaph]h)}(hjh]h reference)}(hjh]huhttps://developers.redhat.com/blog/2021/05/13/receive-side-scaling-rss-with-ebpf-and-cpumap#redirecting_into_a_cpumap}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurijuh1jhjubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjhhhhhNubah}(h]h ]h"]h$]h&]jjuh1hhhhKhjhhubeh}(h] referencesah ]h"] referencesah$]h&]uh1hhhhhhhhKubeh}(h]bpf-map-type-cpumapah ]h"]bpf_map_type_cpumapah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj-error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(jjjjj@j=j8j5 user spaceNjqjnjjjjjjj}jzjju nametypes}(jjj@j8jqjqjjjj}juh}(jhjjuj=jj5jjjCjnjljjtjjjjjzj&jjjju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}j;KsRparse_messages]hsystem_message)}(hhh]h)}(h-Duplicate implicit target name: "user space".h]h1Duplicate implicit target name: “user space”.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]jalevelKtypeINFOsourcehlineKuh1jhjhhhhhKubatransform_messages] transformerN include_log] decorationNhhub.