xref: /openbmc/linux/Documentation/bpf/map_of_maps.rst (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1f720b848SDonald Hunter.. SPDX-License-Identifier: GPL-2.0-only
2f720b848SDonald Hunter.. Copyright (C) 2022 Red Hat, Inc.
3f720b848SDonald Hunter
4f720b848SDonald Hunter========================================================
5f720b848SDonald HunterBPF_MAP_TYPE_ARRAY_OF_MAPS and BPF_MAP_TYPE_HASH_OF_MAPS
6f720b848SDonald Hunter========================================================
7f720b848SDonald Hunter
8f720b848SDonald Hunter.. note::
9f720b848SDonald Hunter   - ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` and ``BPF_MAP_TYPE_HASH_OF_MAPS`` were
10f720b848SDonald Hunter     introduced in kernel version 4.12
11f720b848SDonald Hunter
12f720b848SDonald Hunter``BPF_MAP_TYPE_ARRAY_OF_MAPS`` and ``BPF_MAP_TYPE_HASH_OF_MAPS`` provide general
13f720b848SDonald Hunterpurpose support for map in map storage. One level of nesting is supported, where
14f720b848SDonald Hunteran outer map contains instances of a single type of inner map, for example
15f720b848SDonald Hunter``array_of_maps->sock_map``.
16f720b848SDonald Hunter
17f720b848SDonald HunterWhen creating an outer map, an inner map instance is used to initialize the
18f720b848SDonald Huntermetadata that the outer map holds about its inner maps. This inner map has a
19f720b848SDonald Hunterseparate lifetime from the outer map and can be deleted after the outer map has
20f720b848SDonald Hunterbeen created.
21f720b848SDonald Hunter
22f720b848SDonald HunterThe outer map supports element lookup, update and delete from user space using
23f720b848SDonald Hunterthe syscall API. A BPF program is only allowed to do element lookup in the outer
24f720b848SDonald Huntermap.
25f720b848SDonald Hunter
26f720b848SDonald Hunter.. note::
27f720b848SDonald Hunter   - Multi-level nesting is not supported.
28f720b848SDonald Hunter   - Any BPF map type can be used as an inner map, except for
29f720b848SDonald Hunter     ``BPF_MAP_TYPE_PROG_ARRAY``.
30f720b848SDonald Hunter   - A BPF program cannot update or delete outer map entries.
31f720b848SDonald Hunter
32f720b848SDonald HunterFor ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` the key is an unsigned 32-bit integer index
33f720b848SDonald Hunterinto the array. The array is a fixed size with ``max_entries`` elements that are
34f720b848SDonald Hunterzero initialized when created.
35f720b848SDonald Hunter
36f720b848SDonald HunterFor ``BPF_MAP_TYPE_HASH_OF_MAPS`` the key type can be chosen when defining the
37f720b848SDonald Huntermap. The kernel is responsible for allocating and freeing key/value pairs, up to
38f720b848SDonald Hunterthe max_entries limit that you specify. Hash maps use pre-allocation of hash
39f720b848SDonald Huntertable elements by default. The ``BPF_F_NO_PREALLOC`` flag can be used to disable
40f720b848SDonald Hunterpre-allocation when it is too memory expensive.
41f720b848SDonald Hunter
42f720b848SDonald HunterUsage
43f720b848SDonald Hunter=====
44f720b848SDonald Hunter
45f720b848SDonald HunterKernel BPF Helper
46f720b848SDonald Hunter-----------------
47f720b848SDonald Hunter
48*539886a3SDonald Hunterbpf_map_lookup_elem()
49*539886a3SDonald Hunter~~~~~~~~~~~~~~~~~~~~~
50*539886a3SDonald Hunter
51*539886a3SDonald Hunter.. code-block:: c
52*539886a3SDonald Hunter
53f720b848SDonald Hunter   void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
54f720b848SDonald Hunter
55f720b848SDonald HunterInner maps can be retrieved using the ``bpf_map_lookup_elem()`` helper. This
56f720b848SDonald Hunterhelper returns a pointer to the inner map, or ``NULL`` if no entry was found.
57f720b848SDonald Hunter
58f720b848SDonald HunterExamples
59f720b848SDonald Hunter========
60f720b848SDonald Hunter
61f720b848SDonald HunterKernel BPF Example
62f720b848SDonald Hunter------------------
63f720b848SDonald Hunter
64f720b848SDonald HunterThis snippet shows how to create and initialise an array of devmaps in a BPF
65f720b848SDonald Hunterprogram. Note that the outer array can only be modified from user space using
66f720b848SDonald Hunterthe syscall API.
67f720b848SDonald Hunter
68f720b848SDonald Hunter.. code-block:: c
69f720b848SDonald Hunter
70f720b848SDonald Hunter    struct inner_map {
71f720b848SDonald Hunter            __uint(type, BPF_MAP_TYPE_DEVMAP);
72f720b848SDonald Hunter            __uint(max_entries, 10);
73f720b848SDonald Hunter            __type(key, __u32);
74f720b848SDonald Hunter            __type(value, __u32);
75f720b848SDonald Hunter    } inner_map1 SEC(".maps"), inner_map2 SEC(".maps");
76f720b848SDonald Hunter
77f720b848SDonald Hunter    struct {
78f720b848SDonald Hunter            __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
79f720b848SDonald Hunter            __uint(max_entries, 2);
80f720b848SDonald Hunter            __type(key, __u32);
81f720b848SDonald Hunter            __array(values, struct inner_map);
82f720b848SDonald Hunter    } outer_map SEC(".maps") = {
83f720b848SDonald Hunter            .values = { &inner_map1,
84f720b848SDonald Hunter                        &inner_map2 }
85f720b848SDonald Hunter    };
86f720b848SDonald Hunter
87f720b848SDonald HunterSee ``progs/test_btf_map_in_map.c`` in ``tools/testing/selftests/bpf`` for more
88f720b848SDonald Hunterexamples of declarative initialisation of outer maps.
89f720b848SDonald Hunter
90f720b848SDonald HunterUser Space
91f720b848SDonald Hunter----------
92f720b848SDonald Hunter
93f720b848SDonald HunterThis snippet shows how to create an array based outer map:
94f720b848SDonald Hunter
95f720b848SDonald Hunter.. code-block:: c
96f720b848SDonald Hunter
97f720b848SDonald Hunter    int create_outer_array(int inner_fd) {
98f720b848SDonald Hunter            LIBBPF_OPTS(bpf_map_create_opts, opts, .inner_map_fd = inner_fd);
99f720b848SDonald Hunter            int fd;
100f720b848SDonald Hunter
101f720b848SDonald Hunter            fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS,
102f720b848SDonald Hunter                                "example_array",       /* name */
103f720b848SDonald Hunter                                sizeof(__u32),         /* key size */
104f720b848SDonald Hunter                                sizeof(__u32),         /* value size */
105f720b848SDonald Hunter                                256,                   /* max entries */
106f720b848SDonald Hunter                                &opts);                /* create opts */
107f720b848SDonald Hunter            return fd;
108f720b848SDonald Hunter    }
109f720b848SDonald Hunter
110f720b848SDonald Hunter
111f720b848SDonald HunterThis snippet shows how to add an inner map to an outer map:
112f720b848SDonald Hunter
113f720b848SDonald Hunter.. code-block:: c
114f720b848SDonald Hunter
115f720b848SDonald Hunter    int add_devmap(int outer_fd, int index, const char *name) {
116f720b848SDonald Hunter            int fd;
117f720b848SDonald Hunter
118f720b848SDonald Hunter            fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, name,
119f720b848SDonald Hunter                                sizeof(__u32), sizeof(__u32), 256, NULL);
120f720b848SDonald Hunter            if (fd < 0)
121f720b848SDonald Hunter                    return fd;
122f720b848SDonald Hunter
123f720b848SDonald Hunter            return bpf_map_update_elem(outer_fd, &index, &fd, BPF_ANY);
124f720b848SDonald Hunter    }
125f720b848SDonald Hunter
126f720b848SDonald HunterReferences
127f720b848SDonald Hunter==========
128f720b848SDonald Hunter
129f720b848SDonald Hunter- https://lore.kernel.org/netdev/20170322170035.923581-3-kafai@fb.com/
130f720b848SDonald Hunter- https://lore.kernel.org/netdev/20170322170035.923581-4-kafai@fb.com/
131