From: Yonghong Song <yhs@fb.com>
To: "Toke Høiland-Jørgensen" <toke@redhat.com>,
"Daniel Borkmann" <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>, Martin Lau <kafai@fb.com>,
Song Liu <songliubraving@fb.com>,
Jesper Dangaard Brouer <brouer@redhat.com>,
"Andrii Nakryiko" <andrii.nakryiko@gmail.com>,
David Miller <davem@davemloft.net>,
"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
"bpf@vger.kernel.org" <bpf@vger.kernel.org>
Subject: Re: [PATCH RFC bpf-next 2/3] libbpf: Handle function externs and support static linking
Date: Thu, 19 Dec 2019 16:24:14 +0000 [thread overview]
Message-ID: <d220154c-6aad-4bc1-ab86-6ae72e351dca@fb.com> (raw)
In-Reply-To: <157676577267.957277.6240503077867756432.stgit@toke.dk>
On 12/19/19 6:29 AM, Toke Høiland-Jørgensen wrote:
> From: Toke Høiland-Jørgensen <toke@redhat.com>
>
> This adds support for resolving function externs to libbpf, with a new API
> to resolve external function calls by static linking at load-time. The API
> for this requires the caller to supply the object files containing the
> target functions, and to specify an explicit mapping between extern
> function names in the calling program, and function names in the target
> object file. This is to support the XDP multi-prog case, where the
> dispatcher program may not necessarily have control over function names in
> the target programs, so simple function name resolution can't be used.
>
> The target object files must be loaded into the kernel before the calling
> program, to ensure all relocations are done on the target functions, so we
> can just copy over the instructions.
>
> Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
> ---
> tools/lib/bpf/btf.c | 10 +-
> tools/lib/bpf/libbpf.c | 268 +++++++++++++++++++++++++++++++++++++++---------
> tools/lib/bpf/libbpf.h | 17 +++
> 3 files changed, 244 insertions(+), 51 deletions(-)
>
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index 5f04f56e1eb6..2740d4a6b2eb 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
> @@ -246,6 +246,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
> size = t->size;
> goto done;
> case BTF_KIND_PTR:
> + case BTF_KIND_FUNC_PROTO:
> size = sizeof(void *);
> goto done;
> case BTF_KIND_TYPEDEF:
> @@ -288,6 +289,7 @@ int btf__align_of(const struct btf *btf, __u32 id)
> case BTF_KIND_ENUM:
> return min(sizeof(void *), t->size);
> case BTF_KIND_PTR:
> + case BTF_KIND_FUNC_PROTO:
> return sizeof(void *);
> case BTF_KIND_TYPEDEF:
> case BTF_KIND_VOLATILE:
> @@ -640,12 +642,16 @@ int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
> */
> if (btf_is_datasec(t)) {
> err = btf_fixup_datasec(obj, btf, t);
> - if (err)
> + /* FIXME: With function externs we can get a BTF DATASEC
> + * entry for .extern, but the section doesn't exist; so
> + * make ENOENT non-fatal
> + */
> + if (err && err != -ENOENT)
> break;
> }
> }
>
> - return err;
> + return err == -ENOENT ? err : 0;
> }
>
> int btf__load(struct btf *btf)
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 266b725e444b..b2c0a2f927e7 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -172,13 +172,17 @@ enum reloc_type {
> RELO_CALL,
> RELO_DATA,
> RELO_EXTERN,
> + RELO_EXTERN_CALL,
> };
>
> +struct extern_desc;
> +
> struct reloc_desc {
> enum reloc_type type;
> int insn_idx;
> int map_idx;
> int sym_off;
> + struct extern_desc *ext;
> };
>
> /*
> @@ -274,6 +278,7 @@ enum extern_type {
> EXT_INT,
> EXT_TRISTATE,
> EXT_CHAR_ARR,
> + EXT_FUNC
> };
>
> struct extern_desc {
> @@ -287,6 +292,7 @@ struct extern_desc {
> bool is_signed;
> bool is_weak;
> bool is_set;
> + struct bpf_program *tgt_prog;
> };
>
> static LIST_HEAD(bpf_objects_list);
> @@ -305,6 +311,7 @@ struct bpf_object {
> char *kconfig;
> struct extern_desc *externs;
> int nr_extern;
> + int nr_data_extern;
> int kconfig_map_idx;
>
> bool loaded;
> @@ -1041,6 +1048,7 @@ static int set_ext_value_tri(struct extern_desc *ext, void *ext_val,
> case EXT_UNKNOWN:
> case EXT_INT:
> case EXT_CHAR_ARR:
> + case EXT_FUNC:
> default:
> pr_warn("extern %s=%c should be bool, tristate, or char\n",
> ext->name, value);
> @@ -1281,7 +1289,7 @@ static int bpf_object__init_kconfig_map(struct bpf_object *obj)
> size_t map_sz;
> int err;
>
> - if (obj->nr_extern == 0)
> + if (obj->nr_data_extern == 0)
> return 0;
>
> last_ext = &obj->externs[obj->nr_extern - 1];
> @@ -1822,29 +1830,51 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj)
> struct btf_type *t;
> int i, j, vlen;
>
> - if (!obj->btf || (has_func && has_datasec))
> + if (!obj->btf)
> return;
> -
> for (i = 1; i <= btf__get_nr_types(btf); i++) {
> t = (struct btf_type *)btf__type_by_id(btf, i);
>
> - if (!has_datasec && btf_is_var(t)) {
> - /* replace VAR with INT */
> - t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
> - /*
> - * using size = 1 is the safest choice, 4 will be too
> - * big and cause kernel BTF validation failure if
> - * original variable took less than 4 bytes
> + if (btf_is_var(t)) {
> + struct btf_type *var_t;
> +
> + var_t = (struct btf_type *)btf__type_by_id(btf,
> + t->type);
> +
> + /* FIXME: The kernel doesn't understand func_proto with
> + * BTF_VAR_GLOBAL_EXTERN linkage, so we just replace
> + * them with INTs here. What's the right thing to do?
> */
> - t->size = 1;
> - *(int *)(t + 1) = BTF_INT_ENC(0, 0, 8);
> - } else if (!has_datasec && btf_is_datasec(t)) {
> + if (!has_datasec ||
> + (btf_kind(var_t) == BTF_KIND_FUNC_PROTO &&
> + btf_var(t)->linkage == BTF_VAR_GLOBAL_EXTERN)) {
You are the first user to use extern function encoding in BTF! Thanks!
Recently, we have discussion with Alexei and felt that putting extern
function into datasec/var is not pretty. So we have the following llvm patch
https://reviews.llvm.org/D71638
to put extern function as a BTF_KIND_FUNC, i.e.,
BTF_KIND_FUNC
.info (lower 2 bits) -> FUNC_STATIC, FUNC_GLOBAL, FUNC_EXTERN
.type -> BTF_KIND_FUNC_PROTO
Alexei is working on kernel side to ensure this is handled properly
before llvm patch can be merged.
Just let you know for the future potential BTF interface change.
> + /* replace VAR with INT */
> + t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
> + /*
> + * using size = 1 is the safest choice, 4 will
> + * be too big and cause kernel BTF validation
> + * failure if original variable took less than 4
> + * bytes
> + */
> + t->size = 1;
> + *(int *)(t + 1) = BTF_INT_ENC(0, 0, 8);
> + }
> + } else if (btf_is_datasec(t)) {
> /* replace DATASEC with STRUCT */
> const struct btf_var_secinfo *v = btf_var_secinfos(t);
> struct btf_member *m = btf_members(t);
> struct btf_type *vt;
> + size_t tot_size = 0;
> char *name;
>
> + /* FIXME: The .extern datasec can be 0-sized when there
> + * are only function signatures but no variables marked
> + * as extern. Kernel doesn't understand this, so we need
> + * to get rid of those.
> + */
> + if (has_datasec && t->size > 0)
> + continue;
> +
> name = (char *)btf__name_by_offset(btf, t->name_off);
> while (*name) {
> if (*name == '.')
> @@ -1861,7 +1891,10 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj)
> /* preserve variable name as member name */
> vt = (void *)btf__type_by_id(btf, v->type);
> m->name_off = vt->name_off;
> + tot_size += vt->size;
> }
> + if (t->size < tot_size)
> + t->size = tot_size;
> } else if (!has_func && btf_is_func_proto(t)) {
> /* replace FUNC_PROTO with ENUM */
> vlen = btf_vlen(t);
> @@ -2205,6 +2238,8 @@ static enum extern_type find_extern_type(const struct btf *btf, int id,
> if (find_extern_type(btf, btf_array(t)->type, NULL) != EXT_CHAR)
> return EXT_UNKNOWN;
> return EXT_CHAR_ARR;
> + case BTF_KIND_FUNC_PROTO:
> + return EXT_FUNC;
> default:
> return EXT_UNKNOWN;
> }
> @@ -2215,6 +2250,10 @@ static int cmp_externs(const void *_a, const void *_b)
[...]
next prev parent reply other threads:[~2019-12-19 16:24 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-19 14:29 [PATCH RFC bpf-next 0/3] libbpf: Add support for extern function calls Toke Høiland-Jørgensen
2019-12-19 14:29 ` [PATCH RFC bpf-next 1/3] libbpf: Add new bpf_object__load2() using new-style opts Toke Høiland-Jørgensen
2019-12-19 23:50 ` Andrii Nakryiko
2019-12-20 10:50 ` Toke Høiland-Jørgensen
2019-12-19 14:29 ` [PATCH RFC bpf-next 2/3] libbpf: Handle function externs and support static linking Toke Høiland-Jørgensen
2019-12-19 16:24 ` Yonghong Song [this message]
2019-12-19 16:59 ` Toke Høiland-Jørgensen
2019-12-20 0:02 ` Andrii Nakryiko
2019-12-20 10:47 ` Toke Høiland-Jørgensen
2019-12-20 17:28 ` Andrii Nakryiko
2019-12-19 14:29 ` [PATCH RFC bpf-next 3/3] selftests/bpf: Add selftest for XDP multiprogs Toke Høiland-Jørgensen
2019-12-20 20:30 ` [PATCH RFC bpf-next 0/3] libbpf: Add support for extern function calls Alexei Starovoitov
2019-12-21 16:24 ` Toke Høiland-Jørgensen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d220154c-6aad-4bc1-ab86-6ae72e351dca@fb.com \
--to=yhs@fb.com \
--cc=andrii.nakryiko@gmail.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brouer@redhat.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=kafai@fb.com \
--cc=netdev@vger.kernel.org \
--cc=songliubraving@fb.com \
--cc=toke@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).