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