diff mbox series

[bpf-next,v2] bpftool: Dump map id instead of value for map_of_maps types

Message ID 20230424090935.52707-1-kuro@kuroa.me (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series [bpf-next,v2] bpftool: Dump map id instead of value for map_of_maps types | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/cc_maintainers success CCed 13 of 13 maintainers
netdev/build_clang fail Errors and warnings before: 13 this patch: 13
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 14 this patch: 14
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-16 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-34 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-36 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32 on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-32 success Logs for test_verifier on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on s390x with gcc

Commit Message

Xueming Feng April 24, 2023, 9:09 a.m. UTC
When using `bpftool map dump` in plain format, it is usually
more convenient to show the inner map id instead of raw value.
Changing this behavior would help with quick debugging with
`bpftool`, without disrupting scripted behavior. Since user
could dump the inner map with id, and need to convert value.

Signed-off-by: Xueming Feng <kuro@kuroa.me>
---
Changes in v2:
  - Fix commit message grammar.
	- Change `print_uint` to only print to stdout, make `arg` const, and rename 
	  `n` to `arg_size`.
  - Make `print_uint` able to take any size of argument up to `unsigned long`, 
		and print it as unsigned decimal.

Thanks for the review and suggestions! I have changed my patch accordingly.
There is a possibility that `arg_size` is larger than `unsigned long`,
but previous review suggested that it should be up to the caller function to 
set `arg_size` correctly. So I didn't add check for that, should I?

 tools/bpf/bpftool/main.c | 15 +++++++++++++++
 tools/bpf/bpftool/main.h |  1 +
 tools/bpf/bpftool/map.c  |  9 +++++++--
 3 files changed, 23 insertions(+), 2 deletions(-)

Comments

Kui-Feng Lee April 24, 2023, 4:44 p.m. UTC | #1
On 4/24/23 02:09, Xueming Feng wrote:
> When using `bpftool map dump` in plain format, it is usually
> more convenient to show the inner map id instead of raw value.
> Changing this behavior would help with quick debugging with
> `bpftool`, without disrupting scripted behavior. Since user
> could dump the inner map with id, and need to convert value.
> 
> Signed-off-by: Xueming Feng <kuro@kuroa.me>
> ---
> Changes in v2:
>    - Fix commit message grammar.
> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
> 	  `n` to `arg_size`.
>    - Make `print_uint` able to take any size of argument up to `unsigned long`,
> 		and print it as unsigned decimal.
> 
> Thanks for the review and suggestions! I have changed my patch accordingly.
> There is a possibility that `arg_size` is larger than `unsigned long`,
> but previous review suggested that it should be up to the caller function to
> set `arg_size` correctly. So I didn't add check for that, should I?
> 
>   tools/bpf/bpftool/main.c | 15 +++++++++++++++
>   tools/bpf/bpftool/main.h |  1 +
>   tools/bpf/bpftool/map.c  |  9 +++++++--
>   3 files changed, 23 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
> index 08d0ac543c67..810c0dc10ecb 100644
> --- a/tools/bpf/bpftool/main.c
> +++ b/tools/bpf/bpftool/main.c
> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>   	return 0;
>   }
>   
> +void print_uint(const void *arg, unsigned int arg_size)
> +{
> +	const unsigned char *data = arg;
> +	unsigned long val = 0ul;
> +
> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> +		memcpy(&val, data, arg_size);
> +	#else
> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
> +		       data, arg_size);
> +	#endif

Is it possible that arg_size is bigger than sizeof(val)?

> +
> +	fprintf(stdout, "%lu", val);
> +}
> +
>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>   {
>   	unsigned char *data = arg;
> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> index 0ef373cef4c7..0de671423431 100644
> --- a/tools/bpf/bpftool/main.h
> +++ b/tools/bpf/bpftool/main.h
> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>   
>   bool is_prefix(const char *pfx, const char *str);
>   int detect_common_prefix(const char *arg, ...);
> +void print_uint(const void *arg, unsigned int arg_size);
>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>   void usage(void) __noreturn;
>   
> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
> index aaeb8939e137..f5be4c0564cf 100644
> --- a/tools/bpf/bpftool/map.c
> +++ b/tools/bpf/bpftool/map.c
> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>   		}
>   
>   		if (info->value_size) {
> -			printf("value:%c", break_names ? '\n' : ' ');
> -			fprint_hex(stdout, value, info->value_size, " ");
> +			if (map_is_map_of_maps(info->type)) {
> +				printf("id:%c", break_names ? '\n' : ' ');
> +				print_uint(value, info->value_size);
> +			} else {
> +				printf("value:%c", break_names ? '\n' : ' ');
> +				fprint_hex(stdout, value, info->value_size, " ");
> +			}
>   		}
>   
>   		printf("\n");
Yonghong Song April 25, 2023, 1:07 a.m. UTC | #2
On 4/24/23 2:09 AM, Xueming Feng wrote:
> When using `bpftool map dump` in plain format, it is usually
> more convenient to show the inner map id instead of raw value.
> Changing this behavior would help with quick debugging with
> `bpftool`, without disrupting scripted behavior. Since user
> could dump the inner map with id, and need to convert value.
> 
> Signed-off-by: Xueming Feng <kuro@kuroa.me>
> ---
> Changes in v2:
>    - Fix commit message grammar.
> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
> 	  `n` to `arg_size`.
>    - Make `print_uint` able to take any size of argument up to `unsigned long`,
> 		and print it as unsigned decimal.
> 
> Thanks for the review and suggestions! I have changed my patch accordingly.
> There is a possibility that `arg_size` is larger than `unsigned long`,
> but previous review suggested that it should be up to the caller function to
> set `arg_size` correctly. So I didn't add check for that, should I?
> 
>   tools/bpf/bpftool/main.c | 15 +++++++++++++++
>   tools/bpf/bpftool/main.h |  1 +
>   tools/bpf/bpftool/map.c  |  9 +++++++--
>   3 files changed, 23 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
> index 08d0ac543c67..810c0dc10ecb 100644
> --- a/tools/bpf/bpftool/main.c
> +++ b/tools/bpf/bpftool/main.c
> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>   	return 0;
>   }
>   
> +void print_uint(const void *arg, unsigned int arg_size)
> +{
> +	const unsigned char *data = arg;
> +	unsigned long val = 0ul;
> +
> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> +		memcpy(&val, data, arg_size);
> +	#else
> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
> +		       data, arg_size);
> +	#endif
> +
> +	fprintf(stdout, "%lu", val);
> +}
> +
>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>   {
>   	unsigned char *data = arg;
> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> index 0ef373cef4c7..0de671423431 100644
> --- a/tools/bpf/bpftool/main.h
> +++ b/tools/bpf/bpftool/main.h
> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>   
>   bool is_prefix(const char *pfx, const char *str);
>   int detect_common_prefix(const char *arg, ...);
> +void print_uint(const void *arg, unsigned int arg_size);
>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>   void usage(void) __noreturn;
>   
> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
> index aaeb8939e137..f5be4c0564cf 100644
> --- a/tools/bpf/bpftool/map.c
> +++ b/tools/bpf/bpftool/map.c
> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>   		}
>   
>   		if (info->value_size) {
> -			printf("value:%c", break_names ? '\n' : ' ');
> -			fprint_hex(stdout, value, info->value_size, " ");
> +			if (map_is_map_of_maps(info->type)) {
> +				printf("id:%c", break_names ? '\n' : ' ');
> +				print_uint(value, info->value_size);

For all map_in_map types, the inner map value size is 32bit int which 
represents a fd (for map creation) and a id (for map info), e.g., in
show_prog_maps() in prog.c. So maybe we can simplify the code as below:
	printf("id: %u", *(unsigned int *)value);


> +			} else {
> +				printf("value:%c", break_names ? '\n' : ' ');
> +				fprint_hex(stdout, value, info->value_size, " ");
> +			}
>   		}
>   
>   		printf("\n");
Xueming Feng April 25, 2023, 3:58 a.m. UTC | #3
> On 4/24/23 02:09, Xueming Feng wrote:
>> When using `bpftool map dump` in plain format, it is usually
>> more convenient to show the inner map id instead of raw value.
>> Changing this behavior would help with quick debugging with
>> `bpftool`, without disrupting scripted behavior. Since user
>> could dump the inner map with id, and need to convert value.
>> 
>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>> ---
>> Changes in v2:
>>    - Fix commit message grammar.
>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>> 	  `n` to `arg_size`.
>>    - Make `print_uint` able to take any size of argument up to `unsigned long`,
>> 		and print it as unsigned decimal.
>> 
>> Thanks for the review and suggestions! I have changed my patch accordingly.
>> There is a possibility that `arg_size` is larger than `unsigned long`,
>> but previous review suggested that it should be up to the caller function to
>> set `arg_size` correctly. So I didn't add check for that, should I?
>> 
>>   tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>   tools/bpf/bpftool/main.h |  1 +
>>   tools/bpf/bpftool/map.c  |  9 +++++++--
>>   3 files changed, 23 insertions(+), 2 deletions(-)
>> 
>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>> index 08d0ac543c67..810c0dc10ecb 100644
>> --- a/tools/bpf/bpftool/main.c
>> +++ b/tools/bpf/bpftool/main.c
>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>   	return 0;
>>   }
>>   
>> +void print_uint(const void *arg, unsigned int arg_size)
>> +{
>> +	const unsigned char *data = arg;
>> +	unsigned long val = 0ul;
>> +
>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>> +		memcpy(&val, data, arg_size);
>> +	#else
>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>> +		       data, arg_size);
>> +	#endif

On Mon, 24 Apr 2023 09:44:18 -0700, Kui-Feng Lee wrote:
> Is it possible that arg_size is bigger than sizeof(val)?

Yes it is possible, I had the thought of adding a check. But as I mentioned 
before the diff section, previous review 
https://lore.kernel.org/bpf/20230421101154.23690-1-kuro@kuroa.me/ suggested that 
I should leave it to the caller function to behave. If I were to add a check, 
what action do you recommend if the check fails? Print a '-1', do nothing,
or just use the first sizeof(val) bytes?

>> +
>> +	fprintf(stdout, "%lu", val);
>> +}
>> +
>>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>   {
>>   	unsigned char *data = arg;
>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>> index 0ef373cef4c7..0de671423431 100644
>> --- a/tools/bpf/bpftool/main.h
>> +++ b/tools/bpf/bpftool/main.h
>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>   
>>   bool is_prefix(const char *pfx, const char *str);
>>   int detect_common_prefix(const char *arg, ...);
>> +void print_uint(const void *arg, unsigned int arg_size);
>>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>   void usage(void) __noreturn;
>>   
>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>> index aaeb8939e137..f5be4c0564cf 100644
>> --- a/tools/bpf/bpftool/map.c
>> +++ b/tools/bpf/bpftool/map.c
>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>   		}
>>   
>>   		if (info->value_size) {
>> -			printf("value:%c", break_names ? '\n' : ' ');
>> -			fprint_hex(stdout, value, info->value_size, " ");
>> +			if (map_is_map_of_maps(info->type)) {
>> +				printf("id:%c", break_names ? '\n' : ' ');
>> +				print_uint(value, info->value_size);
>> +			} else {
>> +				printf("value:%c", break_names ? '\n' : ' ');
>> +				fprint_hex(stdout, value, info->value_size, " ");
>> +			}
>>   		}
>>   
>>   		printf("\n");
Xueming Feng April 25, 2023, 4:10 a.m. UTC | #4
> On 4/24/23 2:09 AM, Xueming Feng wrote:
>> When using `bpftool map dump` in plain format, it is usually
>> more convenient to show the inner map id instead of raw value.
>> Changing this behavior would help with quick debugging with
>> `bpftool`, without disrupting scripted behavior. Since user
>> could dump the inner map with id, and need to convert value.
>> 
>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>> ---
>> Changes in v2:
>>    - Fix commit message grammar.
>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>> 	  `n` to `arg_size`.
>>    - Make `print_uint` able to take any size of argument up to `unsigned long`,
>> 		and print it as unsigned decimal.
>> 
>> Thanks for the review and suggestions! I have changed my patch accordingly.
>> There is a possibility that `arg_size` is larger than `unsigned long`,
>> but previous review suggested that it should be up to the caller function to
>> set `arg_size` correctly. So I didn't add check for that, should I?
>> 
>>   tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>   tools/bpf/bpftool/main.h |  1 +
>>   tools/bpf/bpftool/map.c  |  9 +++++++--
>>   3 files changed, 23 insertions(+), 2 deletions(-)
>> 
>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>> index 08d0ac543c67..810c0dc10ecb 100644
>> --- a/tools/bpf/bpftool/main.c
>> +++ b/tools/bpf/bpftool/main.c
>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>   	return 0;
>>   }
>>   
>> +void print_uint(const void *arg, unsigned int arg_size)
>> +{
>> +	const unsigned char *data = arg;
>> +	unsigned long val = 0ul;
>> +
>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>> +		memcpy(&val, data, arg_size);
>> +	#else
>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>> +		       data, arg_size);
>> +	#endif
>> +
>> +	fprintf(stdout, "%lu", val);
>> +}
>> +
>>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>   {
>>   	unsigned char *data = arg;
>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>> index 0ef373cef4c7..0de671423431 100644
>> --- a/tools/bpf/bpftool/main.h
>> +++ b/tools/bpf/bpftool/main.h
>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>   
>>   bool is_prefix(const char *pfx, const char *str);
>>   int detect_common_prefix(const char *arg, ...);
>> +void print_uint(const void *arg, unsigned int arg_size);
>>   void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>   void usage(void) __noreturn;
>>   
>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>> index aaeb8939e137..f5be4c0564cf 100644
>> --- a/tools/bpf/bpftool/map.c
>> +++ b/tools/bpf/bpftool/map.c
>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>   		}
>>   
>>   		if (info->value_size) {
>> -			printf("value:%c", break_names ? '\n' : ' ');
>> -			fprint_hex(stdout, value, info->value_size, " ");
>> +			if (map_is_map_of_maps(info->type)) {
>> +				printf("id:%c", break_names ? '\n' : ' ');
>1> +				print_uint(value, info->value_size);

On Mon, 24 Apr 2023 18:07:27 -0700, Yonghong Song wrote:
> For all map_in_map types, the inner map value size is 32bit int which 
> represents a fd (for map creation) and a id (for map info), e.g., in
> show_prog_maps() in prog.c. So maybe we can simplify the code as below:
> 	printf("id: %u", *(unsigned int *)value);

That is true, maybe the "id" could also be changed to "map_id" to follow the
convention. Do you think that `print_uint` could be useful in the future? 
If that is the case, should I keep using it here as an example usage, and to 
avoid dead code? Or should I just remove it?

>> +			} else {
>> +				printf("value:%c", break_names ? '\n' : ' ');
>> +				fprint_hex(stdout, value, info->value_size, " ");
>> +			}
>>   		}
>>   
>>   		printf("\n");
Kui-Feng Lee April 25, 2023, 5:19 a.m. UTC | #5
On 4/24/23 20:58, Xueming Feng wrote:
>> On 4/24/23 02:09, Xueming Feng wrote:
>>> When using `bpftool map dump` in plain format, it is usually
>>> more convenient to show the inner map id instead of raw value.
>>> Changing this behavior would help with quick debugging with
>>> `bpftool`, without disrupting scripted behavior. Since user
>>> could dump the inner map with id, and need to convert value.
>>>
>>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>>> ---
>>> Changes in v2:
>>>     - Fix commit message grammar.
>>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>>> 	  `n` to `arg_size`.
>>>     - Make `print_uint` able to take any size of argument up to `unsigned long`,
>>> 		and print it as unsigned decimal.
>>>
>>> Thanks for the review and suggestions! I have changed my patch accordingly.
>>> There is a possibility that `arg_size` is larger than `unsigned long`,
>>> but previous review suggested that it should be up to the caller function to
>>> set `arg_size` correctly. So I didn't add check for that, should I?
>>>
>>>    tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>>    tools/bpf/bpftool/main.h |  1 +
>>>    tools/bpf/bpftool/map.c  |  9 +++++++--
>>>    3 files changed, 23 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>>> index 08d0ac543c67..810c0dc10ecb 100644
>>> --- a/tools/bpf/bpftool/main.c
>>> +++ b/tools/bpf/bpftool/main.c
>>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>>    	return 0;
>>>    }
>>>    
>>> +void print_uint(const void *arg, unsigned int arg_size)
>>> +{
>>> +	const unsigned char *data = arg;
>>> +	unsigned long val = 0ul;
>>> +
>>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>>> +		memcpy(&val, data, arg_size);
>>> +	#else
>>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>>> +		       data, arg_size);
>>> +	#endif
> 
> On Mon, 24 Apr 2023 09:44:18 -0700, Kui-Feng Lee wrote:
>> Is it possible that arg_size is bigger than sizeof(val)?
> 
> Yes it is possible, I had the thought of adding a check. But as I mentioned
> before the diff section, previous review
> https://lore.kernel.org/bpf/20230421101154.23690-1-kuro@kuroa.me/ suggested that
> I should leave it to the caller function to behave. If I were to add a check,
> what action do you recommend if the check fails? Print a '-1', do nothing,
> or just use the first sizeof(val) bytes?

In the previous patch, it may have integer overflow, but it is never 
buffer underrun.  This version uses memcpy and may cause buffer underrun 
if arg_size is bigger than sizeof(val).  I would say that at least 
prevent buffer underrun from happening.

> 
>>> +
>>> +	fprintf(stdout, "%lu", val);
>>> +}
>>> +
>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>>    {
>>>    	unsigned char *data = arg;
>>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>>> index 0ef373cef4c7..0de671423431 100644
>>> --- a/tools/bpf/bpftool/main.h
>>> +++ b/tools/bpf/bpftool/main.h
>>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>>    
>>>    bool is_prefix(const char *pfx, const char *str);
>>>    int detect_common_prefix(const char *arg, ...);
>>> +void print_uint(const void *arg, unsigned int arg_size);
>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>>    void usage(void) __noreturn;
>>>    
>>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>>> index aaeb8939e137..f5be4c0564cf 100644
>>> --- a/tools/bpf/bpftool/map.c
>>> +++ b/tools/bpf/bpftool/map.c
>>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>>    		}
>>>    
>>>    		if (info->value_size) {
>>> -			printf("value:%c", break_names ? '\n' : ' ');
>>> -			fprint_hex(stdout, value, info->value_size, " ");
>>> +			if (map_is_map_of_maps(info->type)) {
>>> +				printf("id:%c", break_names ? '\n' : ' ');
>>> +				print_uint(value, info->value_size);
>>> +			} else {
>>> +				printf("value:%c", break_names ? '\n' : ' ');
>>> +				fprint_hex(stdout, value, info->value_size, " ");
>>> +			}
>>>    		}
>>>    
>>>    		printf("\n");
Yonghong Song April 25, 2023, 5:58 a.m. UTC | #6
On 4/24/23 9:10 PM, Xueming Feng wrote:
>> On 4/24/23 2:09 AM, Xueming Feng wrote:
>>> When using `bpftool map dump` in plain format, it is usually
>>> more convenient to show the inner map id instead of raw value.
>>> Changing this behavior would help with quick debugging with
>>> `bpftool`, without disrupting scripted behavior. Since user
>>> could dump the inner map with id, and need to convert value.
>>>
>>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>>> ---
>>> Changes in v2:
>>>     - Fix commit message grammar.
>>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>>> 	  `n` to `arg_size`.
>>>     - Make `print_uint` able to take any size of argument up to `unsigned long`,
>>> 		and print it as unsigned decimal.
>>>
>>> Thanks for the review and suggestions! I have changed my patch accordingly.
>>> There is a possibility that `arg_size` is larger than `unsigned long`,
>>> but previous review suggested that it should be up to the caller function to
>>> set `arg_size` correctly. So I didn't add check for that, should I?
>>>
>>>    tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>>    tools/bpf/bpftool/main.h |  1 +
>>>    tools/bpf/bpftool/map.c  |  9 +++++++--
>>>    3 files changed, 23 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>>> index 08d0ac543c67..810c0dc10ecb 100644
>>> --- a/tools/bpf/bpftool/main.c
>>> +++ b/tools/bpf/bpftool/main.c
>>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>>    	return 0;
>>>    }
>>>    
>>> +void print_uint(const void *arg, unsigned int arg_size)
>>> +{
>>> +	const unsigned char *data = arg;
>>> +	unsigned long val = 0ul;
>>> +
>>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>>> +		memcpy(&val, data, arg_size);
>>> +	#else
>>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>>> +		       data, arg_size);
>>> +	#endif
>>> +
>>> +	fprintf(stdout, "%lu", val);
>>> +}
>>> +
>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>>    {
>>>    	unsigned char *data = arg;
>>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>>> index 0ef373cef4c7..0de671423431 100644
>>> --- a/tools/bpf/bpftool/main.h
>>> +++ b/tools/bpf/bpftool/main.h
>>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>>    
>>>    bool is_prefix(const char *pfx, const char *str);
>>>    int detect_common_prefix(const char *arg, ...);
>>> +void print_uint(const void *arg, unsigned int arg_size);
>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>>    void usage(void) __noreturn;
>>>    
>>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>>> index aaeb8939e137..f5be4c0564cf 100644
>>> --- a/tools/bpf/bpftool/map.c
>>> +++ b/tools/bpf/bpftool/map.c
>>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>>    		}
>>>    
>>>    		if (info->value_size) {
>>> -			printf("value:%c", break_names ? '\n' : ' ');
>>> -			fprint_hex(stdout, value, info->value_size, " ");
>>> +			if (map_is_map_of_maps(info->type)) {
>>> +				printf("id:%c", break_names ? '\n' : ' ');
>> 1> +				print_uint(value, info->value_size);
> 
> On Mon, 24 Apr 2023 18:07:27 -0700, Yonghong Song wrote:
>> For all map_in_map types, the inner map value size is 32bit int which
>> represents a fd (for map creation) and a id (for map info), e.g., in
>> show_prog_maps() in prog.c. So maybe we can simplify the code as below:
>> 	printf("id: %u", *(unsigned int *)value);
> 
> That is true, maybe the "id" could also be changed to "map_id" to follow the
> convention. Do you think that `print_uint` could be useful in the future?
> If that is the case, should I keep using it here as an example usage, and to
> avoid dead code? Or should I just remove it?

Maybe, "inner_map_id" is a better choice. For array of maps, some array 
element value could be 0, implying "inner_map_id 0", but I think it is
okay, people should know a real inner_map_id (or any map_id) should 
never be 0.

Function "print_uint" is not needed any more. Please remove it.

Please add the command line to dump map values triggering the above 
change, also the actual dumps with and without this patch.

> 
>>> +			} else {
>>> +				printf("value:%c", break_names ? '\n' : ' ');
>>> +				fprint_hex(stdout, value, info->value_size, " ");
>>> +			}
>>>    		}
>>>    
>>>    		printf("\n");
Xueming Feng April 25, 2023, 6:09 a.m. UTC | #7
>On 4/24/23 20:58, Xueming Feng wrote:
>>> On 4/24/23 02:09, Xueming Feng wrote:
>>>> When using `bpftool map dump` in plain format, it is usually
>>>> more convenient to show the inner map id instead of raw value.
>>>> Changing this behavior would help with quick debugging with
>>>> `bpftool`, without disrupting scripted behavior. Since user
>>>> could dump the inner map with id, and need to convert value.
>>>>
>>>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>>>> ---
>>>> Changes in v2:
>>>>     - Fix commit message grammar.
>>>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>>>> 	  `n` to `arg_size`.
>>>>     - Make `print_uint` able to take any size of argument up to `unsigned long`,
>>>> 		and print it as unsigned decimal.
>>>>
>>>> Thanks for the review and suggestions! I have changed my patch accordingly.
>>>> There is a possibility that `arg_size` is larger than `unsigned long`,
>>>> but previous review suggested that it should be up to the caller function to
>>>> set `arg_size` correctly. So I didn't add check for that, should I?
>>>>
>>>>    tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>>>    tools/bpf/bpftool/main.h |  1 +
>>>>    tools/bpf/bpftool/map.c  |  9 +++++++--
>>>>    3 files changed, 23 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>>>> index 08d0ac543c67..810c0dc10ecb 100644
>>>> --- a/tools/bpf/bpftool/main.c
>>>> +++ b/tools/bpf/bpftool/main.c
>>>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>>>    	return 0;
>>>>    }
>>>>    
>>>> +void print_uint(const void *arg, unsigned int arg_size)
>>>> +{
>>>> +	const unsigned char *data = arg;
>>>> +	unsigned long val = 0ul;
>>>> +
>>>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>>>> +		memcpy(&val, data, arg_size);
>>>> +	#else
>>>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>>>> +		       data, arg_size);
>>>> +	#endif
>> 
>> On Mon, 24 Apr 2023 09:44:18 -0700, Kui-Feng Lee wrote:
>>> Is it possible that arg_size is bigger than sizeof(val)?
>> 
>> Yes it is possible, I had the thought of adding a check. But as I mentioned
>> before the diff section, previous review
>> https://lore.kernel.org/bpf/20230421101154.23690-1-kuro@kuroa.me/ suggested that
>> I should leave it to the caller function to behave. If I were to add a check,
>> what action do you recommend if the check fails? Print a '-1', do nothing,
>> or just use the first sizeof(val) bytes?

On Mon, 24 Apr 2023 22:19:52 -0700, Kui-Feng Lee wrote:
> In the previous patch, it may have integer overflow, but it is never 
> buffer underrun.  This version uses memcpy and may cause buffer underrun 
> if arg_size is bigger than sizeof(val).  I would say that at least 
> prevent buffer underrun from happening.

Thanks for the advice! This function is pending remove in the next version of 
this patch. But I will remember this for future patches.

>>> +
>>> +	fprintf(stdout, "%lu", val);
>>> +}
>>> +
>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>>    {
>>>    	unsigned char *data = arg;
>>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>>> index 0ef373cef4c7..0de671423431 100644
>>> --- a/tools/bpf/bpftool/main.h
>>> +++ b/tools/bpf/bpftool/main.h
>>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>>    
>>>    bool is_prefix(const char *pfx, const char *str);
>>>    int detect_common_prefix(const char *arg, ...);
>>> +void print_uint(const void *arg, unsigned int arg_size);
>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>>    void usage(void) __noreturn;
>>>    
>>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>>> index aaeb8939e137..f5be4c0564cf 100644
>>> --- a/tools/bpf/bpftool/map.c
>>> +++ b/tools/bpf/bpftool/map.c
>>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>>    		}
>>>    
>>>    		if (info->value_size) {
>>> -			printf("value:%c", break_names ? '\n' : ' ');
>>> -			fprint_hex(stdout, value, info->value_size, " ");
>>> +			if (map_is_map_of_maps(info->type)) {
>>> +				printf("id:%c", break_names ? '\n' : ' ');
>>> +				print_uint(value, info->value_size);
>>> +			} else {
>>> +				printf("value:%c", break_names ? '\n' : ' ');
>>> +				fprint_hex(stdout, value, info->value_size, " ");
>>> +			}
>>>    		}
>>>    
>>>    		printf("\n");
Xueming Feng April 25, 2023, 6:37 a.m. UTC | #8
>On 4/24/23 9:10 PM, Xueming Feng wrote:
>>> On 4/24/23 2:09 AM, Xueming Feng wrote:
>>>> When using `bpftool map dump` in plain format, it is usually
>>>> more convenient to show the inner map id instead of raw value.
>>>> Changing this behavior would help with quick debugging with
>>>> `bpftool`, without disrupting scripted behavior. Since user
>>>> could dump the inner map with id, and need to convert value.
>>>>
>>>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>>>> ---
>>>> Changes in v2:
>>>>     - Fix commit message grammar.
>>>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>>>> 	  `n` to `arg_size`.
>>>>     - Make `print_uint` able to take any size of argument up to `unsigned long`,
>>>> 		and print it as unsigned decimal.
>>>>
>>>> Thanks for the review and suggestions! I have changed my patch accordingly.
>>>> There is a possibility that `arg_size` is larger than `unsigned long`,
>>>> but previous review suggested that it should be up to the caller function to
>>>> set `arg_size` correctly. So I didn't add check for that, should I?
>>>>
>>>>    tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>>>    tools/bpf/bpftool/main.h |  1 +
>>>>    tools/bpf/bpftool/map.c  |  9 +++++++--
>>>>    3 files changed, 23 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>>>> index 08d0ac543c67..810c0dc10ecb 100644
>>>> --- a/tools/bpf/bpftool/main.c
>>>> +++ b/tools/bpf/bpftool/main.c
>>>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>>>    	return 0;
>>>>    }
>>>>    
>>>> +void print_uint(const void *arg, unsigned int arg_size)
>>>> +{
>>>> +	const unsigned char *data = arg;
>>>> +	unsigned long val = 0ul;
>>>> +
>>>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>>>> +		memcpy(&val, data, arg_size);
>>>> +	#else
>>>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>>>> +		       data, arg_size);
>>>> +	#endif
>>>> +
>>>> +	fprintf(stdout, "%lu", val);
>>>> +}
>>>> +
>>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>>>    {
>>>>    	unsigned char *data = arg;
>>>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>>>> index 0ef373cef4c7..0de671423431 100644
>>>> --- a/tools/bpf/bpftool/main.h
>>>> +++ b/tools/bpf/bpftool/main.h
>>>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>>>    
>>>>    bool is_prefix(const char *pfx, const char *str);
>>>>    int detect_common_prefix(const char *arg, ...);
>>>> +void print_uint(const void *arg, unsigned int arg_size);
>>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>>>    void usage(void) __noreturn;
>>>>    
>>>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>>>> index aaeb8939e137..f5be4c0564cf 100644
>>>> --- a/tools/bpf/bpftool/map.c
>>>> +++ b/tools/bpf/bpftool/map.c
>>>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>>>    		}
>>>>    
>>>>    		if (info->value_size) {
>>>> -			printf("value:%c", break_names ? '\n' : ' ');
>>>> -			fprint_hex(stdout, value, info->value_size, " ");
>>>> +			if (map_is_map_of_maps(info->type)) {
>>>> +				printf("id:%c", break_names ? '\n' : ' ');
>>> 1> +				print_uint(value, info->value_size);
>> 
>> On Mon, 24 Apr 2023 18:07:27 -0700, Yonghong Song wrote:
>>> For all map_in_map types, the inner map value size is 32bit int which
>>> represents a fd (for map creation) and a id (for map info), e.g., in
>>> show_prog_maps() in prog.c. So maybe we can simplify the code as below:
>>> 	printf("id: %u", *(unsigned int *)value);
>> 
>> That is true, maybe the "id" could also be changed to "map_id" to follow the
>> convention. Do you think that `print_uint` could be useful in the future?
>> If that is the case, should I keep using it here as an example usage, and to
>> avoid dead code? Or should I just remove it?

On Mon, 24 Apr 2023 22:58:10 -0700, Yonghong Song wrote:
> Maybe, "inner_map_id" is a better choice. For array of maps, some array 
> element value could be 0, implying "inner_map_id 0", but I think it is
> okay, people should know a real inner_map_id (or any map_id) should 
> never be 0.
> 
> Function "print_uint" is not needed any more. Please remove it.

Will reflect this in v3.

> 
> Please add the command line to dump map values triggering the above 
> change, also the actual dumps with and without this patch.

$ bpftool map dump id 138
Without patch:
```
key:
fc 00 00 00 00 00 00 00  00 00 00 00 00 00 00 05
27 16 06 00
value:
8b 00 00 00
Found 1 element
```
With patch:
```
key:
fc 00 00 00 00 00 00 00  00 00 00 00 00 00 00 05
27 16 06 00
inner_map_id:
139 
Found 1 element
```

>> 
>>>> +			} else {
>>>> +				printf("value:%c", break_names ? '\n' : ' ');
>>>> +				fprint_hex(stdout, value, info->value_size, " ");
>>>> +			}
>>>>    		}
>>>>    
>>>>    		printf("\n");
Quentin Monnet April 25, 2023, 8:57 a.m. UTC | #9
2023-04-25 14:37 UTC+0800 ~ Xueming Feng <kuro@kuroa.me>
>> On 4/24/23 9:10 PM, Xueming Feng wrote:
>>>> On 4/24/23 2:09 AM, Xueming Feng wrote:
>>>>> When using `bpftool map dump` in plain format, it is usually
>>>>> more convenient to show the inner map id instead of raw value.
>>>>> Changing this behavior would help with quick debugging with
>>>>> `bpftool`, without disrupting scripted behavior. Since user
>>>>> could dump the inner map with id, and need to convert value.
>>>>>
>>>>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>>>>> ---
>>>>> Changes in v2:
>>>>>     - Fix commit message grammar.
>>>>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>>>>> 	  `n` to `arg_size`.
>>>>>     - Make `print_uint` able to take any size of argument up to `unsigned long`,
>>>>> 		and print it as unsigned decimal.
>>>>>
>>>>> Thanks for the review and suggestions! I have changed my patch accordingly.
>>>>> There is a possibility that `arg_size` is larger than `unsigned long`,
>>>>> but previous review suggested that it should be up to the caller function to
>>>>> set `arg_size` correctly. So I didn't add check for that, should I?
>>>>>
>>>>>    tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>>>>    tools/bpf/bpftool/main.h |  1 +
>>>>>    tools/bpf/bpftool/map.c  |  9 +++++++--
>>>>>    3 files changed, 23 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>>>>> index 08d0ac543c67..810c0dc10ecb 100644
>>>>> --- a/tools/bpf/bpftool/main.c
>>>>> +++ b/tools/bpf/bpftool/main.c
>>>>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>>>>    	return 0;
>>>>>    }
>>>>>    
>>>>> +void print_uint(const void *arg, unsigned int arg_size)
>>>>> +{
>>>>> +	const unsigned char *data = arg;
>>>>> +	unsigned long val = 0ul;
>>>>> +
>>>>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>>>>> +		memcpy(&val, data, arg_size);
>>>>> +	#else
>>>>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>>>>> +		       data, arg_size);
>>>>> +	#endif
>>>>> +
>>>>> +	fprintf(stdout, "%lu", val);
>>>>> +}
>>>>> +
>>>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>>>>    {
>>>>>    	unsigned char *data = arg;
>>>>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>>>>> index 0ef373cef4c7..0de671423431 100644
>>>>> --- a/tools/bpf/bpftool/main.h
>>>>> +++ b/tools/bpf/bpftool/main.h
>>>>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>>>>    
>>>>>    bool is_prefix(const char *pfx, const char *str);
>>>>>    int detect_common_prefix(const char *arg, ...);
>>>>> +void print_uint(const void *arg, unsigned int arg_size);
>>>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>>>>    void usage(void) __noreturn;
>>>>>    
>>>>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>>>>> index aaeb8939e137..f5be4c0564cf 100644
>>>>> --- a/tools/bpf/bpftool/map.c
>>>>> +++ b/tools/bpf/bpftool/map.c
>>>>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>>>>    		}
>>>>>    
>>>>>    		if (info->value_size) {
>>>>> -			printf("value:%c", break_names ? '\n' : ' ');
>>>>> -			fprint_hex(stdout, value, info->value_size, " ");
>>>>> +			if (map_is_map_of_maps(info->type)) {
>>>>> +				printf("id:%c", break_names ? '\n' : ' ');
>>>> 1> +				print_uint(value, info->value_size);
>>>
>>> On Mon, 24 Apr 2023 18:07:27 -0700, Yonghong Song wrote:
>>>> For all map_in_map types, the inner map value size is 32bit int which
>>>> represents a fd (for map creation) and a id (for map info), e.g., in
>>>> show_prog_maps() in prog.c. So maybe we can simplify the code as below:
>>>> 	printf("id: %u", *(unsigned int *)value);
>>>
>>> That is true, maybe the "id" could also be changed to "map_id" to follow the
>>> convention. Do you think that `print_uint` could be useful in the future?
>>> If that is the case, should I keep using it here as an example usage, and to
>>> avoid dead code? Or should I just remove it?

This makes me think we could also have something similar for prog_array
maps (but not necessarily as part of your patchset).

> 
> On Mon, 24 Apr 2023 22:58:10 -0700, Yonghong Song wrote:
>> Maybe, "inner_map_id" is a better choice. For array of maps, some array 
>> element value could be 0, implying "inner_map_id 0", but I think it is
>> okay, people should know a real inner_map_id (or any map_id) should 
>> never be 0.
>>
>> Function "print_uint" is not needed any more. Please remove it.
> 
> Will reflect this in v3.
> 
>>
>> Please add the command line to dump map values triggering the above 
>> change, also the actual dumps with and without this patch.
> 
> $ bpftool map dump id 138
> Without patch:
> ```
> key:
> fc 00 00 00 00 00 00 00  00 00 00 00 00 00 00 05
> 27 16 06 00
> value:
> 8b 00 00 00
> Found 1 element
> ```
> With patch:
> ```
> key:
> fc 00 00 00 00 00 00 00  00 00 00 00 00 00 00 05
> 27 16 06 00
> inner_map_id:
> 139 
> Found 1 element
> ```

Thanks! Please add those sample outputs to the commit description for
v3. Can you please also add an example with JSON ("-p")?

Quentin
Xueming Feng April 25, 2023, 9:52 a.m. UTC | #10
>2023-04-25 14:37 UTC+0800 ~ Xueming Feng <kuro@kuroa.me>
>>> On 4/24/23 9:10 PM, Xueming Feng wrote:
>>>>> On 4/24/23 2:09 AM, Xueming Feng wrote:
>>>>>> When using `bpftool map dump` in plain format, it is usually
>>>>>> more convenient to show the inner map id instead of raw value.
>>>>>> Changing this behavior would help with quick debugging with
>>>>>> `bpftool`, without disrupting scripted behavior. Since user
>>>>>> could dump the inner map with id, and need to convert value.
>>>>>>
>>>>>> Signed-off-by: Xueming Feng <kuro@kuroa.me>
>>>>>> ---
>>>>>> Changes in v2:
>>>>>>     - Fix commit message grammar.
>>>>>> 	- Change `print_uint` to only print to stdout, make `arg` const, and rename
>>>>>> 	  `n` to `arg_size`.
>>>>>>     - Make `print_uint` able to take any size of argument up to `unsigned long`,
>>>>>> 		and print it as unsigned decimal.
>>>>>>
>>>>>> Thanks for the review and suggestions! I have changed my patch accordingly.
>>>>>> There is a possibility that `arg_size` is larger than `unsigned long`,
>>>>>> but previous review suggested that it should be up to the caller function to
>>>>>> set `arg_size` correctly. So I didn't add check for that, should I?
>>>>>>
>>>>>>    tools/bpf/bpftool/main.c | 15 +++++++++++++++
>>>>>>    tools/bpf/bpftool/main.h |  1 +
>>>>>>    tools/bpf/bpftool/map.c  |  9 +++++++--
>>>>>>    3 files changed, 23 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
>>>>>> index 08d0ac543c67..810c0dc10ecb 100644
>>>>>> --- a/tools/bpf/bpftool/main.c
>>>>>> +++ b/tools/bpf/bpftool/main.c
>>>>>> @@ -251,6 +251,21 @@ int detect_common_prefix(const char *arg, ...)
>>>>>>    	return 0;
>>>>>>    }
>>>>>>    
>>>>>> +void print_uint(const void *arg, unsigned int arg_size)
>>>>>> +{
>>>>>> +	const unsigned char *data = arg;
>>>>>> +	unsigned long val = 0ul;
>>>>>> +
>>>>>> +	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
>>>>>> +		memcpy(&val, data, arg_size);
>>>>>> +	#else
>>>>>> +		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
>>>>>> +		       data, arg_size);
>>>>>> +	#endif
>>>>>> +
>>>>>> +	fprintf(stdout, "%lu", val);
>>>>>> +}
>>>>>> +
>>>>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
>>>>>>    {
>>>>>>    	unsigned char *data = arg;
>>>>>> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
>>>>>> index 0ef373cef4c7..0de671423431 100644
>>>>>> --- a/tools/bpf/bpftool/main.h
>>>>>> +++ b/tools/bpf/bpftool/main.h
>>>>>> @@ -90,6 +90,7 @@ void __printf(1, 2) p_info(const char *fmt, ...);
>>>>>>    
>>>>>>    bool is_prefix(const char *pfx, const char *str);
>>>>>>    int detect_common_prefix(const char *arg, ...);
>>>>>> +void print_uint(const void *arg, unsigned int arg_size);
>>>>>>    void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
>>>>>>    void usage(void) __noreturn;
>>>>>>    
>>>>>> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
>>>>>> index aaeb8939e137..f5be4c0564cf 100644
>>>>>> --- a/tools/bpf/bpftool/map.c
>>>>>> +++ b/tools/bpf/bpftool/map.c
>>>>>> @@ -259,8 +259,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
>>>>>>    		}
>>>>>>    
>>>>>>    		if (info->value_size) {
>>>>>> -			printf("value:%c", break_names ? '\n' : ' ');
>>>>>> -			fprint_hex(stdout, value, info->value_size, " ");
>>>>>> +			if (map_is_map_of_maps(info->type)) {
>>>>>> +				printf("id:%c", break_names ? '\n' : ' ');
>>>>> 1> +				print_uint(value, info->value_size);
>>>>
>>>> On Mon, 24 Apr 2023 18:07:27 -0700, Yonghong Song wrote:
>>>>> For all map_in_map types, the inner map value size is 32bit int which
>>>>> represents a fd (for map creation) and a id (for map info), e.g., in
>>>>> show_prog_maps() in prog.c. So maybe we can simplify the code as below:
>>>>> 	printf("id: %u", *(unsigned int *)value);
>>>>
>>>> That is true, maybe the "id" could also be changed to "map_id" to follow the
>>>> convention. Do you think that `print_uint` could be useful in the future?
>>>> If that is the case, should I keep using it here as an example usage, and to
>>>> avoid dead code? Or should I just remove it?

On Tue, 25 Apr 2023 09:57:17 +0100, Quentin Monnet wrote:
> This makes me think we could also have something similar for prog_array
> maps (but not necessarily as part of your patchset).

Good idea, will take a look at that after finishing v3 patch, and possibly
make a separate patch for it. (This is my first time contributing, better keep 
it simple).

>> On Mon, 24 Apr 2023 22:58:10 -0700, Yonghong Song wrote:
>>> Maybe, "inner_map_id" is a better choice. For array of maps, some array 
>>> element value could be 0, implying "inner_map_id 0", but I think it is
>>> okay, people should know a real inner_map_id (or any map_id) should 
>>> never be 0.
>>>
>>> Function "print_uint" is not needed any more. Please remove it.
>> 
>> Will reflect this in v3.
>> 
>>>
>>> Please add the command line to dump map values triggering the above 
>>> change, also the actual dumps with and without this patch.
>> 
>> $ bpftool map dump id 138
>> Without patch:
>> ```
>> key:
>> fc 00 00 00 00 00 00 00  00 00 00 00 00 00 00 05
>> 27 16 06 00
>> value:
>> 8b 00 00 00
>> Found 1 element
>> ```
>> With patch:
>> ```
>> key:
>> fc 00 00 00 00 00 00 00  00 00 00 00 00 00 00 05
>> 27 16 06 00
>> inner_map_id:
>> 139 
>> Found 1 element
>> ```

> Thanks! Please add those sample outputs to the commit description for
> v3. Can you please also add an example with JSON ("-p")?

Sure, will add them in v3! About json output, they are currently not touched
to avoid breaking scripts. I will add inner_map_id as a new field in v3 like the 
following patch.
https://lore.kernel.org/bpf/20230419003651.988865-1-kuifeng@meta.com/

> Quentin
diff mbox series

Patch

diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index 08d0ac543c67..810c0dc10ecb 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -251,6 +251,21 @@  int detect_common_prefix(const char *arg, ...)
 	return 0;
 }
 
+void print_uint(const void *arg, unsigned int arg_size)
+{
+	const unsigned char *data = arg;
+	unsigned long val = 0ul;
+
+	#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+		memcpy(&val, data, arg_size);
+	#else
+		memcpy((unsigned char *)&val + sizeof(val) - arg_size,
+		       data, arg_size);
+	#endif
+
+	fprintf(stdout, "%lu", val);
+}
+
 void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
 {
 	unsigned char *data = arg;
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 0ef373cef4c7..0de671423431 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -90,6 +90,7 @@  void __printf(1, 2) p_info(const char *fmt, ...);
 
 bool is_prefix(const char *pfx, const char *str);
 int detect_common_prefix(const char *arg, ...);
+void print_uint(const void *arg, unsigned int arg_size);
 void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
 void usage(void) __noreturn;
 
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index aaeb8939e137..f5be4c0564cf 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -259,8 +259,13 @@  static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
 		}
 
 		if (info->value_size) {
-			printf("value:%c", break_names ? '\n' : ' ');
-			fprint_hex(stdout, value, info->value_size, " ");
+			if (map_is_map_of_maps(info->type)) {
+				printf("id:%c", break_names ? '\n' : ' ');
+				print_uint(value, info->value_size);
+			} else {
+				printf("value:%c", break_names ? '\n' : ' ');
+				fprint_hex(stdout, value, info->value_size, " ");
+			}
 		}
 
 		printf("\n");