diff mbox series

[bpf-next,v3,2/3] libbpf: add bpf_object__load_xattr() API function to pass log_level

Message ID 20190524103648.15669-3-quentin.monnet@netronome.com
State Accepted
Delegated to: BPF Maintainers
Headers show
Series tools: bpftool: add an option for debug output from libbpf and verifier | expand

Commit Message

Quentin Monnet May 24, 2019, 10:36 a.m. UTC
libbpf was recently made aware of the log_level attribute for programs,
used to specify the level of information expected to be dumped by the
verifier. Function bpf_prog_load_xattr() got support for this log_level
parameter.

But some applications using libbpf rely on another function to load
programs, bpf_object__load(), which does accept any parameter for log
level. Create an API function based on bpf_object__load(), but accepting
an "attr" object as a parameter. Then add a log_level field to that
object, so that applications calling the new bpf_object__load_xattr()
can pick the desired log level.

v3:
- Rewrite commit log.

v2:
- We are in a new cycle, bump libbpf extraversion number.

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/lib/bpf/Makefile   |  2 +-
 tools/lib/bpf/libbpf.c   | 20 +++++++++++++++++---
 tools/lib/bpf/libbpf.h   |  6 ++++++
 tools/lib/bpf/libbpf.map |  5 +++++
 4 files changed, 29 insertions(+), 4 deletions(-)

Comments

Jesper Dangaard Brouer May 24, 2019, 11:22 a.m. UTC | #1
On Fri, 24 May 2019 11:36:47 +0100
Quentin Monnet <quentin.monnet@netronome.com> wrote:

> libbpf was recently made aware of the log_level attribute for programs,
> used to specify the level of information expected to be dumped by the
> verifier. Function bpf_prog_load_xattr() got support for this log_level
> parameter.
> 
> But some applications using libbpf rely on another function to load
> programs, bpf_object__load(), which does accept any parameter for log
> level. Create an API function based on bpf_object__load(), but accepting
> an "attr" object as a parameter. Then add a log_level field to that
> object, so that applications calling the new bpf_object__load_xattr()
> can pick the desired log level.

Does this allow us to extend struct bpf_object_load_attr later?

> v3:
> - Rewrite commit log.
> 
> v2:
> - We are in a new cycle, bump libbpf extraversion number.
> 
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  tools/lib/bpf/Makefile   |  2 +-
>  tools/lib/bpf/libbpf.c   | 20 +++++++++++++++++---
>  tools/lib/bpf/libbpf.h   |  6 ++++++
>  tools/lib/bpf/libbpf.map |  5 +++++
>  4 files changed, 29 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
> index a2aceadf68db..9312066a1ae3 100644
> --- a/tools/lib/bpf/Makefile
> +++ b/tools/lib/bpf/Makefile
> @@ -3,7 +3,7 @@
>  
>  BPF_VERSION = 0
>  BPF_PATCHLEVEL = 0
> -BPF_EXTRAVERSION = 3
> +BPF_EXTRAVERSION = 4
>  
>  MAKEFLAGS += --no-print-directory
>  
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 197b574406b3..1c6fb7a3201e 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -2222,7 +2222,7 @@ static bool bpf_program__is_function_storage(struct bpf_program *prog,
>  }
>  
>  static int
> -bpf_object__load_progs(struct bpf_object *obj)
> +bpf_object__load_progs(struct bpf_object *obj, int log_level)
>  {
>  	size_t i;
>  	int err;
> @@ -2230,6 +2230,7 @@ bpf_object__load_progs(struct bpf_object *obj)
>  	for (i = 0; i < obj->nr_programs; i++) {
>  		if (bpf_program__is_function_storage(&obj->programs[i], obj))
>  			continue;
> +		obj->programs[i].log_level = log_level;
>  		err = bpf_program__load(&obj->programs[i],
>  					obj->license,
>  					obj->kern_version);
> @@ -2381,10 +2382,14 @@ int bpf_object__unload(struct bpf_object *obj)
>  	return 0;
>  }
>  
> -int bpf_object__load(struct bpf_object *obj)
> +int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
>  {
> +	struct bpf_object *obj;
>  	int err;
>  
> +	if (!attr)
> +		return -EINVAL;
> +	obj = attr->obj;
>  	if (!obj)
>  		return -EINVAL;
>  
> @@ -2397,7 +2402,7 @@ int bpf_object__load(struct bpf_object *obj)
>  
>  	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);
> +	CHECK_ERR(bpf_object__load_progs(obj, attr->log_level), err, out);
>  
>  	return 0;
>  out:
> @@ -2406,6 +2411,15 @@ int bpf_object__load(struct bpf_object *obj)
>  	return err;
>  }
>  
> +int bpf_object__load(struct bpf_object *obj)
> +{
> +	struct bpf_object_load_attr attr = {
> +		.obj = obj,
> +	};
> +
> +	return bpf_object__load_xattr(&attr);
> +}
> +
>  static int check_path(const char *path)
>  {
>  	char *cp, errmsg[STRERR_BUFSIZE];
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index c5ff00515ce7..e1c748db44f6 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -89,8 +89,14 @@ LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
>  LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
>  LIBBPF_API void bpf_object__close(struct bpf_object *object);
>  
> +struct bpf_object_load_attr {
> +	struct bpf_object *obj;
> +	int log_level;
> +};

Can this be extended later?

>  /* Load/unload object into/from kernel */
>  LIBBPF_API int bpf_object__load(struct bpf_object *obj);
> +LIBBPF_API int bpf_object__load_xattr(struct bpf_object_load_attr *attr);
>  LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
>  LIBBPF_API const char *bpf_object__name(struct bpf_object *obj);
>  LIBBPF_API unsigned int bpf_object__kversion(struct bpf_object *obj);
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 673001787cba..6ce61fa0baf3 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -164,3 +164,8 @@ LIBBPF_0.0.3 {
>  		bpf_map_freeze;
>  		btf__finalize_data;
>  } LIBBPF_0.0.2;
> +
> +LIBBPF_0.0.4 {
> +	global:
> +		bpf_object__load_xattr;
> +} LIBBPF_0.0.3;
Quentin Monnet May 24, 2019, 11:51 a.m. UTC | #2
2019-05-24 13:22 UTC+0200 ~ Jesper Dangaard Brouer <brouer@redhat.com>
> On Fri, 24 May 2019 11:36:47 +0100
> Quentin Monnet <quentin.monnet@netronome.com> wrote:
> 
>> libbpf was recently made aware of the log_level attribute for programs,
>> used to specify the level of information expected to be dumped by the
>> verifier. Function bpf_prog_load_xattr() got support for this log_level
>> parameter.
>>
>> But some applications using libbpf rely on another function to load
>> programs, bpf_object__load(), which does accept any parameter for log
>> level. Create an API function based on bpf_object__load(), but accepting
>> an "attr" object as a parameter. Then add a log_level field to that
>> object, so that applications calling the new bpf_object__load_xattr()
>> can pick the desired log level.
> 
> Does this allow us to extend struct bpf_object_load_attr later?

I see no reason why it could not. Having the _xattr() version of the
function is precisely a way to have something extensible in the future,
without having to create additional API functions each time we want to
pass a new parameter. And e.g. struct bpf_prog_load_attr (used with
bpf_prog_load_xattr()) has already been extended in the past. So, yeah,
we can add to it in the future. Do you have something in mind?

Quentin
Jesper Dangaard Brouer May 24, 2019, 12:49 p.m. UTC | #3
On Fri, 24 May 2019 12:51:14 +0100
Quentin Monnet <quentin.monnet@netronome.com> wrote:

> 2019-05-24 13:22 UTC+0200 ~ Jesper Dangaard Brouer <brouer@redhat.com>
> > On Fri, 24 May 2019 11:36:47 +0100
> > Quentin Monnet <quentin.monnet@netronome.com> wrote:
> >   
> >> libbpf was recently made aware of the log_level attribute for programs,
> >> used to specify the level of information expected to be dumped by the
> >> verifier. Function bpf_prog_load_xattr() got support for this log_level
> >> parameter.
> >>
> >> But some applications using libbpf rely on another function to load
> >> programs, bpf_object__load(), which does accept any parameter for log
> >> level. Create an API function based on bpf_object__load(), but accepting
> >> an "attr" object as a parameter. Then add a log_level field to that
> >> object, so that applications calling the new bpf_object__load_xattr()
> >> can pick the desired log level.  
> > 
> > Does this allow us to extend struct bpf_object_load_attr later?  
> 
> I see no reason why it could not. Having the _xattr() version of the
> function is precisely a way to have something extensible in the future,
> without having to create additional API functions each time we want to
> pass a new parameter. And e.g. struct bpf_prog_load_attr (used with
> bpf_prog_load_xattr()) has already been extended in the past. So, yeah,
> we can add to it in the future.

Great.  I just don't know/understand how user-space handle this. If a
binary is compiled with libbpf as dynamic loadable lib, then it e.g. saw
libbpf.so.2 when it was compiled, then can't it choose to use libbpf.so.3
then? (e.g. when libbpf.so.2 is not on the system). (I would actually
like to learn/understand this, so links are welcome).

> Do you have something in mind?

I was playing with extending bpf_prog_load_attr, but instead I created a
bpf_prog_load_attr_maps instead and a new function
bpf_prog_load_xattr_maps(), e.g. see:

https://github.com/xdp-project/xdp-tutorial/blob/master/common/common_libbpf.h
https://github.com/xdp-project/xdp-tutorial/blob/master/common/common_libbpf.c

I guess, I could just extend bpf_prog_load_attr instead, right?
Quentin Monnet May 24, 2019, 3:15 p.m. UTC | #4
2019-05-24 14:49 UTC+0200 ~ Jesper Dangaard Brouer <brouer@redhat.com>
> On Fri, 24 May 2019 12:51:14 +0100
> Quentin Monnet <quentin.monnet@netronome.com> wrote:
> 
>> 2019-05-24 13:22 UTC+0200 ~ Jesper Dangaard Brouer <brouer@redhat.com>
>>> On Fri, 24 May 2019 11:36:47 +0100
>>> Quentin Monnet <quentin.monnet@netronome.com> wrote:
>>>   
>>>> libbpf was recently made aware of the log_level attribute for programs,
>>>> used to specify the level of information expected to be dumped by the
>>>> verifier. Function bpf_prog_load_xattr() got support for this log_level
>>>> parameter.
>>>>
>>>> But some applications using libbpf rely on another function to load
>>>> programs, bpf_object__load(), which does accept any parameter for log
>>>> level. Create an API function based on bpf_object__load(), but accepting
>>>> an "attr" object as a parameter. Then add a log_level field to that
>>>> object, so that applications calling the new bpf_object__load_xattr()
>>>> can pick the desired log level.  
>>>
>>> Does this allow us to extend struct bpf_object_load_attr later?  
>>
>> I see no reason why it could not. Having the _xattr() version of the
>> function is precisely a way to have something extensible in the future,
>> without having to create additional API functions each time we want to
>> pass a new parameter. And e.g. struct bpf_prog_load_attr (used with
>> bpf_prog_load_xattr()) has already been extended in the past. So, yeah,
>> we can add to it in the future.
> 
> Great.  I just don't know/understand how user-space handle this. If a
> binary is compiled with libbpf as dynamic loadable lib, then it e.g. saw
> libbpf.so.2 when it was compiled, then can't it choose to use libbpf.so.3
> then? (e.g. when libbpf.so.2 is not on the system). (I would actually
> like to learn/understand this, so links are welcome).

Well I'm no library expert, so don't take my word for it. As far as I
understand, the soname of the library is selected at link time. So if
your app is linked again libbpf.so.2, you will need version 2.* of the
library to be installed on your system, because increasing the version
number usually implies ABI breakage. You can usually check which version
of the libraries is needed with ldd ("ldd bpftool", except that you
won't see libbpf because it's statically linked for bpftool).

This being said, for now the version number for libbpf has not been
incremented and is still at 0, we only had the extraversion increasing.
Since it's not part of the soname ("-Wl,-soname,libbpf.so.$(VERSION)" in
libbpf Makefile), it is not taken into account when searching for the
lib on the system. What I mean is that if the program is linked against
libbpf.so.0, it could pick libbpf.so.0.0.2 or libbpf.so.0.0.3
indifferently depending on what it finds on the system (I assume it
takes the newest?). There should not be any ABI breakage between the
two, so programs compiled against an older patchlevel or extraversion of
the library should still be able to use a newer one.

There is some documentation on libraries here (I should take some time
to finish reading it myself!):

http://tldp.org/HOWTO/Program-Library-HOWTO/

There are also interesting elements in the documentation that was cited
when Andrey introduced the LIBPPF_API macros in libbpf:

https://www.akkadia.org/drepper/dsohowto.pdf

> 
>> Do you have something in mind?
> 
> I was playing with extending bpf_prog_load_attr, but instead I created a
> bpf_prog_load_attr_maps instead and a new function
> bpf_prog_load_xattr_maps(), e.g. see:
> 
> https://github.com/xdp-project/xdp-tutorial/blob/master/common/common_libbpf.h
> https://github.com/xdp-project/xdp-tutorial/blob/master/common/common_libbpf.c
> 
> I guess, I could just extend bpf_prog_load_attr instead, right?
> 

I believe so.

Best,
Quentin
Alexei Starovoitov May 29, 2019, 12:35 a.m. UTC | #5
On Fri, May 24, 2019 at 3:36 AM Quentin Monnet
<quentin.monnet@netronome.com> wrote:
>
> libbpf was recently made aware of the log_level attribute for programs,
> used to specify the level of information expected to be dumped by the
> verifier. Function bpf_prog_load_xattr() got support for this log_level
> parameter.
>
> But some applications using libbpf rely on another function to load
> programs, bpf_object__load(), which does accept any parameter for log
> level. Create an API function based on bpf_object__load(), but accepting
> an "attr" object as a parameter. Then add a log_level field to that
> object, so that applications calling the new bpf_object__load_xattr()
> can pick the desired log level.
>
> v3:
> - Rewrite commit log.
>
> v2:
> - We are in a new cycle, bump libbpf extraversion number.
>
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  tools/lib/bpf/Makefile   |  2 +-
>  tools/lib/bpf/libbpf.c   | 20 +++++++++++++++++---
>  tools/lib/bpf/libbpf.h   |  6 ++++++
>  tools/lib/bpf/libbpf.map |  5 +++++
>  4 files changed, 29 insertions(+), 4 deletions(-)

This commit broke ./test_progs -s
prog_tests/bpf_verif_scale.c no longer passes log_level.
Could you please take a look?
Quentin Monnet May 29, 2019, 9:18 a.m. UTC | #6
2019-05-28 17:35 UTC-0700 ~ Alexei Starovoitov
<alexei.starovoitov@gmail.com>
> On Fri, May 24, 2019 at 3:36 AM Quentin Monnet
> <quentin.monnet@netronome.com> wrote:
>>
>> libbpf was recently made aware of the log_level attribute for programs,
>> used to specify the level of information expected to be dumped by the
>> verifier. Function bpf_prog_load_xattr() got support for this log_level
>> parameter.
>>
>> But some applications using libbpf rely on another function to load
>> programs, bpf_object__load(), which does accept any parameter for log
>> level. Create an API function based on bpf_object__load(), but accepting
>> an "attr" object as a parameter. Then add a log_level field to that
>> object, so that applications calling the new bpf_object__load_xattr()
>> can pick the desired log level.
>>
>> v3:
>> - Rewrite commit log.
>>
>> v2:
>> - We are in a new cycle, bump libbpf extraversion number.
>>
>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>> ---
>>  tools/lib/bpf/Makefile   |  2 +-
>>  tools/lib/bpf/libbpf.c   | 20 +++++++++++++++++---
>>  tools/lib/bpf/libbpf.h   |  6 ++++++
>>  tools/lib/bpf/libbpf.map |  5 +++++
>>  4 files changed, 29 insertions(+), 4 deletions(-)
> 
> This commit broke ./test_progs -s
> prog_tests/bpf_verif_scale.c no longer passes log_level.
> Could you please take a look?
> 

Indeed, I forgot that bpf_load_prog_xattr() would eventually call
bpf_object__load_progs() as well, where the log_level is now overwritten.

Fix incoming, sorry about that.

Quentin
diff mbox series

Patch

diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index a2aceadf68db..9312066a1ae3 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -3,7 +3,7 @@ 
 
 BPF_VERSION = 0
 BPF_PATCHLEVEL = 0
-BPF_EXTRAVERSION = 3
+BPF_EXTRAVERSION = 4
 
 MAKEFLAGS += --no-print-directory
 
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 197b574406b3..1c6fb7a3201e 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2222,7 +2222,7 @@  static bool bpf_program__is_function_storage(struct bpf_program *prog,
 }
 
 static int
-bpf_object__load_progs(struct bpf_object *obj)
+bpf_object__load_progs(struct bpf_object *obj, int log_level)
 {
 	size_t i;
 	int err;
@@ -2230,6 +2230,7 @@  bpf_object__load_progs(struct bpf_object *obj)
 	for (i = 0; i < obj->nr_programs; i++) {
 		if (bpf_program__is_function_storage(&obj->programs[i], obj))
 			continue;
+		obj->programs[i].log_level = log_level;
 		err = bpf_program__load(&obj->programs[i],
 					obj->license,
 					obj->kern_version);
@@ -2381,10 +2382,14 @@  int bpf_object__unload(struct bpf_object *obj)
 	return 0;
 }
 
-int bpf_object__load(struct bpf_object *obj)
+int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
 {
+	struct bpf_object *obj;
 	int err;
 
+	if (!attr)
+		return -EINVAL;
+	obj = attr->obj;
 	if (!obj)
 		return -EINVAL;
 
@@ -2397,7 +2402,7 @@  int bpf_object__load(struct bpf_object *obj)
 
 	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);
+	CHECK_ERR(bpf_object__load_progs(obj, attr->log_level), err, out);
 
 	return 0;
 out:
@@ -2406,6 +2411,15 @@  int bpf_object__load(struct bpf_object *obj)
 	return err;
 }
 
+int bpf_object__load(struct bpf_object *obj)
+{
+	struct bpf_object_load_attr attr = {
+		.obj = obj,
+	};
+
+	return bpf_object__load_xattr(&attr);
+}
+
 static int check_path(const char *path)
 {
 	char *cp, errmsg[STRERR_BUFSIZE];
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index c5ff00515ce7..e1c748db44f6 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -89,8 +89,14 @@  LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
 LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
 LIBBPF_API void bpf_object__close(struct bpf_object *object);
 
+struct bpf_object_load_attr {
+	struct bpf_object *obj;
+	int log_level;
+};
+
 /* Load/unload object into/from kernel */
 LIBBPF_API int bpf_object__load(struct bpf_object *obj);
+LIBBPF_API int bpf_object__load_xattr(struct bpf_object_load_attr *attr);
 LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
 LIBBPF_API const char *bpf_object__name(struct bpf_object *obj);
 LIBBPF_API unsigned int bpf_object__kversion(struct bpf_object *obj);
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 673001787cba..6ce61fa0baf3 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -164,3 +164,8 @@  LIBBPF_0.0.3 {
 		bpf_map_freeze;
 		btf__finalize_data;
 } LIBBPF_0.0.2;
+
+LIBBPF_0.0.4 {
+	global:
+		bpf_object__load_xattr;
+} LIBBPF_0.0.3;