diff mbox series

[v2,bpf-next,1/2] bpftool: Use print_entry_error() in case of ENOENT when dumping

Message ID 20190412030322.15494-1-bpoirier@suse.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series [v2,bpf-next,1/2] bpftool: Use print_entry_error() in case of ENOENT when dumping | expand

Commit Message

Benjamin Poirier April 12, 2019, 3:03 a.m. UTC
Commit bf598a8f0f77 ("bpftool: Improve handling of ENOENT on map dumps")
used print_entry_plain() in case of ENOENT because that function provided
the desired formatting. However, that commit actually introduces dead code.
Per-cpu maps are zero-filled. When reading them, it's all or nothing. There
will never be a case where some cpus have an entry and others don't.

The truth is that ENOENT is an error case. So rework print_entry_error() to
provide the desired formatting.

Note that this commit changes the output format in case of errors other
than ENOENT.

example before:
key:
00 00 00 00
value:
No space left on device
[...]

example after:
key: 00 00 00 00
value:
No space left on device
[...]

The ENOENT case is unchanged:
key: 00 00 00 00  value: 14 5b 00 00 00 00 00 00
key: 01 00 00 00  value: <no entry>
[...]

Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
---
 tools/bpf/bpftool/map.c | 34 ++++++++++++++--------------------
 1 file changed, 14 insertions(+), 20 deletions(-)

Comments

Quentin Monnet April 12, 2019, 10:28 a.m. UTC | #1
2019-04-12 12:03 UTC+0900 ~ Benjamin Poirier <bpoirier@suse.com>
> Commit bf598a8f0f77 ("bpftool: Improve handling of ENOENT on map dumps")
> used print_entry_plain() in case of ENOENT because that function provided
> the desired formatting. However, that commit actually introduces dead code.
> Per-cpu maps are zero-filled. When reading them, it's all or nothing. There
> will never be a case where some cpus have an entry and others don't.
> 
> The truth is that ENOENT is an error case. So rework print_entry_error() to
> provide the desired formatting.
> 
> Note that this commit changes the output format in case of errors other
> than ENOENT.
> 
> example before:
> key:
> 00 00 00 00
> value:
> No space left on device
> [...]
> 
> example after:
> key: 00 00 00 00
> value:
> No space left on device
> [...]
> 
> The ENOENT case is unchanged:
> key: 00 00 00 00  value: 14 5b 00 00 00 00 00 00
> key: 01 00 00 00  value: <no entry>
> [...]
> 
> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
> ---
>   tools/bpf/bpftool/map.c | 34 ++++++++++++++--------------------
>   1 file changed, 14 insertions(+), 20 deletions(-)
> 
> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
> index e96903078991..71840faaeab5 100644
> --- a/tools/bpf/bpftool/map.c
> +++ b/tools/bpf/bpftool/map.c
> @@ -261,20 +261,19 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
>   }
>   
>   static void print_entry_error(struct bpf_map_info *info, unsigned char *key,
> -			      const char *value)
> +			      const char *value, bool single_line)

Nit: if you respin the series, could you rename "value" into "error_msg" 
or something like this to better indicate we never pass an actual map 
value to the function?

>   {
> -	int value_size = strlen(value);
> -	bool single_line, break_names;
> +	bool break_names;
>   
> -	break_names = info->key_size > 16 || value_size > 16;
> -	single_line = info->key_size + value_size <= 24 && !break_names;
> +	break_names = info->key_size > 16;
> +	single_line = single_line && !break_names;

If I understand correctly, this will also change formatting when error 
message is short (shorter than 16 characters: the "value" line will now 
be unconditionally split, even for short error messages (other than "<no 
entry>")). Why removing the condition on value_size > 16? (This is just 
a remark, I am not against changing it.)

>   
>   	printf("key:%c", break_names ? '\n' : ' ');
>   	fprint_hex(stdout, key, info->key_size, " ");
>   
>   	printf(single_line ? "  " : "\n");
>   
> -	printf("value:%c%s", break_names ? '\n' : ' ', value);
> +	printf("value:%c%s", single_line ? ' ' : '\n', value);
>   
>   	printf("\n");
>   }

[...]
Benjamin Poirier April 12, 2019, 10:49 p.m. UTC | #2
On 2019/04/12 11:28, Quentin Monnet wrote:
[...]
> 
> >   {
> > -	int value_size = strlen(value);
> > -	bool single_line, break_names;
> > +	bool break_names;
> > -	break_names = info->key_size > 16 || value_size > 16;
> > -	single_line = info->key_size + value_size <= 24 && !break_names;
> > +	break_names = info->key_size > 16;
> > +	single_line = single_line && !break_names;
> 
> If I understand correctly, this will also change formatting when error
> message is short (shorter than 16 characters: the "value" line will now be
> unconditionally split, even for short error messages (other than "<no
> entry>")). Why removing the condition on value_size > 16? (This is just a
> remark, I am not against changing it.)
> 

With this patch, the error messages from bpftool ("<no entry>", "<cannot
read>"), which are chosen to be short, appear on the same line and the
messages from strerror appear on a separate line. Because those latter
messages are from a source external to bpftool and their length is
unknown ahead of time, I felt it led to a more predictable output to
consistently put them on their own line.

To be honest, I don't think the formatting in those print_entry_*
functions should change according to the length in any case. I think the
key and value for each entry should always be on the same line for ease
of grepping. A followup patch maybe...
Jakub Kicinski April 12, 2019, 11:53 p.m. UTC | #3
On Sat, 13 Apr 2019 07:49:24 +0900, Benjamin Poirier wrote:
> To be honest, I don't think the formatting in those print_entry_*
> functions should change according to the length in any case. I think the
> key and value for each entry should always be on the same line for ease
> of grepping. A followup patch maybe...

No, no, please never grep bpftool output.  We have JSON output,
please use JQ: http://manpages.ubuntu.com/manpages/bionic/man1/jq.1.html
Jakub Kicinski April 12, 2019, 11:57 p.m. UTC | #4
On Fri, 12 Apr 2019 12:03:21 +0900, Benjamin Poirier wrote:
> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
> index e96903078991..71840faaeab5 100644
> --- a/tools/bpf/bpftool/map.c
> +++ b/tools/bpf/bpftool/map.c
> @@ -261,20 +261,19 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
>  }
>  
>  static void print_entry_error(struct bpf_map_info *info, unsigned char *key,
> -			      const char *value)
> +			      const char *value, bool single_line)
>  {
> -	int value_size = strlen(value);
> -	bool single_line, break_names;
> +	bool break_names;

I'd rather you kept the strlen() and 16 char limitation logic.

> -	break_names = info->key_size > 16 || value_size > 16;
> -	single_line = info->key_size + value_size <= 24 && !break_names;
> +	break_names = info->key_size > 16;
> +	single_line = single_line && !break_names;
>  
>  	printf("key:%c", break_names ? '\n' : ' ');
>  	fprint_hex(stdout, key, info->key_size, " ");
>  
>  	printf(single_line ? "  " : "\n");
>  
> -	printf("value:%c%s", break_names ? '\n' : ' ', value);
> +	printf("value:%c%s", single_line ? ' ' : '\n', value);
>  
>  	printf("\n");
>  }
Benjamin Poirier April 14, 2019, 11:29 p.m. UTC | #5
On 2019/04/12 16:53, Jakub Kicinski wrote:
> On Sat, 13 Apr 2019 07:49:24 +0900, Benjamin Poirier wrote:
> > To be honest, I don't think the formatting in those print_entry_*
> > functions should change according to the length in any case. I think the
> > key and value for each entry should always be on the same line for ease
> > of grepping. A followup patch maybe...
> 
> No, no, please never grep bpftool output.  We have JSON output,
> please use JQ: http://manpages.ubuntu.com/manpages/bionic/man1/jq.1.html
> 

Fair enough. I didn't know about jq, thanks.
diff mbox series

Patch

diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index e96903078991..71840faaeab5 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -261,20 +261,19 @@  static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
 }
 
 static void print_entry_error(struct bpf_map_info *info, unsigned char *key,
-			      const char *value)
+			      const char *value, bool single_line)
 {
-	int value_size = strlen(value);
-	bool single_line, break_names;
+	bool break_names;
 
-	break_names = info->key_size > 16 || value_size > 16;
-	single_line = info->key_size + value_size <= 24 && !break_names;
+	break_names = info->key_size > 16;
+	single_line = single_line && !break_names;
 
 	printf("key:%c", break_names ? '\n' : ' ');
 	fprint_hex(stdout, key, info->key_size, " ");
 
 	printf(single_line ? "  " : "\n");
 
-	printf("value:%c%s", break_names ? '\n' : ' ', value);
+	printf("value:%c%s", single_line ? ' ' : '\n', value);
 
 	printf("\n");
 }
@@ -298,11 +297,7 @@  static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
 
 		if (info->value_size) {
 			printf("value:%c", break_names ? '\n' : ' ');
-			if (value)
-				fprint_hex(stdout, value, info->value_size,
-					   " ");
-			else
-				printf("<no entry>");
+			fprint_hex(stdout, value, info->value_size, " ");
 		}
 
 		printf("\n");
@@ -321,11 +316,8 @@  static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
 			for (i = 0; i < n; i++) {
 				printf("value (CPU %02d):%c",
 				       i, info->value_size > 16 ? '\n' : ' ');
-				if (value)
-					fprint_hex(stdout, value + i * step,
-						   info->value_size, " ");
-				else
-					printf("<no entry>");
+				fprint_hex(stdout, value + i * step,
+					   info->value_size, " ");
 				printf("\n");
 			}
 		}
@@ -722,11 +714,13 @@  static int dump_map_elem(int fd, void *key, void *value,
 		jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
 		jsonw_end_object(json_wtr);
 	} else {
+		const char *msg = NULL;
+
 		if (errno == ENOENT)
-			print_entry_plain(map_info, key, NULL);
-		else
-			print_entry_error(map_info, key,
-					  strerror(lookup_errno));
+			msg = "<no entry>";
+
+		print_entry_error(map_info, key,
+				  msg ? : strerror(lookup_errno), !!msg);
 	}
 
 	return 0;