diff mbox series

[bpf-next,RFC,v1,3/8] libbpf: Support kernel module function calls

Message ID 20210830173424.1385796-4-memxor@gmail.com (mailing list archive)
State RFC
Delegated to: BPF
Headers show
Series Support kernel module function calls from eBPF | expand

Checks

Context Check Description
bpf/vmtest-bpf-next pending Kernel LATEST + selftests
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for bpf-next
netdev/subject_prefix success Link
netdev/cc_maintainers warning 2 maintainers not CCed: kpsingh@kernel.org john.fastabend@gmail.com
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch warning CHECK: multiple assignments should be avoided WARNING: Missing commit description - Add an appropriate one WARNING: line length of 100 exceeds 80 columns WARNING: line length of 81 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns WARNING: line length of 98 exceeds 80 columns
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success Link

Commit Message

Kumar Kartikeya Dwivedi Aug. 30, 2021, 5:34 p.m. UTC
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 tools/lib/bpf/bpf.c             |  3 ++
 tools/lib/bpf/libbpf.c          | 71 +++++++++++++++++++++++++++++++--
 tools/lib/bpf/libbpf_internal.h |  2 +
 3 files changed, 73 insertions(+), 3 deletions(-)

Comments

Andrii Nakryiko Sept. 1, 2021, 12:55 a.m. UTC | #1
On Mon, Aug 30, 2021 at 10:34 AM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>

-ENOCOMMITMESSAGE?

> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
>  tools/lib/bpf/bpf.c             |  3 ++
>  tools/lib/bpf/libbpf.c          | 71 +++++++++++++++++++++++++++++++--
>  tools/lib/bpf/libbpf_internal.h |  2 +
>  3 files changed, 73 insertions(+), 3 deletions(-)
>

[...]

> @@ -515,6 +521,13 @@ struct bpf_object {
>         void *priv;
>         bpf_object_clear_priv_t clear_priv;
>
> +       struct {
> +               struct hashmap *map;
> +               int *fds;
> +               size_t cap_cnt;
> +               __u32 n_fds;
> +       } kfunc_btf_fds;
> +
>         char path[];
>  };
>  #define obj_elf_valid(o)       ((o)->efile.elf)
> @@ -5327,6 +5340,7 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
>                         ext = &obj->externs[relo->sym_off];
>                         insn[0].src_reg = BPF_PSEUDO_KFUNC_CALL;
>                         insn[0].imm = ext->ksym.kernel_btf_id;
> +                       insn[0].off = ext->ksym.offset;

Just a few lines above we use insn[1].imm =
ext->ksym.kernel_btf_obj_fd; for EXT_KSYM (for variables). Why are you
inventing a new form if we already have a pretty consistent pattern?

>                         break;
>                 case RELO_SUBPROG_ADDR:
>                         if (insn[0].src_reg != BPF_PSEUDO_FUNC) {

[...]
Kumar Kartikeya Dwivedi Sept. 1, 2021, 2:27 a.m. UTC | #2
On Wed, Sep 01, 2021 at 06:25:14AM IST, Andrii Nakryiko wrote:
> On Mon, Aug 30, 2021 at 10:34 AM Kumar Kartikeya Dwivedi
> <memxor@gmail.com> wrote:
> >
>
> -ENOCOMMITMESSAGE?
>
> > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > ---
> >  tools/lib/bpf/bpf.c             |  3 ++
> >  tools/lib/bpf/libbpf.c          | 71 +++++++++++++++++++++++++++++++--
> >  tools/lib/bpf/libbpf_internal.h |  2 +
> >  3 files changed, 73 insertions(+), 3 deletions(-)
> >
>
> [...]
>
> > @@ -515,6 +521,13 @@ struct bpf_object {
> >         void *priv;
> >         bpf_object_clear_priv_t clear_priv;
> >
> > +       struct {
> > +               struct hashmap *map;
> > +               int *fds;
> > +               size_t cap_cnt;
> > +               __u32 n_fds;
> > +       } kfunc_btf_fds;
> > +
> >         char path[];
> >  };
> >  #define obj_elf_valid(o)       ((o)->efile.elf)
> > @@ -5327,6 +5340,7 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
> >                         ext = &obj->externs[relo->sym_off];
> >                         insn[0].src_reg = BPF_PSEUDO_KFUNC_CALL;
> >                         insn[0].imm = ext->ksym.kernel_btf_id;
> > +                       insn[0].off = ext->ksym.offset;
>
> Just a few lines above we use insn[1].imm =
> ext->ksym.kernel_btf_obj_fd; for EXT_KSYM (for variables). Why are you
> inventing a new form if we already have a pretty consistent pattern?
>

That makes sense. This is all new to me, so I went with what was described in
e6ac2450d6de (bpf: Support bpf program calling kernel function), but I'll rework
it to encode the btf fd like that in the next spin. It also makes the everything
far simpler.

> >                         break;
> >                 case RELO_SUBPROG_ADDR:
> >                         if (insn[0].src_reg != BPF_PSEUDO_FUNC) {
>
> [...]

--
Kartikeya
Alexei Starovoitov Sept. 1, 2021, 2:59 a.m. UTC | #3
On Tue, Aug 31, 2021 at 7:27 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
> > > @@ -5327,6 +5340,7 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
> > >                         ext = &obj->externs[relo->sym_off];
> > >                         insn[0].src_reg = BPF_PSEUDO_KFUNC_CALL;
> > >                         insn[0].imm = ext->ksym.kernel_btf_id;
> > > +                       insn[0].off = ext->ksym.offset;
> >
> > Just a few lines above we use insn[1].imm =
> > ext->ksym.kernel_btf_obj_fd; for EXT_KSYM (for variables). Why are you
> > inventing a new form if we already have a pretty consistent pattern?
> >
>
> That makes sense. This is all new to me, so I went with what was described in
> e6ac2450d6de (bpf: Support bpf program calling kernel function), but I'll rework
> it to encode the btf fd like that in the next spin. It also makes the everything
> far simpler.

Hmm. kfunc call is a call insn. There is no imm[1].
Andrii Nakryiko Sept. 1, 2021, 3:38 a.m. UTC | #4
On Tue, Aug 31, 2021 at 7:59 PM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Tue, Aug 31, 2021 at 7:27 PM Kumar Kartikeya Dwivedi
> <memxor@gmail.com> wrote:
> > > > @@ -5327,6 +5340,7 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
> > > >                         ext = &obj->externs[relo->sym_off];
> > > >                         insn[0].src_reg = BPF_PSEUDO_KFUNC_CALL;
> > > >                         insn[0].imm = ext->ksym.kernel_btf_id;
> > > > +                       insn[0].off = ext->ksym.offset;
> > >
> > > Just a few lines above we use insn[1].imm =
> > > ext->ksym.kernel_btf_obj_fd; for EXT_KSYM (for variables). Why are you
> > > inventing a new form if we already have a pretty consistent pattern?
> > >
> >
> > That makes sense. This is all new to me, so I went with what was described in
> > e6ac2450d6de (bpf: Support bpf program calling kernel function), but I'll rework
> > it to encode the btf fd like that in the next spin. It also makes the everything
> > far simpler.
>
> Hmm. kfunc call is a call insn. There is no imm[1].

Doh, right :( Never mind, we'll need to use fd_array for this.

Either way, I don't think hashmap use is warranted here to find a BTF
slot. Let's just do linear search, it's not like we are going to have
thousands of module BTFs used by any single BPF program, right?
diff mbox series

Patch

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 2401fad090c5..df2d1ceba146 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -265,6 +265,9 @@  int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
 	attr.line_info_cnt = load_attr->line_info_cnt;
 	attr.line_info = ptr_to_u64(load_attr->line_info);
 
+	attr.kfunc_btf_fds = ptr_to_u64(load_attr->kfunc_btf_fds);
+	attr.kfunc_btf_fds_cnt = load_attr->kfunc_btf_fds_cnt;
+
 	if (load_attr->name)
 		memcpy(attr.prog_name, load_attr->name,
 		       min(strlen(load_attr->name), (size_t)BPF_OBJ_NAME_LEN - 1));
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 88d8825fc6f6..c4677ef97caa 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -419,6 +419,12 @@  struct extern_desc {
 
 			/* local btf_id of the ksym extern's type. */
 			__u32 type_id;
+			/* offset to be patched in for insn->off,
+			 * this is 0 for btf_vmlinux, and index + 1
+			 * for module BTF, where index is BTF index in
+			 * obj->kfunc_btf_fds.fds array
+			 */
+			__u32 offset;
 		} ksym;
 	};
 };
@@ -515,6 +521,13 @@  struct bpf_object {
 	void *priv;
 	bpf_object_clear_priv_t clear_priv;
 
+	struct {
+		struct hashmap *map;
+		int *fds;
+		size_t cap_cnt;
+		__u32 n_fds;
+	} kfunc_btf_fds;
+
 	char path[];
 };
 #define obj_elf_valid(o)	((o)->efile.elf)
@@ -5327,6 +5340,7 @@  bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
 			ext = &obj->externs[relo->sym_off];
 			insn[0].src_reg = BPF_PSEUDO_KFUNC_CALL;
 			insn[0].imm = ext->ksym.kernel_btf_id;
+			insn[0].off = ext->ksym.offset;
 			break;
 		case RELO_SUBPROG_ADDR:
 			if (insn[0].src_reg != BPF_PSEUDO_FUNC) {
@@ -6122,6 +6136,11 @@  load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
 	load_attr.log_level = prog->log_level;
 	load_attr.prog_flags = prog->prog_flags;
 
+	if (prog->obj->kfunc_btf_fds.n_fds) {
+		load_attr.kfunc_btf_fds = prog->obj->kfunc_btf_fds.fds;
+		load_attr.kfunc_btf_fds_cnt = prog->obj->kfunc_btf_fds.n_fds;
+	}
+
 	if (prog->obj->gen_loader) {
 		bpf_gen__prog_load(prog->obj->gen_loader, &load_attr,
 				   prog - prog->obj->programs);
@@ -6723,9 +6742,49 @@  static int bpf_object__resolve_ksym_func_btf_id(struct bpf_object *obj,
 	}
 
 	if (kern_btf != obj->btf_vmlinux) {
-		pr_warn("extern (func ksym) '%s': function in kernel module is not supported\n",
-			ext->name);
-		return -ENOTSUP;
+		size_t index;
+		void *value;
+
+		/* Lazy initialize btf->fd index map */
+		if (!obj->kfunc_btf_fds.map) {
+			obj->kfunc_btf_fds.map = hashmap__new(bpf_core_hash_fn, bpf_core_equal_fn,
+							      NULL);
+			if (!obj->kfunc_btf_fds.map)
+				return -ENOMEM;
+
+			obj->kfunc_btf_fds.fds = calloc(8, sizeof(*obj->kfunc_btf_fds.fds));
+			if (!obj->kfunc_btf_fds.fds) {
+				hashmap__free(obj->kfunc_btf_fds.map);
+				return -ENOMEM;
+			}
+			obj->kfunc_btf_fds.cap_cnt = 8;
+		}
+
+		if (!hashmap__find(obj->kfunc_btf_fds.map, kern_btf, &value)) {
+			size_t *cap_cnt = &obj->kfunc_btf_fds.cap_cnt;
+			/* Not found, insert BTF fd into slot, and grab next
+			 * index from the fd array.
+			 */
+			ret = libbpf_ensure_mem((void **)&obj->kfunc_btf_fds.fds,
+						cap_cnt, sizeof(int), obj->kfunc_btf_fds.n_fds + 1);
+			if (ret)
+				return ret;
+			index = obj->kfunc_btf_fds.n_fds++;
+			obj->kfunc_btf_fds.fds[index] = kern_btf_fd;
+			value = (void *)index;
+			ret = hashmap__add(obj->kfunc_btf_fds.map, kern_btf, &value);
+			if (ret)
+				return ret;
+
+		} else {
+			index = (size_t)value;
+		}
+		/* index starts from 0, so shift offset by 1 as offset == 0 is reserved
+		 * for btf_vmlinux in the kernel
+		 */
+		ext->ksym.offset = index + 1;
+	} else {
+		ext->ksym.offset = 0;
 	}
 
 	kern_func = btf__type_by_id(kern_btf, kfunc_id);
@@ -6901,6 +6960,12 @@  int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
 			err = bpf_gen__finish(obj->gen_loader);
 	}
 
+	/* clean up kfunc_btf */
+	hashmap__free(obj->kfunc_btf_fds.map);
+	obj->kfunc_btf_fds.map = NULL;
+	zfree(&obj->kfunc_btf_fds.fds);
+	obj->kfunc_btf_fds.cap_cnt = obj->kfunc_btf_fds.n_fds = 0;
+
 	/* clean up module BTFs */
 	for (i = 0; i < obj->btf_module_cnt; i++) {
 		close(obj->btf_modules[i].fd);
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index 533b0211f40a..701719d9caaf 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -276,6 +276,8 @@  struct bpf_prog_load_params {
 	__u32 log_level;
 	char *log_buf;
 	size_t log_buf_sz;
+	int *kfunc_btf_fds;
+	__u32 kfunc_btf_fds_cnt;
 };
 
 int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr);