tools: bpftool: make it easier to feed hex bytes to bpftool

bpftool uses hexadecimal values when it dumps map contents:

    # bpftool map dump id 1337
    key: ff 13 37 ff  value: a1 b2 c3 d4 ff ff ff ff
    Found 1 element

In order to lookup or update values with bpftool, the natural reflex is
then to copy and paste the values to the command line, and to try to run
something like:

    # bpftool map update id 1337 key ff 13 37 ff \
            value 00 00 00 00 00 00 1a 2b
    Error: error parsing byte: ff

bpftool complains, because it uses strtoul() with a 0 base to parse the
bytes, and that without a "0x" prefix, the bytes are considered as
decimal values (or even octal if they start with "0").

To feed hexadecimal values instead, one needs to add "0x" prefixes
everywhere necessary:

    # bpftool map update id 1337 key 0xff 0x13 0x37 0xff \
            value 0 0 0 0 0 0 0x1a 0x2b

To make it easier to use hexadecimal values, add an optional "hex"
keyword to put after "key" or "value" to tell bpftool to consider the
digits as hexadecimal. We can now do:

    # bpftool map update id 1337 key hex ff 13 37 ff \
            value hex 0 0 0 0 0 0 1a 2b

Without the "hex" keyword, the bytes are still parsed according to
normal integer notation (decimal if no prefix, or hexadecimal or octal
if "0x" or "0" prefix is used, respectively).

The patch also add related documentation and bash completion for the
"hex" keyword.

Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Suggested-by: David Beckett <david.beckett@netronome.com>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
Quentin Monnet 2018-04-17 19:46:34 -07:00 committed by Daniel Borkmann
parent 8de0e8ba97
commit 0c90f2243e
3 changed files with 36 additions and 18 deletions

View File

@ -23,10 +23,10 @@ MAP COMMANDS
| **bpftool** **map { show | list }** [*MAP*] | **bpftool** **map { show | list }** [*MAP*]
| **bpftool** **map dump** *MAP* | **bpftool** **map dump** *MAP*
| **bpftool** **map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*] | **bpftool** **map update** *MAP* **key** [**hex**] *BYTES* **value** [**hex**] *VALUE* [*UPDATE_FLAGS*]
| **bpftool** **map lookup** *MAP* **key** *BYTES* | **bpftool** **map lookup** *MAP* **key** [**hex**] *BYTES*
| **bpftool** **map getnext** *MAP* [**key** *BYTES*] | **bpftool** **map getnext** *MAP* [**key** [**hex**] *BYTES*]
| **bpftool** **map delete** *MAP* **key** *BYTES* | **bpftool** **map delete** *MAP* **key** [**hex**] *BYTES*
| **bpftool** **map pin** *MAP* *FILE* | **bpftool** **map pin** *MAP* *FILE*
| **bpftool** **map help** | **bpftool** **map help**
| |
@ -48,20 +48,26 @@ DESCRIPTION
**bpftool map dump** *MAP* **bpftool map dump** *MAP*
Dump all entries in a given *MAP*. Dump all entries in a given *MAP*.
**bpftool map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*] **bpftool map update** *MAP* **key** [**hex**] *BYTES* **value** [**hex**] *VALUE* [*UPDATE_FLAGS*]
Update map entry for a given *KEY*. Update map entry for a given *KEY*.
*UPDATE_FLAGS* can be one of: **any** update existing entry *UPDATE_FLAGS* can be one of: **any** update existing entry
or add if doesn't exit; **exist** update only if entry already or add if doesn't exit; **exist** update only if entry already
exists; **noexist** update only if entry doesn't exist. exists; **noexist** update only if entry doesn't exist.
**bpftool map lookup** *MAP* **key** *BYTES* If the **hex** keyword is provided in front of the bytes
sequence, the bytes are parsed as hexadeximal values, even if
no "0x" prefix is added. If the keyword is not provided, then
the bytes are parsed as decimal values, unless a "0x" prefix
(for hexadecimal) or a "0" prefix (for octal) is provided.
**bpftool map lookup** *MAP* **key** [**hex**] *BYTES*
Lookup **key** in the map. Lookup **key** in the map.
**bpftool map getnext** *MAP* [**key** *BYTES*] **bpftool map getnext** *MAP* [**key** [**hex**] *BYTES*]
Get next key. If *key* is not specified, get first key. Get next key. If *key* is not specified, get first key.
**bpftool map delete** *MAP* **key** *BYTES* **bpftool map delete** *MAP* **key** [**hex**] *BYTES*
Remove entry from the map. Remove entry from the map.
**bpftool map pin** *MAP* *FILE* **bpftool map pin** *MAP* *FILE*
@ -98,7 +104,12 @@ EXAMPLES
10: hash name some_map flags 0x0 10: hash name some_map flags 0x0
key 4B value 8B max_entries 2048 memlock 167936B key 4B value 8B max_entries 2048 memlock 167936B
**# bpftool map update id 10 key 13 00 07 00 value 02 00 00 00 01 02 03 04** The following three commands are equivalent:
|
| **# bpftool map update id 10 key hex 20 c4 b7 00 value hex 0f ff ff ab 01 02 03 4c**
| **# bpftool map update id 10 key 0x20 0xc4 0xb7 0x00 value 0x0f 0xff 0xff 0xab 0x01 0x02 0x03 0x4c**
| **# bpftool map update id 10 key 32 196 183 0 value 15 255 255 171 1 2 3 76**
**# bpftool map lookup id 10 key 0 1 2 3** **# bpftool map lookup id 10 key 0 1 2 3**

View File

@ -147,7 +147,7 @@ _bpftool()
# Deal with simplest keywords # Deal with simplest keywords
case $prev in case $prev in
help|key|opcodes|visual) help|hex|opcodes|visual)
return 0 return 0
;; ;;
tag) tag)
@ -283,7 +283,7 @@ _bpftool()
return 0 return 0
;; ;;
key) key)
return 0 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
;; ;;
*) *)
_bpftool_once_attr 'key' _bpftool_once_attr 'key'
@ -302,7 +302,7 @@ _bpftool()
return 0 return 0
;; ;;
key) key)
return 0 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
;; ;;
value) value)
# We can have bytes, or references to a prog or a # We can have bytes, or references to a prog or a
@ -321,6 +321,8 @@ _bpftool()
return 0 return 0
;; ;;
*) *)
COMPREPLY+=( $( compgen -W 'hex' \
-- "$cur" ) )
return 0 return 0
;; ;;
esac esac

View File

@ -283,11 +283,16 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
static char **parse_bytes(char **argv, const char *name, unsigned char *val, static char **parse_bytes(char **argv, const char *name, unsigned char *val,
unsigned int n) unsigned int n)
{ {
unsigned int i = 0; unsigned int i = 0, base = 0;
char *endptr; char *endptr;
if (is_prefix(*argv, "hex")) {
base = 16;
argv++;
}
while (i < n && argv[i]) { while (i < n && argv[i]) {
val[i] = strtoul(argv[i], &endptr, 0); val[i] = strtoul(argv[i], &endptr, base);
if (*endptr) { if (*endptr) {
p_err("error parsing byte: %s", argv[i]); p_err("error parsing byte: %s", argv[i]);
return NULL; return NULL;
@ -869,10 +874,10 @@ static int do_help(int argc, char **argv)
fprintf(stderr, fprintf(stderr,
"Usage: %s %s { show | list } [MAP]\n" "Usage: %s %s { show | list } [MAP]\n"
" %s %s dump MAP\n" " %s %s dump MAP\n"
" %s %s update MAP key BYTES value VALUE [UPDATE_FLAGS]\n" " %s %s update MAP key [hex] BYTES value [hex] VALUE [UPDATE_FLAGS]\n"
" %s %s lookup MAP key BYTES\n" " %s %s lookup MAP key [hex] BYTES\n"
" %s %s getnext MAP [key BYTES]\n" " %s %s getnext MAP [key [hex] BYTES]\n"
" %s %s delete MAP key BYTES\n" " %s %s delete MAP key [hex] BYTES\n"
" %s %s pin MAP FILE\n" " %s %s pin MAP FILE\n"
" %s %s help\n" " %s %s help\n"
"\n" "\n"