bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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)
[...]

  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).