libbpf: Support attachment of BPF tracing programs to kernel modules
authorAndrii Nakryiko <andrii@kernel.org>
Thu, 3 Dec 2020 20:46:32 +0000 (12:46 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 4 Dec 2020 01:38:21 +0000 (17:38 -0800)
Teach libbpf to search for BTF types in kernel modules for tracing BPF
programs. This allows attachment of raw_tp/fentry/fexit/fmod_ret/etc BPF
program types to tracepoints and functions in kernel modules.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20201203204634.1325171-13-andrii@kernel.org
tools/lib/bpf/bpf.c
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf_internal.h

index 5d681ce..bba48ff 100644 (file)
@@ -231,8 +231,11 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
        attr.prog_type = load_attr->prog_type;
        attr.expected_attach_type = load_attr->expected_attach_type;
 
+       if (load_attr->attach_prog_fd)
+               attr.attach_prog_fd = load_attr->attach_prog_fd;
+       else
+               attr.attach_btf_obj_fd = load_attr->attach_btf_obj_fd;
        attr.attach_btf_id = load_attr->attach_btf_id;
-       attr.attach_prog_fd = load_attr->attach_prog_fd;
 
        attr.prog_ifindex = load_attr->prog_ifindex;
        attr.kern_version = load_attr->kern_version;
index 103d66e..912e01b 100644 (file)
@@ -278,6 +278,7 @@ struct bpf_program {
        enum bpf_prog_type type;
        enum bpf_attach_type expected_attach_type;
        int prog_ifindex;
+       __u32 attach_btf_obj_fd;
        __u32 attach_btf_id;
        __u32 attach_prog_fd;
        void *func_info;
@@ -408,6 +409,7 @@ struct module_btf {
        struct btf *btf;
        char *name;
        __u32 id;
+       int fd;
 };
 
 struct bpf_object {
@@ -4766,8 +4768,7 @@ static int load_module_btfs(struct bpf_object *obj)
                if (err) {
                        err = -errno;
                        pr_warn("failed to get BTF object #%d info: %d\n", id, err);
-                       close(fd);
-                       return err;
+                       goto err_out;
                }
 
                /* ignore non-module BTFs */
@@ -4777,25 +4778,33 @@ static int load_module_btfs(struct bpf_object *obj)
                }
 
                btf = btf_get_from_fd(fd, obj->btf_vmlinux);
-               close(fd);
                if (IS_ERR(btf)) {
                        pr_warn("failed to load module [%s]'s BTF object #%d: %ld\n",
                                name, id, PTR_ERR(btf));
-                       return PTR_ERR(btf);
+                       err = PTR_ERR(btf);
+                       goto err_out;
                }
 
                err = btf_ensure_mem((void **)&obj->btf_modules, &obj->btf_module_cap,
                                     sizeof(*obj->btf_modules), obj->btf_module_cnt + 1);
                if (err)
-                       return err;
+                       goto err_out;
 
                mod_btf = &obj->btf_modules[obj->btf_module_cnt++];
 
                mod_btf->btf = btf;
                mod_btf->id = id;
+               mod_btf->fd = fd;
                mod_btf->name = strdup(name);
-               if (!mod_btf->name)
-                       return -ENOMEM;
+               if (!mod_btf->name) {
+                       err = -ENOMEM;
+                       goto err_out;
+               }
+               continue;
+
+err_out:
+               close(fd);
+               return err;
        }
 
        return 0;
@@ -6841,7 +6850,10 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
        load_attr.insn_cnt = insns_cnt;
        load_attr.license = license;
        load_attr.attach_btf_id = prog->attach_btf_id;
-       load_attr.attach_prog_fd = prog->attach_prog_fd;
+       if (prog->attach_prog_fd)
+               load_attr.attach_prog_fd = prog->attach_prog_fd;
+       else
+               load_attr.attach_btf_obj_fd = prog->attach_btf_obj_fd;
        load_attr.attach_btf_id = prog->attach_btf_id;
        load_attr.kern_version = kern_version;
        load_attr.prog_ifindex = prog->prog_ifindex;
@@ -6937,11 +6949,11 @@ out:
        return ret;
 }
 
-static int libbpf_find_attach_btf_id(struct bpf_program *prog);
+static int libbpf_find_attach_btf_id(struct bpf_program *prog, int *btf_obj_fd, int *btf_type_id);
 
 int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver)
 {
-       int err = 0, fd, i, btf_id;
+       int err = 0, fd, i;
 
        if (prog->obj->loaded) {
                pr_warn("prog '%s': can't load after object was loaded\n", prog->name);
@@ -6951,10 +6963,14 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver)
        if ((prog->type == BPF_PROG_TYPE_TRACING ||
             prog->type == BPF_PROG_TYPE_LSM ||
             prog->type == BPF_PROG_TYPE_EXT) && !prog->attach_btf_id) {
-               btf_id = libbpf_find_attach_btf_id(prog);
-               if (btf_id <= 0)
-                       return btf_id;
-               prog->attach_btf_id = btf_id;
+               int btf_obj_fd = 0, btf_type_id = 0;
+
+               err = libbpf_find_attach_btf_id(prog, &btf_obj_fd, &btf_type_id);
+               if (err)
+                       return err;
+
+               prog->attach_btf_obj_fd = btf_obj_fd;
+               prog->attach_btf_id = btf_type_id;
        }
 
        if (prog->instances.nr < 0 || !prog->instances.fds) {
@@ -7467,6 +7483,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
 
        /* clean up module BTFs */
        for (i = 0; i < obj->btf_module_cnt; i++) {
+               close(obj->btf_modules[i].fd);
                btf__free(obj->btf_modules[i].btf);
                free(obj->btf_modules[i].name);
        }
@@ -8821,8 +8838,8 @@ static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix,
        return btf__find_by_name_kind(btf, btf_type_name, kind);
 }
 
-static inline int __find_vmlinux_btf_id(struct btf *btf, const char *name,
-                                       enum bpf_attach_type attach_type)
+static inline int find_attach_btf_id(struct btf *btf, const char *name,
+                                    enum bpf_attach_type attach_type)
 {
        int err;
 
@@ -8838,9 +8855,6 @@ static inline int __find_vmlinux_btf_id(struct btf *btf, const char *name,
        else
                err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
 
-       if (err <= 0)
-               pr_warn("%s is not found in vmlinux BTF\n", name);
-
        return err;
 }
 
@@ -8856,7 +8870,10 @@ int libbpf_find_vmlinux_btf_id(const char *name,
                return -EINVAL;
        }
 
-       err = __find_vmlinux_btf_id(btf, name, attach_type);
+       err = find_attach_btf_id(btf, name, attach_type);
+       if (err <= 0)
+               pr_warn("%s is not found in vmlinux BTF\n", name);
+
        btf__free(btf);
        return err;
 }
@@ -8894,11 +8911,49 @@ out:
        return err;
 }
 
-static int libbpf_find_attach_btf_id(struct bpf_program *prog)
+static int find_kernel_btf_id(struct bpf_object *obj, const char *attach_name,
+                             enum bpf_attach_type attach_type,
+                             int *btf_obj_fd, int *btf_type_id)
+{
+       int ret, i;
+
+       ret = find_attach_btf_id(obj->btf_vmlinux, attach_name, attach_type);
+       if (ret > 0) {
+               *btf_obj_fd = 0; /* vmlinux BTF */
+               *btf_type_id = ret;
+               return 0;
+       }
+       if (ret != -ENOENT)
+               return ret;
+
+       ret = load_module_btfs(obj);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < obj->btf_module_cnt; i++) {
+               const struct module_btf *mod = &obj->btf_modules[i];
+
+               ret = find_attach_btf_id(mod->btf, attach_name, attach_type);
+               if (ret > 0) {
+                       *btf_obj_fd = mod->fd;
+                       *btf_type_id = ret;
+                       return 0;
+               }
+               if (ret == -ENOENT)
+                       continue;
+
+               return ret;
+       }
+
+       return -ESRCH;
+}
+
+static int libbpf_find_attach_btf_id(struct bpf_program *prog, int *btf_obj_fd, int *btf_type_id)
 {
        enum bpf_attach_type attach_type = prog->expected_attach_type;
        __u32 attach_prog_fd = prog->attach_prog_fd;
-       const char *name = prog->sec_name;
+       const char *name = prog->sec_name, *attach_name;
+       const struct bpf_sec_def *sec = NULL;
        int i, err;
 
        if (!name)
@@ -8909,17 +8964,37 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog)
                        continue;
                if (strncmp(name, section_defs[i].sec, section_defs[i].len))
                        continue;
-               if (attach_prog_fd)
-                       err = libbpf_find_prog_btf_id(name + section_defs[i].len,
-                                                     attach_prog_fd);
-               else
-                       err = __find_vmlinux_btf_id(prog->obj->btf_vmlinux,
-                                                   name + section_defs[i].len,
-                                                   attach_type);
+
+               sec = &section_defs[i];
+               break;
+       }
+
+       if (!sec) {
+               pr_warn("failed to identify BTF ID based on ELF section name '%s'\n", name);
+               return -ESRCH;
+       }
+       attach_name = name + sec->len;
+
+       /* BPF program's BTF ID */
+       if (attach_prog_fd) {
+               err = libbpf_find_prog_btf_id(attach_name, attach_prog_fd);
+               if (err < 0) {
+                       pr_warn("failed to find BPF program (FD %d) BTF ID for '%s': %d\n",
+                                attach_prog_fd, attach_name, err);
+                       return err;
+               }
+               *btf_obj_fd = 0;
+               *btf_type_id = err;
+               return 0;
+       }
+
+       /* kernel/module BTF ID */
+       err = find_kernel_btf_id(prog->obj, attach_name, attach_type, btf_obj_fd, btf_type_id);
+       if (err) {
+               pr_warn("failed to find kernel BTF type ID of '%s': %d\n", attach_name, err);
                return err;
        }
-       pr_warn("failed to identify btf_id based on ELF section name '%s'\n", name);
-       return -ESRCH;
+       return 0;
 }
 
 int libbpf_attach_type_by_name(const char *name,
@@ -10808,6 +10883,7 @@ int bpf_program__set_attach_target(struct bpf_program *prog,
                return btf_id;
 
        prog->attach_btf_id = btf_id;
+       prog->attach_btf_obj_fd = 0;
        prog->attach_prog_fd = attach_prog_fd;
        return 0;
 }
index 681073a..969d0ac 100644 (file)
@@ -160,6 +160,7 @@ struct bpf_prog_load_params {
        const char *license;
        __u32 kern_version;
        __u32 attach_prog_fd;
+       __u32 attach_btf_obj_fd;
        __u32 attach_btf_id;
        __u32 prog_ifindex;
        __u32 prog_btf_fd;