mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-13 04:48:21 -04:00
bpf: Add array of maps support
This patch adds a few helper funcs to enable map-in-map support (i.e. outer_map->inner_map). The first outer_map type BPF_MAP_TYPE_ARRAY_OF_MAPS is also added in this patch. The next patch will introduce a hash of maps type. Any bpf map type can be acted as an inner_map. The exception is BPF_MAP_TYPE_PROG_ARRAY because the extra level of indirection makes it harder to verify the owner_prog_type and owner_jited. Multi-level map-in-map is not supported (i.e. map->map is ok but not map->map->map). When adding an inner_map to an outer_map, it currently checks the map_type, key_size, value_size, map_flags, max_entries and ops. The verifier also uses those map's properties to do static analysis. map_flags is needed because we need to ensure BPF_PROG_TYPE_PERF_EVENT is using a preallocated hashtab for the inner_hash also. ops and max_entries are needed to generate inlined map-lookup instructions. For simplicity reason, a simple '==' test is used for both map_flags and max_entries. The equality of ops is implied by the equality of map_type. During outer_map creation time, an inner_map_fd is needed to create an outer_map. However, the inner_map_fd's life time does not depend on the outer_map. The inner_map_fd is merely used to initialize the inner_map_meta of the outer_map. Also, for the outer_map: * It allows element update and delete from syscall * It allows element lookup from bpf_prog The above is similar to the current fd_array pattern. Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
fad73a1a35
commit
56f668dfe0
@@ -17,6 +17,8 @@
|
||||
#include <linux/filter.h>
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include "map_in_map.h"
|
||||
|
||||
static void bpf_array_free_percpu(struct bpf_array *array)
|
||||
{
|
||||
int i;
|
||||
@@ -602,3 +604,64 @@ static int __init register_cgroup_array_map(void)
|
||||
}
|
||||
late_initcall(register_cgroup_array_map);
|
||||
#endif
|
||||
|
||||
static struct bpf_map *array_of_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
struct bpf_map *map, *inner_map_meta;
|
||||
|
||||
inner_map_meta = bpf_map_meta_alloc(attr->inner_map_fd);
|
||||
if (IS_ERR(inner_map_meta))
|
||||
return inner_map_meta;
|
||||
|
||||
map = fd_array_map_alloc(attr);
|
||||
if (IS_ERR(map)) {
|
||||
bpf_map_meta_free(inner_map_meta);
|
||||
return map;
|
||||
}
|
||||
|
||||
map->inner_map_meta = inner_map_meta;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static void array_of_map_free(struct bpf_map *map)
|
||||
{
|
||||
/* map->inner_map_meta is only accessed by syscall which
|
||||
* is protected by fdget/fdput.
|
||||
*/
|
||||
bpf_map_meta_free(map->inner_map_meta);
|
||||
bpf_fd_array_map_clear(map);
|
||||
fd_array_map_free(map);
|
||||
}
|
||||
|
||||
static void *array_of_map_lookup_elem(struct bpf_map *map, void *key)
|
||||
{
|
||||
struct bpf_map **inner_map = array_map_lookup_elem(map, key);
|
||||
|
||||
if (!inner_map)
|
||||
return NULL;
|
||||
|
||||
return READ_ONCE(*inner_map);
|
||||
}
|
||||
|
||||
static const struct bpf_map_ops array_of_map_ops = {
|
||||
.map_alloc = array_of_map_alloc,
|
||||
.map_free = array_of_map_free,
|
||||
.map_get_next_key = array_map_get_next_key,
|
||||
.map_lookup_elem = array_of_map_lookup_elem,
|
||||
.map_delete_elem = fd_array_map_delete_elem,
|
||||
.map_fd_get_ptr = bpf_map_fd_get_ptr,
|
||||
.map_fd_put_ptr = bpf_map_fd_put_ptr,
|
||||
};
|
||||
|
||||
static struct bpf_map_type_list array_of_map_type __ro_after_init = {
|
||||
.ops = &array_of_map_ops,
|
||||
.type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
|
||||
};
|
||||
|
||||
static int __init register_array_of_map(void)
|
||||
{
|
||||
bpf_register_map_type(&array_of_map_type);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(register_array_of_map);
|
||||
|
||||
Reference in New Issue
Block a user