libbpf: Make global data internal arrays mmap()-able, if possible
authorAndrii Nakryiko <andriin@fb.com>
Sun, 17 Nov 2019 17:28:05 +0000 (09:28 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 18 Nov 2019 10:41:59 +0000 (11:41 +0100)
Add detection of BPF_F_MMAPABLE flag support for arrays and add it as an extra
flag to internal global data maps, if supported by kernel. This allows users
to memory-map global data and use it without BPF map operations, greatly
simplifying user experience.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Song Liu <songliubraving@fb.com>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20191117172806.2195367-5-andriin@fb.com
tools/lib/bpf/libbpf.c

index 7132c6b..15e91a1 100644 (file)
@@ -142,6 +142,8 @@ struct bpf_capabilities {
        __u32 btf_func:1;
        /* BTF_KIND_VAR and BTF_KIND_DATASEC support */
        __u32 btf_datasec:1;
+       /* BPF_F_MMAPABLE is supported for arrays */
+       __u32 array_mmap:1;
 };
 
 /*
@@ -857,8 +859,6 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
                pr_warn("failed to alloc map name\n");
                return -ENOMEM;
        }
-       pr_debug("map '%s' (global data): at sec_idx %d, offset %zu.\n",
-                map_name, map->sec_idx, map->sec_offset);
 
        def = &map->def;
        def->type = BPF_MAP_TYPE_ARRAY;
@@ -866,6 +866,12 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
        def->value_size = data->d_size;
        def->max_entries = 1;
        def->map_flags = type == LIBBPF_MAP_RODATA ? BPF_F_RDONLY_PROG : 0;
+       if (obj->caps.array_mmap)
+               def->map_flags |= BPF_F_MMAPABLE;
+
+       pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",
+                map_name, map->sec_idx, map->sec_offset, def->map_flags);
+
        if (data_buff) {
                *data_buff = malloc(data->d_size);
                if (!*data_buff) {
@@ -2161,6 +2167,27 @@ static int bpf_object__probe_btf_datasec(struct bpf_object *obj)
        return 0;
 }
 
+static int bpf_object__probe_array_mmap(struct bpf_object *obj)
+{
+       struct bpf_create_map_attr attr = {
+               .map_type = BPF_MAP_TYPE_ARRAY,
+               .map_flags = BPF_F_MMAPABLE,
+               .key_size = sizeof(int),
+               .value_size = sizeof(int),
+               .max_entries = 1,
+       };
+       int fd;
+
+       fd = bpf_create_map_xattr(&attr);
+       if (fd >= 0) {
+               obj->caps.array_mmap = 1;
+               close(fd);
+               return 1;
+       }
+
+       return 0;
+}
+
 static int
 bpf_object__probe_caps(struct bpf_object *obj)
 {
@@ -2169,6 +2196,7 @@ bpf_object__probe_caps(struct bpf_object *obj)
                bpf_object__probe_global_data,
                bpf_object__probe_btf_func,
                bpf_object__probe_btf_datasec,
+               bpf_object__probe_array_mmap,
        };
        int i, ret;