All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/2] libbpf: support more map options
@ 2017-10-02 16:41 Craig Gallek
  2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Craig Gallek @ 2017-10-02 16:41 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
	David S . Miller
  Cc: Chonggang Li, netdev

From: Craig Gallek <kraig@google.com>

The functional change to this series is the ability to use flags when
creating maps from object files loaded by libbpf.  In order to do this,
the first patch updates the library to handle map definitions that
differ in size from libbpf's struct bpf_map_def.

For object files with a larger map definition, libbpf will continue to load
if the unknown fields are all zero, otherwise the map is rejected.  If the
map definition in the object file is smaller than expected, libbpf will use
zero as a default value in the missing fields.

Craig Gallek (2):
  libbpf: parse maps sections of varying size
  libbpf: use map_flags when creating maps

 tools/lib/bpf/libbpf.c | 56 ++++++++++++++++++++++++++++++++++++++++++--------
 tools/lib/bpf/libbpf.h |  1 +
 2 files changed, 48 insertions(+), 9 deletions(-)

-- 
2.14.2.822.g60be5d43e6-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-02 16:41 [PATCH net-next v2 0/2] libbpf: support more map options Craig Gallek
@ 2017-10-02 16:41 ` Craig Gallek
  2017-10-02 23:07   ` Alexei Starovoitov
                     ` (2 more replies)
  2017-10-02 16:41 ` [PATCH net-next v2 2/2] libbpf: use map_flags when creating maps Craig Gallek
  2017-10-04  4:26 ` [PATCH net-next v2 0/2] libbpf: support more map options David Miller
  2 siblings, 3 replies; 15+ messages in thread
From: Craig Gallek @ 2017-10-02 16:41 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
	David S . Miller
  Cc: Chonggang Li, netdev

From: Craig Gallek <kraig@google.com>

This library previously assumed a fixed-size map options structure.
Any new options were ignored.  In order to allow the options structure
to grow and to support parsing older programs, this patch updates
the maps section parsing to handle varying sizes.

Object files with maps sections smaller than expected will have the new
fields initialized to zero.  Object files which have larger than expected
maps sections will be rejected unless all of the unrecognized data is zero.

This change still assumes that each map definition in the maps section
is the same size.

Signed-off-by: Craig Gallek <kraig@google.com>
---
 tools/lib/bpf/libbpf.c | 54 ++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 46 insertions(+), 8 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4f402dcdf372..28b300868ad7 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -580,7 +580,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
 }
 
 static int
-bpf_object__validate_maps(struct bpf_object *obj)
+bpf_object__validate_maps(struct bpf_object *obj, int map_def_sz)
 {
 	int i;
 
@@ -595,9 +595,11 @@ bpf_object__validate_maps(struct bpf_object *obj)
 		const struct bpf_map *a = &obj->maps[i - 1];
 		const struct bpf_map *b = &obj->maps[i];
 
-		if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
-			pr_warning("corrupted map section in %s: map \"%s\" too small\n",
-				   obj->path, a->name);
+		if (b->offset - a->offset < map_def_sz) {
+			pr_warning("corrupted map section in %s: map \"%s\" too small "
+				   "(%zd vs %d)\n",
+				   obj->path, a->name, b->offset - a->offset,
+				   map_def_sz);
 			return -EINVAL;
 		}
 	}
@@ -615,7 +617,7 @@ static int compare_bpf_map(const void *_a, const void *_b)
 static int
 bpf_object__init_maps(struct bpf_object *obj)
 {
-	int i, map_idx, nr_maps = 0;
+	int i, map_idx, map_def_sz, nr_maps = 0;
 	Elf_Scn *scn;
 	Elf_Data *data;
 	Elf_Data *symbols = obj->efile.symbols;
@@ -658,6 +660,15 @@ bpf_object__init_maps(struct bpf_object *obj)
 	if (!nr_maps)
 		return 0;
 
+	/* Assume equally sized map definitions */
+	map_def_sz = data->d_size / nr_maps;
+	if (!data->d_size || (data->d_size % nr_maps) != 0) {
+		pr_warning("unable to determine map definition size "
+			   "section %s, %d maps in %zd bytes\n",
+			   obj->path, nr_maps, data->d_size);
+		return -EINVAL;
+	}
+
 	obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
 	if (!obj->maps) {
 		pr_warning("alloc maps for object failed\n");
@@ -690,7 +701,7 @@ bpf_object__init_maps(struct bpf_object *obj)
 				      obj->efile.strtabidx,
 				      sym.st_name);
 		obj->maps[map_idx].offset = sym.st_value;
-		if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) {
+		if (sym.st_value + map_def_sz > data->d_size) {
 			pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",
 				   obj->path, map_name);
 			return -EINVAL;
@@ -704,12 +715,39 @@ bpf_object__init_maps(struct bpf_object *obj)
 		pr_debug("map %d is \"%s\"\n", map_idx,
 			 obj->maps[map_idx].name);
 		def = (struct bpf_map_def *)(data->d_buf + sym.st_value);
-		obj->maps[map_idx].def = *def;
+		/*
+		 * If the definition of the map in the object file fits in
+		 * bpf_map_def, copy it.  Any extra fields in our version
+		 * of bpf_map_def will default to zero as a result of the
+		 * calloc above.
+		 */
+		if (map_def_sz <= sizeof(struct bpf_map_def)) {
+			memcpy(&obj->maps[map_idx].def, def, map_def_sz);
+		} else {
+			/*
+			 * Here the map structure being read is bigger than what
+			 * we expect, truncate if the excess bits are all zero.
+			 * If they are not zero, reject this map as
+			 * incompatible.
+			 */
+			char *b;
+			for (b = ((char *)def) + sizeof(struct bpf_map_def);
+			     b < ((char *)def) + map_def_sz; b++) {
+				if (*b != 0) {
+					pr_warning("maps section in %s: \"%s\" "
+						   "has unrecognized, non-zero "
+						   "options\n",
+						   obj->path, map_name);
+					return -EINVAL;
+				}
+			}
+			obj->maps[map_idx].def = *def;
+		}
 		map_idx++;
 	}
 
 	qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map);
-	return bpf_object__validate_maps(obj);
+	return bpf_object__validate_maps(obj, map_def_sz);
 }
 
 static int bpf_object__elf_collect(struct bpf_object *obj)
-- 
2.14.2.822.g60be5d43e6-goog

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next v2 2/2] libbpf: use map_flags when creating maps
  2017-10-02 16:41 [PATCH net-next v2 0/2] libbpf: support more map options Craig Gallek
  2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
@ 2017-10-02 16:41 ` Craig Gallek
  2017-10-04  4:26 ` [PATCH net-next v2 0/2] libbpf: support more map options David Miller
  2 siblings, 0 replies; 15+ messages in thread
From: Craig Gallek @ 2017-10-02 16:41 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
	David S . Miller
  Cc: Chonggang Li, netdev

From: Craig Gallek <kraig@google.com>

This is required to use BPF_MAP_TYPE_LPM_TRIE or any other map type
which requires flags.

Signed-off-by: Craig Gallek <kraig@google.com>
---
 tools/lib/bpf/libbpf.c | 2 +-
 tools/lib/bpf/libbpf.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 28b300868ad7..5996e7565cc8 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -968,7 +968,7 @@ bpf_object__create_maps(struct bpf_object *obj)
 					   def->key_size,
 					   def->value_size,
 					   def->max_entries,
-					   0);
+					   def->map_flags);
 		if (*pfd < 0) {
 			size_t j;
 			int err = *pfd;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 7959086eb9c9..6e20003109e0 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -207,6 +207,7 @@ struct bpf_map_def {
 	unsigned int key_size;
 	unsigned int value_size;
 	unsigned int max_entries;
+	unsigned int map_flags;
 };
 
 /*
-- 
2.14.2.822.g60be5d43e6-goog

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
@ 2017-10-02 23:07   ` Alexei Starovoitov
  2017-10-03 14:39     ` Daniel Borkmann
  2017-10-03 14:03   ` Jesper Dangaard Brouer
  2017-10-03 14:11   ` Jesper Dangaard Brouer
  2 siblings, 1 reply; 15+ messages in thread
From: Alexei Starovoitov @ 2017-10-02 23:07 UTC (permalink / raw)
  To: Craig Gallek, Daniel Borkmann, Jesper Dangaard Brouer, David S . Miller
  Cc: Chonggang Li, netdev

On 10/2/17 9:41 AM, Craig Gallek wrote:
> +	/* Assume equally sized map definitions */
> +	map_def_sz = data->d_size / nr_maps;
> +	if (!data->d_size || (data->d_size % nr_maps) != 0) {
> +		pr_warning("unable to determine map definition size "
> +			   "section %s, %d maps in %zd bytes\n",
> +			   obj->path, nr_maps, data->d_size);
> +		return -EINVAL;
> +	}

this approach is not as flexible as done by samples/bpf/bpf_load.c
where it looks at every map independently by walking symtab,
but I guess it's ok.
I'd like to hear what Daniel and Jesper say,
since we really want to move to libbpf.a in samples/bpf/
and loader has to get to parity with the one in samples.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
  2017-10-02 23:07   ` Alexei Starovoitov
@ 2017-10-03 14:03   ` Jesper Dangaard Brouer
  2017-10-04 13:58     ` Craig Gallek
  2017-10-03 14:11   ` Jesper Dangaard Brouer
  2 siblings, 1 reply; 15+ messages in thread
From: Jesper Dangaard Brouer @ 2017-10-03 14:03 UTC (permalink / raw)
  To: Craig Gallek
  Cc: Alexei Starovoitov, Daniel Borkmann, David S . Miller,
	Chonggang Li, netdev, brouer, Eric Leblond, Wangnan (F)



First of all, thank you Craig for working on this.  As Alexei says, we
need to improve tools/lib/bpf/libbpf and move towards converting users
of bpf_load.c to this lib instead.

Comments inlined below.

On Mon,  2 Oct 2017 12:41:28 -0400 Craig Gallek <kraigatgoog@gmail.com> wrote:

> From: Craig Gallek <kraig@google.com>
> 
> This library previously assumed a fixed-size map options structure.
> Any new options were ignored.  In order to allow the options structure
> to grow and to support parsing older programs, this patch updates
> the maps section parsing to handle varying sizes.
> 
> Object files with maps sections smaller than expected will have the new
> fields initialized to zero.  Object files which have larger than expected
> maps sections will be rejected unless all of the unrecognized data is zero.
> 
> This change still assumes that each map definition in the maps section
> is the same size.
> 
> Signed-off-by: Craig Gallek <kraig@google.com>
> ---
>  tools/lib/bpf/libbpf.c | 54 ++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 46 insertions(+), 8 deletions(-)
> 
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 4f402dcdf372..28b300868ad7 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -580,7 +580,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
>  }
>  
>  static int
> -bpf_object__validate_maps(struct bpf_object *obj)
> +bpf_object__validate_maps(struct bpf_object *obj, int map_def_sz)
>  {
>  	int i;
>  
> @@ -595,9 +595,11 @@ bpf_object__validate_maps(struct bpf_object *obj)
>  		const struct bpf_map *a = &obj->maps[i - 1];
>  		const struct bpf_map *b = &obj->maps[i];
>  
> -		if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
> -			pr_warning("corrupted map section in %s: map \"%s\" too small\n",
> -				   obj->path, a->name);
> +		if (b->offset - a->offset < map_def_sz) {
> +			pr_warning("corrupted map section in %s: map \"%s\" too small "
> +				   "(%zd vs %d)\n",
> +				   obj->path, a->name, b->offset - a->offset,
> +				   map_def_sz);
>  			return -EINVAL;
>  		}
>  	}
> @@ -615,7 +617,7 @@ static int compare_bpf_map(const void *_a, const void *_b)
>  static int
>  bpf_object__init_maps(struct bpf_object *obj)
>  {
> -	int i, map_idx, nr_maps = 0;
> +	int i, map_idx, map_def_sz, nr_maps = 0;
>  	Elf_Scn *scn;
>  	Elf_Data *data;
>  	Elf_Data *symbols = obj->efile.symbols;
> @@ -658,6 +660,15 @@ bpf_object__init_maps(struct bpf_object *obj)
>  	if (!nr_maps)
>  		return 0;
>  
> +	/* Assume equally sized map definitions */
> +	map_def_sz = data->d_size / nr_maps;
> +	if (!data->d_size || (data->d_size % nr_maps) != 0) {
> +		pr_warning("unable to determine map definition size "
> +			   "section %s, %d maps in %zd bytes\n",
> +			   obj->path, nr_maps, data->d_size);
> +		return -EINVAL;
> +	}
> +
>  	obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
>  	if (!obj->maps) {
>  		pr_warning("alloc maps for object failed\n");
> @@ -690,7 +701,7 @@ bpf_object__init_maps(struct bpf_object *obj)
>  				      obj->efile.strtabidx,
>  				      sym.st_name);
>  		obj->maps[map_idx].offset = sym.st_value;
> -		if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) {
> +		if (sym.st_value + map_def_sz > data->d_size) {
>  			pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",
>  				   obj->path, map_name);
>  			return -EINVAL;
> @@ -704,12 +715,39 @@ bpf_object__init_maps(struct bpf_object *obj)
>  		pr_debug("map %d is \"%s\"\n", map_idx,
>  			 obj->maps[map_idx].name);
>  		def = (struct bpf_map_def *)(data->d_buf + sym.st_value);
> -		obj->maps[map_idx].def = *def;
> +		/*
> +		 * If the definition of the map in the object file fits in
> +		 * bpf_map_def, copy it.  Any extra fields in our version
> +		 * of bpf_map_def will default to zero as a result of the
> +		 * calloc above.
> +		 */
> +		if (map_def_sz <= sizeof(struct bpf_map_def)) {
> +			memcpy(&obj->maps[map_idx].def, def, map_def_sz);
> +		} else {
> +			/*
> +			 * Here the map structure being read is bigger than what
> +			 * we expect, truncate if the excess bits are all zero.
> +			 * If they are not zero, reject this map as
> +			 * incompatible.
> +			 */
> +			char *b;
> +			for (b = ((char *)def) + sizeof(struct bpf_map_def);
> +			     b < ((char *)def) + map_def_sz; b++) {
> +				if (*b != 0) {
> +					pr_warning("maps section in %s: \"%s\" "
> +						   "has unrecognized, non-zero "
> +						   "options\n",
> +						   obj->path, map_name);
> +					return -EINVAL;
> +				}
> +			}
> +			obj->maps[map_idx].def = *def;

I'm not too happy/comfortable with this way of copying the memory of
"def" (the type-cased struct bpf_map_def).  I guess it works, and is
part of the C-standard(?).


> +		}
>  		map_idx++;
>  	}
>  
>  	qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map);
> -	return bpf_object__validate_maps(obj);
> +	return bpf_object__validate_maps(obj, map_def_sz);
>  }
>  
>  static int bpf_object__elf_collect(struct bpf_object *obj)

Besides above comment, I think the patch is correct, based on what I
did in commit 156450d9d964 ("samples/bpf: make bpf_load.c code
compatible with ELF maps section changes").

  https://git.kernel.org/torvalds/c/156450d9d964

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
  2017-10-02 23:07   ` Alexei Starovoitov
  2017-10-03 14:03   ` Jesper Dangaard Brouer
@ 2017-10-03 14:11   ` Jesper Dangaard Brouer
  2017-10-04 13:58     ` Craig Gallek
  2017-10-04 13:58     ` Craig Gallek
  2 siblings, 2 replies; 15+ messages in thread
From: Jesper Dangaard Brouer @ 2017-10-03 14:11 UTC (permalink / raw)
  To: Craig Gallek
  Cc: Alexei Starovoitov, Daniel Borkmann, David S . Miller,
	Chonggang Li, netdev, brouer, Eric Leblond

On Mon,  2 Oct 2017 12:41:28 -0400
Craig Gallek <kraigatgoog@gmail.com> wrote:

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 4f402dcdf372..28b300868ad7 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -580,7 +580,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
>  }
>  
>  static int
> -bpf_object__validate_maps(struct bpf_object *obj)
> +bpf_object__validate_maps(struct bpf_object *obj, int map_def_sz)
>  {
>  	int i;
>  
> @@ -595,9 +595,11 @@ bpf_object__validate_maps(struct bpf_object *obj)
>  		const struct bpf_map *a = &obj->maps[i - 1];
>  		const struct bpf_map *b = &obj->maps[i];
>  
> -		if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
> -			pr_warning("corrupted map section in %s: map \"%s\" too small\n",
> -				   obj->path, a->name);
> +		if (b->offset - a->offset < map_def_sz) {
> +			pr_warning("corrupted map section in %s: map \"%s\" too small "
> +				   "(%zd vs %d)\n",
> +				   obj->path, a->name, b->offset - a->offset,
> +				   map_def_sz);
>  			return -EINVAL;

Hmm... one more comment.  You have just coded handling of ELF
map_def_sz which are smaller in a safe manor, but here this case will
get rejected (in bpf_object__validate_maps).  That cannot be the right
intend?

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-02 23:07   ` Alexei Starovoitov
@ 2017-10-03 14:39     ` Daniel Borkmann
  2017-10-04 13:59       ` Craig Gallek
  0 siblings, 1 reply; 15+ messages in thread
From: Daniel Borkmann @ 2017-10-03 14:39 UTC (permalink / raw)
  To: Alexei Starovoitov, Craig Gallek, Jesper Dangaard Brouer,
	David S . Miller
  Cc: Chonggang Li, netdev

On 10/03/2017 01:07 AM, Alexei Starovoitov wrote:
> On 10/2/17 9:41 AM, Craig Gallek wrote:
>> +    /* Assume equally sized map definitions */
>> +    map_def_sz = data->d_size / nr_maps;
>> +    if (!data->d_size || (data->d_size % nr_maps) != 0) {
>> +        pr_warning("unable to determine map definition size "
>> +               "section %s, %d maps in %zd bytes\n",
>> +               obj->path, nr_maps, data->d_size);
>> +        return -EINVAL;
>> +    }
>
> this approach is not as flexible as done by samples/bpf/bpf_load.c
> where it looks at every map independently by walking symtab,
> but I guess it's ok.

Regarding different map spec structs in a single prog: unless
we have a good use case why we would need it (and I'm not aware
of anything in particular), I would just go with a fixed size.
I did kind of similar sanity checks in bpf_fetch_maps_end() in
iproute2 loader as well.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 0/2] libbpf: support more map options
  2017-10-02 16:41 [PATCH net-next v2 0/2] libbpf: support more map options Craig Gallek
  2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
  2017-10-02 16:41 ` [PATCH net-next v2 2/2] libbpf: use map_flags when creating maps Craig Gallek
@ 2017-10-04  4:26 ` David Miller
  2 siblings, 0 replies; 15+ messages in thread
From: David Miller @ 2017-10-04  4:26 UTC (permalink / raw)
  To: kraigatgoog; +Cc: ast, daniel, brouer, chonggangli, netdev

From: Craig Gallek <kraigatgoog@gmail.com>
Date: Mon,  2 Oct 2017 12:41:27 -0400

> From: Craig Gallek <kraig@google.com>
> 
> The functional change to this series is the ability to use flags when
> creating maps from object files loaded by libbpf.  In order to do this,
> the first patch updates the library to handle map definitions that
> differ in size from libbpf's struct bpf_map_def.
> 
> For object files with a larger map definition, libbpf will continue to load
> if the unknown fields are all zero, otherwise the map is rejected.  If the
> map definition in the object file is smaller than expected, libbpf will use
> zero as a default value in the missing fields.

Judging by the feedback I anticipate another spin of this series.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-03 14:03   ` Jesper Dangaard Brouer
@ 2017-10-04 13:58     ` Craig Gallek
  2017-10-04 14:12       ` David Laight
  0 siblings, 1 reply; 15+ messages in thread
From: Craig Gallek @ 2017-10-04 13:58 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: Alexei Starovoitov, Daniel Borkmann, David S . Miller,
	Chonggang Li, netdev, Eric Leblond, Wangnan (F)

On Tue, Oct 3, 2017 at 10:03 AM, Jesper Dangaard Brouer
<brouer@redhat.com> wrote:
>
>
> First of all, thank you Craig for working on this.  As Alexei says, we
> need to improve tools/lib/bpf/libbpf and move towards converting users
> of bpf_load.c to this lib instead.
>
> Comments inlined below.
>
>> +                     obj->maps[map_idx].def = *def;
>
> I'm not too happy/comfortable with this way of copying the memory of
> "def" (the type-cased struct bpf_map_def).  I guess it works, and is
> part of the C-standard(?).

I believe this is a C++-ism.  I'm not sure if it was pulled into the
C99 standard or if it's just a gcc 'feature' now.  I kept it because
it was in the initial code, but I'm happy to do an explicit copy for
v3 if that looks better.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-03 14:11   ` Jesper Dangaard Brouer
@ 2017-10-04 13:58     ` Craig Gallek
  2017-10-04 13:58     ` Craig Gallek
  1 sibling, 0 replies; 15+ messages in thread
From: Craig Gallek @ 2017-10-04 13:58 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: Alexei Starovoitov, Daniel Borkmann, David S . Miller,
	Chonggang Li, netdev, Eric Leblond

On Tue, Oct 3, 2017 at 10:11 AM, Jesper Dangaard Brouer
<brouer@redhat.com> wrote:
> On Mon,  2 Oct 2017 12:41:28 -0400
> Craig Gallek <kraigatgoog@gmail.com> wrote:
>
>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
>> index 4f402dcdf372..28b300868ad7 100644
>> --- a/tools/lib/bpf/libbpf.c
>> +++ b/tools/lib/bpf/libbpf.c
>> @@ -580,7 +580,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
>>  }
>>
>>  static int
>> -bpf_object__validate_maps(struct bpf_object *obj)
>> +bpf_object__validate_maps(struct bpf_object *obj, int map_def_sz)
>>  {
>>       int i;
>>
>> @@ -595,9 +595,11 @@ bpf_object__validate_maps(struct bpf_object *obj)
>>               const struct bpf_map *a = &obj->maps[i - 1];
>>               const struct bpf_map *b = &obj->maps[i];
>>
>> -             if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
>> -                     pr_warning("corrupted map section in %s: map \"%s\" too small\n",
>> -                                obj->path, a->name);
>> +             if (b->offset - a->offset < map_def_sz) {
>> +                     pr_warning("corrupted map section in %s: map \"%s\" too small "
>> +                                "(%zd vs %d)\n",
>> +                                obj->path, a->name, b->offset - a->offset,
>> +                                map_def_sz);
>>                       return -EINVAL;
>
> Hmm... one more comment.  You have just coded handling of ELF
> map_def_sz which are smaller in a safe manor, but here this case will
> get rejected (in bpf_object__validate_maps).  That cannot be the right
> intend?

I think you are right, but my test program didn't catch this...
Perhaps an off-by-one (I only used slightly smaller map_def sizes).  I
suppose this entire function is unnecessary now.  Even the old version
wouldn't catch the case where the last offset was out of bounds?

> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-03 14:11   ` Jesper Dangaard Brouer
  2017-10-04 13:58     ` Craig Gallek
@ 2017-10-04 13:58     ` Craig Gallek
  1 sibling, 0 replies; 15+ messages in thread
From: Craig Gallek @ 2017-10-04 13:58 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: Alexei Starovoitov, Daniel Borkmann, David S . Miller,
	Chonggang Li, netdev, Eric Leblond

On Tue, Oct 3, 2017 at 10:11 AM, Jesper Dangaard Brouer
<brouer@redhat.com> wrote:
> On Mon,  2 Oct 2017 12:41:28 -0400
> Craig Gallek <kraigatgoog@gmail.com> wrote:
>
>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
>> index 4f402dcdf372..28b300868ad7 100644
>> --- a/tools/lib/bpf/libbpf.c
>> +++ b/tools/lib/bpf/libbpf.c
>> @@ -580,7 +580,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
>>  }
>>
>>  static int
>> -bpf_object__validate_maps(struct bpf_object *obj)
>> +bpf_object__validate_maps(struct bpf_object *obj, int map_def_sz)
>>  {
>>       int i;
>>
>> @@ -595,9 +595,11 @@ bpf_object__validate_maps(struct bpf_object *obj)
>>               const struct bpf_map *a = &obj->maps[i - 1];
>>               const struct bpf_map *b = &obj->maps[i];
>>
>> -             if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
>> -                     pr_warning("corrupted map section in %s: map \"%s\" too small\n",
>> -                                obj->path, a->name);
>> +             if (b->offset - a->offset < map_def_sz) {
>> +                     pr_warning("corrupted map section in %s: map \"%s\" too small "
>> +                                "(%zd vs %d)\n",
>> +                                obj->path, a->name, b->offset - a->offset,
>> +                                map_def_sz);
>>                       return -EINVAL;
>
> Hmm... one more comment.  You have just coded handling of ELF
> map_def_sz which are smaller in a safe manor, but here this case will
> get rejected (in bpf_object__validate_maps).  That cannot be the right
> intend?

I think you are right, but my test program didn't catch this...
Perhaps an off-by-one (I only used slightly smaller map_def sizes).  I
suppose this entire function is unnecessary now.  Even the old version
wouldn't catch the case where the last offset was out of bounds?

> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-03 14:39     ` Daniel Borkmann
@ 2017-10-04 13:59       ` Craig Gallek
  2017-10-04 19:27         ` Daniel Borkmann
  0 siblings, 1 reply; 15+ messages in thread
From: Craig Gallek @ 2017-10-04 13:59 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: Alexei Starovoitov, Jesper Dangaard Brouer, David S . Miller,
	Chonggang Li, netdev

On Tue, Oct 3, 2017 at 10:39 AM, Daniel Borkmann <daniel@iogearbox.net> wrote:
> On 10/03/2017 01:07 AM, Alexei Starovoitov wrote:
>>
>> On 10/2/17 9:41 AM, Craig Gallek wrote:
>>>
>>> +    /* Assume equally sized map definitions */
>>> +    map_def_sz = data->d_size / nr_maps;
>>> +    if (!data->d_size || (data->d_size % nr_maps) != 0) {
>>> +        pr_warning("unable to determine map definition size "
>>> +               "section %s, %d maps in %zd bytes\n",
>>> +               obj->path, nr_maps, data->d_size);
>>> +        return -EINVAL;
>>> +    }
>>
>>
>> this approach is not as flexible as done by samples/bpf/bpf_load.c
>> where it looks at every map independently by walking symtab,
>> but I guess it's ok.
>
>
> Regarding different map spec structs in a single prog: unless
> we have a good use case why we would need it (and I'm not aware
> of anything in particular), I would just go with a fixed size.
> I did kind of similar sanity checks in bpf_fetch_maps_end() in
> iproute2 loader as well.

Split vote?  I'm happy to try to make this work with varying sizes,
but I agree the usefulness seems low.  It would imply building map
sections with different definition structures and we would then need a
way to differentiate them.  If the goal is to allow for different map
definition structures, I don't think size alone is a sufficient
differentiator.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-04 13:58     ` Craig Gallek
@ 2017-10-04 14:12       ` David Laight
  0 siblings, 0 replies; 15+ messages in thread
From: David Laight @ 2017-10-04 14:12 UTC (permalink / raw)
  To: 'Craig Gallek', Jesper Dangaard Brouer
  Cc: Alexei Starovoitov, Daniel Borkmann, David S . Miller,
	Chonggang Li, netdev, Eric Leblond, Wangnan (F)

From: Craig Gallek
> Sent: 04 October 2017 14:58
> >> +                     obj->maps[map_idx].def = *def;
> >
> > I'm not too happy/comfortable with this way of copying the memory of
> > "def" (the type-cased struct bpf_map_def).  I guess it works, and is
> > part of the C-standard(?).
> 
> I believe this is a C++-ism.  I'm not sure if it was pulled into the
> C99 standard or if it's just a gcc 'feature' now.  I kept it because
> it was in the initial code, but I'm happy to do an explicit copy for
> v3 if that looks better.

Structure copies have been valid C for ages.

Annoyingly gcc will call memcpy() directly (not a 'private' function).

	David


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-04 13:59       ` Craig Gallek
@ 2017-10-04 19:27         ` Daniel Borkmann
  2017-10-04 19:54           ` Alexei Starovoitov
  0 siblings, 1 reply; 15+ messages in thread
From: Daniel Borkmann @ 2017-10-04 19:27 UTC (permalink / raw)
  To: Craig Gallek
  Cc: Alexei Starovoitov, Jesper Dangaard Brouer, David S . Miller,
	Chonggang Li, netdev

On 10/04/2017 03:59 PM, Craig Gallek wrote:
> On Tue, Oct 3, 2017 at 10:39 AM, Daniel Borkmann <daniel@iogearbox.net> wrote:
>> On 10/03/2017 01:07 AM, Alexei Starovoitov wrote:
>>> On 10/2/17 9:41 AM, Craig Gallek wrote:
>>>>
>>>> +    /* Assume equally sized map definitions */
>>>> +    map_def_sz = data->d_size / nr_maps;
>>>> +    if (!data->d_size || (data->d_size % nr_maps) != 0) {
>>>> +        pr_warning("unable to determine map definition size "
>>>> +               "section %s, %d maps in %zd bytes\n",
>>>> +               obj->path, nr_maps, data->d_size);
>>>> +        return -EINVAL;
>>>> +    }
>>>
>>> this approach is not as flexible as done by samples/bpf/bpf_load.c
>>> where it looks at every map independently by walking symtab,
>>> but I guess it's ok.
>>
>> Regarding different map spec structs in a single prog: unless
>> we have a good use case why we would need it (and I'm not aware
>> of anything in particular), I would just go with a fixed size.
>> I did kind of similar sanity checks in bpf_fetch_maps_end() in
>> iproute2 loader as well.
>
> Split vote?  I'm happy to try to make this work with varying sizes,
> but I agree the usefulness seems low.  It would imply building map
> sections with different definition structures and we would then need a
> way to differentiate them.  If the goal is to allow for different map
> definition structures, I don't think size alone is a sufficient
> differentiator.

They would still all need to go to maps section, but you would end
up going with different structs for map specs, where they all would
need to overlap for the members in order for this to work. E.g. you
would have maps of both structs sitting in map section of a single
prog ...

struct bpf_map_spec_v1 {
	__u32 type;
	__u32 size_key;
	__u32 size_value;
	__u32 max_elem;
};

struct bpf_map_spec_v2 {
	__u32 type;
	__u32 size_key;
	__u32 size_value;
	__u32 max_elem;
	__u32 flags;
};

... rather than just using single spec everywhere consistently, and
have the members zeroed that are unused or such, so if there's no
real use-case for different structs (cannot think of any right now),
lets not add complexity for it until it's really required.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size
  2017-10-04 19:27         ` Daniel Borkmann
@ 2017-10-04 19:54           ` Alexei Starovoitov
  0 siblings, 0 replies; 15+ messages in thread
From: Alexei Starovoitov @ 2017-10-04 19:54 UTC (permalink / raw)
  To: Daniel Borkmann, Craig Gallek
  Cc: Jesper Dangaard Brouer, David S . Miller, Chonggang Li, netdev

On 10/4/17 12:27 PM, Daniel Borkmann wrote:
> On 10/04/2017 03:59 PM, Craig Gallek wrote:
>> On Tue, Oct 3, 2017 at 10:39 AM, Daniel Borkmann
>> <daniel@iogearbox.net> wrote:
>>> On 10/03/2017 01:07 AM, Alexei Starovoitov wrote:
>>>> On 10/2/17 9:41 AM, Craig Gallek wrote:
>>>>>
>>>>> +    /* Assume equally sized map definitions */
>>>>> +    map_def_sz = data->d_size / nr_maps;
>>>>> +    if (!data->d_size || (data->d_size % nr_maps) != 0) {
>>>>> +        pr_warning("unable to determine map definition size "
>>>>> +               "section %s, %d maps in %zd bytes\n",
>>>>> +               obj->path, nr_maps, data->d_size);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>
>>>> this approach is not as flexible as done by samples/bpf/bpf_load.c
>>>> where it looks at every map independently by walking symtab,
>>>> but I guess it's ok.
>>>
>>> Regarding different map spec structs in a single prog: unless
>>> we have a good use case why we would need it (and I'm not aware
>>> of anything in particular), I would just go with a fixed size.
>>> I did kind of similar sanity checks in bpf_fetch_maps_end() in
>>> iproute2 loader as well.
>>
>> Split vote?  I'm happy to try to make this work with varying sizes,
>> but I agree the usefulness seems low.  It would imply building map
>> sections with different definition structures and we would then need a
>> way to differentiate them.  If the goal is to allow for different map
>> definition structures, I don't think size alone is a sufficient
>> differentiator.
>
> They would still all need to go to maps section, but you would end
> up going with different structs for map specs, where they all would
> need to overlap for the members in order for this to work. E.g. you
> would have maps of both structs sitting in map section of a single
> prog ...
>
> struct bpf_map_spec_v1 {
>     __u32 type;
>     __u32 size_key;
>     __u32 size_value;
>     __u32 max_elem;
> };
>
> struct bpf_map_spec_v2 {
>     __u32 type;
>     __u32 size_key;
>     __u32 size_value;
>     __u32 max_elem;
>     __u32 flags;
> };
>
> ... rather than just using single spec everywhere consistently, and
> have the members zeroed that are unused or such, so if there's no
> real use-case for different structs (cannot think of any right now),
> lets not add complexity for it until it's really required.

makes sense to me :)

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-10-04 19:54 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-02 16:41 [PATCH net-next v2 0/2] libbpf: support more map options Craig Gallek
2017-10-02 16:41 ` [PATCH net-next v2 1/2] libbpf: parse maps sections of varying size Craig Gallek
2017-10-02 23:07   ` Alexei Starovoitov
2017-10-03 14:39     ` Daniel Borkmann
2017-10-04 13:59       ` Craig Gallek
2017-10-04 19:27         ` Daniel Borkmann
2017-10-04 19:54           ` Alexei Starovoitov
2017-10-03 14:03   ` Jesper Dangaard Brouer
2017-10-04 13:58     ` Craig Gallek
2017-10-04 14:12       ` David Laight
2017-10-03 14:11   ` Jesper Dangaard Brouer
2017-10-04 13:58     ` Craig Gallek
2017-10-04 13:58     ` Craig Gallek
2017-10-02 16:41 ` [PATCH net-next v2 2/2] libbpf: use map_flags when creating maps Craig Gallek
2017-10-04  4:26 ` [PATCH net-next v2 0/2] libbpf: support more map options David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.