bpf, libbpf: introduce bpf_object__probe_caps to test BPF capabilities
Subsystems (4)
PATCH v3 1/3 bpf, libbpf: introduce bpf_object__probe_caps to test BPF capabilities
It currently only checks whether kernel supports map/prog names. This capability check will be used in the next two commits to skip setting prog/map names.
--- tools/lib/bpf/libbpf.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
tools/lib/bpf/libbpf.c +58 -0
@@ -24,6 +24,7 @@#include <linux/kernel.h> #include <linux/bpf.h> #include <linux/btf.h> +#include <linux/filter.h> #include <linux/list.h> #include <linux/limits.h> #include <linux/perf_event.h>
@@ -114,6 +115,11 @@ void libbpf_set_print(libbpf_print_fn_t warn,# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ#endif +struct bpf_capabilities { +/* v4.14: kernel support for program & map names. */ +__u32 name:1 ; +}; +/* * bpf_prog should be a better name but it has been used in * linux/filter.h.
@@ -160,6 +166,8 @@ struct bpf_program {void *func_info;__u32 func_info_rec_size;__u32 func_info_len; + +struct bpf_capabilities *caps; };struct bpf_map {
@@ -221,6 +229,8 @@ struct bpf_object {void *priv;bpf_object_clear_priv_t clear_priv; +struct bpf_capabilities caps; +char path[]; };#define obj_elf_valid (o) ((o)->efile.elf)
@@ -342,6 +352,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,if (err)return err; + prog.caps = &obj->caps; progs = obj->programs; nr_progs = obj->nr_programs;
@@ -1135,6 +1146,52 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)return -errno; } +static int +bpf_object__probe_name (struct bpf_object *obj) +{ +struct bpf_load_program_attr attr; +char *cp, errmsg[STRERR_BUFSIZE ]; +struct bpf_insn insns[] = { +BPF_MOV64_IMM (BPF_REG_0 ,0 ), +BPF_EXIT_INSN (), + }; +int ret; + +/* make sure basic loading works */ + +memset (&attr,0 ,sizeof (attr)); + attr.prog_type =BPF_PROG_TYPE_SOCKET_FILTER ; + attr.insns = insns; + attr.insns_cnt =ARRAY_SIZE (insns); + attr.license ="GPL" ; + + ret =bpf_load_program_xattr (&attr,NULL ,0 ); +if (ret <0 ) { + cp =libbpf_strerror_r (errno, errmsg,sizeof (errmsg)); +pr_warning ("Error in %s():%s(%d). Couldn't load basic 'r0 = 0' BPF program.\n" , + __func__, cp, errno); +return -errno; + } +close (ret); + +/* now try the same program, but with the name */ + + attr.name ="test" ; + ret =bpf_load_program_xattr (&attr,NULL ,0 ); +if (ret >=0 ) { + obj->caps.name =1 ; +close (ret); + } + +return 0 ; +} + +static int +bpf_object__probe_caps (struct bpf_object *obj) +{ +return bpf_object__probe_name (obj); +} +static int bpf_object__create_maps (struct bpf_object *obj) {
@@ -1708,6 +1765,7 @@ int bpf_object__load(struct bpf_object *obj) obj->loaded = true; +CHECK_ERR (bpf_object__probe_caps (obj), err, out);CHECK_ERR (bpf_object__create_maps (obj), err, out);CHECK_ERR (bpf_object__relocate (obj), err, out);CHECK_ERR (bpf_object__load_progs (obj), err, out);
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
PATCH v3 2/3 bpf: libbpf: remove map name retry from bpf_create_map_xattr
Instead, check for a newly created caps.name bpf_object capability. If kernel doesn't support names, don't specify the attribute.
See commit 23499442c319 ("bpf: libbpf: retry map creation without the name") for rationale.
--- tools/lib/bpf/bpf.c | 11 +---------- tools/lib/bpf/libbpf.c | 3 ++- 2 files changed, 3 insertions(+), 11 deletions(-)
tools/lib/bpf/bpf.c +1 -10
@@ -69,7 +69,6 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) {__u32 name_len = create_attr->name ?strlen (create_attr->name) :0 ;union bpf_attr attr; -int ret;memset (&attr,'\0' ,sizeof (attr));
@@ -87,15 +86,7 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) attr.map_ifindex = create_attr->map_ifindex; attr.inner_map_fd = create_attr->inner_map_fd; - ret =sys_bpf (BPF_MAP_CREATE , &attr,sizeof (attr)); -if (ret <0 && errno ==EINVAL && create_attr->name) { -/* Retry the same syscall, but without the name. -* Pre v4.14 kernels don't support map names. -*/ -memset (attr.map_name,0 ,sizeof (attr.map_name)); -return sys_bpf (BPF_MAP_CREATE , &attr,sizeof (attr)); - } -return ret; +return sys_bpf (BPF_MAP_CREATE , &attr,sizeof (attr)); } int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
tools/lib/bpf/libbpf.c +2 -1
@@ -1211,7 +1211,8 @@ bpf_object__create_maps(struct bpf_object *obj)continue ; } - create_attr.name = map->name; +if (obj->caps.name) + create_attr.name = map->name; create_attr.map_ifindex = map->map_ifindex; create_attr.map_type = def->type; create_attr.map_flags = def->map_flags;
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
PATCH v3 3/3 bpf: libbpf: don't specify prog name if kernel doesn't support it
In reply to Stanislav FomichevUse recently added capability check.
See commit 23499442c319 ("bpf: libbpf: retry map creation without the name") for rationale.
--- tools/lib/bpf/libbpf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/lib/bpf/libbpf.c +2 -1
@@ -1439,7 +1439,8 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,memset (&load_attr,0 ,sizeof (struct bpf_load_program_attr )); load_attr.prog_type = prog->type; load_attr.expected_attach_type = prog->expected_attach_type; - load_attr.name = prog->name; +if (prog->caps->name) + load_attr.name = prog->name; load_attr.insns = insns; load_attr.insns_cnt = insns_cnt; load_attr.license = license;
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
Daniel Borkmann
maintainerQuoted 6 lines · Stanislav Fomichev
It currently only checks whether kernel supports map/prog names. This capability check will be used in the next two commits to skip setting prog/map names.
Suggested-by Daniel Borkmann <[email protected]>Signed-off-by Stanislav Fomichev <[email protected]>
Looks great, thanks for following through. Applied, thanks!