Skip to content

Commit

Permalink
Merge branch 'bpftool-match-by-name'
Browse files Browse the repository at this point in the history
Paul Chaignon says:

====================
When working with frequently modified BPF programs, both the ID and the
tag may change.  bpftool currently doesn't provide a "stable" way to match
such programs.  This patchset allows bpftool to match programs and maps by
name.

When given a tag that matches several programs, bpftool currently only
considers the first match.  The first patch changes that behavior to
either process all matching programs (for the show and dump commands) or
error out.  The second patch implements program lookup by name, with the
same behavior as for tags in case of ambiguity.  The last patch implements
map lookup by name.

Changelogs:
  Changes in v2:
    - Fix buffer overflow after realloc.
    - Add example output to commit message.
    - Properly close JSON arrays on errors.
    - Fix style errors (line breaks, for loops, exit labels, type for
      tagname).
    - Move do_show code for argc == 2 to do_show_subset functions.
    - Rebase.
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Alexei Starovoitov committed Dec 15, 2019
2 parents a06bf42 + 99f9863 commit a06ae6a
Show file tree
Hide file tree
Showing 6 changed files with 737 additions and 214 deletions.
12 changes: 7 additions & 5 deletions tools/bpf/bpftool/Documentation/bpftool-map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ MAP COMMANDS
| **bpftool** **map freeze** *MAP*
| **bpftool** **map help**
|
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* | **name** *MAP_NAME* }
| *DATA* := { [**hex**] *BYTES* }
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* }
| *VALUE* := { *DATA* | *MAP* | *PROG* }
| *UPDATE_FLAGS* := { **any** | **exist** | **noexist** }
| *TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash**
Expand All @@ -55,8 +55,9 @@ DESCRIPTION
===========
**bpftool map { show | list }** [*MAP*]
Show information about loaded maps. If *MAP* is specified
show information only about given map, otherwise list all
maps currently loaded on the system.
show information only about given maps, otherwise list all
maps currently loaded on the system. In case of **name**,
*MAP* may match several maps which will all be shown.

Output will start with map ID followed by map type and
zero or more named attributes (depending on kernel version).
Expand All @@ -66,7 +67,8 @@ DESCRIPTION
as *FILE*.

**bpftool map dump** *MAP*
Dump all entries in a given *MAP*.
Dump all entries in a given *MAP*. In case of **name**,
*MAP* may match several maps which will all be dumped.

**bpftool map update** *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*]
Update map entry for a given *KEY*.
Expand Down
18 changes: 13 additions & 5 deletions tools/bpf/bpftool/Documentation/bpftool-prog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PROG COMMANDS
| **bpftool** **prog help**
|
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* }
| *TYPE* := {
| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** |
| **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** |
Expand All @@ -53,8 +53,10 @@ DESCRIPTION
===========
**bpftool prog { show | list }** [*PROG*]
Show information about loaded programs. If *PROG* is
specified show information only about given program, otherwise
list all programs currently loaded on the system.
specified show information only about given programs,
otherwise list all programs currently loaded on the system.
In case of **tag** or **name**, *PROG* may match several
programs which will all be shown.

Output will start with program ID followed by program type and
zero or more named attributes (depending on kernel version).
Expand All @@ -68,27 +70,33 @@ DESCRIPTION
performed via the **kernel.bpf_stats_enabled** sysctl knob.

**bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }]
Dump eBPF instructions of the program from the kernel. By
Dump eBPF instructions of the programs from the kernel. By
default, eBPF will be disassembled and printed to standard
output in human-readable format. In this case, **opcodes**
controls if raw opcodes should be printed as well.

In case of **tag** or **name**, *PROG* may match several
programs which will all be dumped. However, if **file** or
**visual** is specified, *PROG* must match a single program.

If **file** is specified, the binary image will instead be
written to *FILE*.

If **visual** is specified, control flow graph (CFG) will be
built instead, and eBPF instructions will be presented with
CFG in DOT format, on standard output.

If the prog has line_info available, the source line will
If the programs have line_info available, the source line will
be displayed by default. If **linum** is specified,
the filename, line number and line column will also be
displayed on top of the source line.

**bpftool prog dump jited** *PROG* [{ **file** *FILE* | **opcodes** | **linum** }]
Dump jited image (host machine code) of the program.

If *FILE* is specified image will be written to a file,
otherwise it will be disassembled and printed to stdout.
*PROG* must match a single program when **file** is specified.

**opcodes** controls if raw opcodes will be printed.

Expand Down
145 changes: 134 additions & 11 deletions tools/bpf/bpftool/bash-completion/bpftool
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ _bpftool_get_map_ids_for_type()
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
}

_bpftool_get_map_names()
{
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
}

# Takes map type and adds matching map names to the list of suggestions.
_bpftool_get_map_names_for_type()
{
local type="$1"
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
command grep -C2 "$type" | \
command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
}

_bpftool_get_prog_ids()
{
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
Expand All @@ -71,6 +86,12 @@ _bpftool_get_prog_tags()
command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
}

_bpftool_get_prog_names()
{
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
command sed -n 's/.*"name": "\(.*\)",$/\1/p' )" -- "$cur" ) )
}

_bpftool_get_btf_ids()
{
COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \
Expand Down Expand Up @@ -180,6 +201,52 @@ _bpftool_map_update_get_id()
esac
}

_bpftool_map_update_get_name()
{
local command="$1"

# Is it the map to update, or a map to insert into the map to update?
# Search for "value" keyword.
local idx value
for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
if [[ ${words[idx]} == "value" ]]; then
value=1
break
fi
done
if [[ $value -eq 0 ]]; then
case "$command" in
push)
_bpftool_get_map_names_for_type stack
;;
enqueue)
_bpftool_get_map_names_for_type queue
;;
*)
_bpftool_get_map_names
;;
esac
return 0
fi

# Name to complete is for a value. It can be either prog name or map name. This
# depends on the type of the map to update.
local type=$(_bpftool_map_guess_map_type)
case $type in
array_of_maps|hash_of_maps)
_bpftool_get_map_names
return 0
;;
prog_array)
_bpftool_get_prog_names
return 0
;;
*)
return 0
;;
esac
}

_bpftool()
{
local cur prev words objword
Expand Down Expand Up @@ -251,20 +318,25 @@ _bpftool()
# Completion depends on object and command in use
case $object in
prog)
# Complete id, only for subcommands that use prog (but no map) ids
# Complete id and name, only for subcommands that use prog (but no
# map) ids/names.
case $command in
show|list|dump|pin)
case $prev in
id)
_bpftool_get_prog_ids
return 0
;;
name)
_bpftool_get_prog_names
return 0
;;
esac
;;
esac

local PROG_TYPE='id pinned tag'
local MAP_TYPE='id pinned'
local PROG_TYPE='id pinned tag name'
local MAP_TYPE='id pinned name'
case $command in
show|list)
[[ $prev != "$command" ]] && return 0
Expand Down Expand Up @@ -315,6 +387,9 @@ _bpftool()
id)
_bpftool_get_prog_ids
;;
name)
_bpftool_get_map_names
;;
pinned)
_filedir
;;
Expand All @@ -335,6 +410,9 @@ _bpftool()
id)
_bpftool_get_map_ids
;;
name)
_bpftool_get_map_names
;;
pinned)
_filedir
;;
Expand Down Expand Up @@ -399,6 +477,10 @@ _bpftool()
_bpftool_get_map_ids
return 0
;;
name)
_bpftool_get_map_names
return 0
;;
pinned|pinmaps)
_filedir
return 0
Expand Down Expand Up @@ -447,7 +529,7 @@ _bpftool()
esac
;;
map)
local MAP_TYPE='id pinned'
local MAP_TYPE='id pinned name'
case $command in
show|list|dump|peek|pop|dequeue|freeze)
case $prev in
Expand All @@ -473,6 +555,24 @@ _bpftool()
esac
return 0
;;
name)
case "$command" in
peek)
_bpftool_get_map_names_for_type stack
_bpftool_get_map_names_for_type queue
;;
pop)
_bpftool_get_map_names_for_type stack
;;
dequeue)
_bpftool_get_map_names_for_type queue
;;
*)
_bpftool_get_map_names
;;
esac
return 0
;;
*)
return 0
;;
Expand Down Expand Up @@ -520,6 +620,10 @@ _bpftool()
_bpftool_get_map_ids
return 0
;;
name)
_bpftool_get_map_names
return 0
;;
key)
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
;;
Expand All @@ -545,6 +649,10 @@ _bpftool()
_bpftool_map_update_get_id $command
return 0
;;
name)
_bpftool_map_update_get_name $command
return 0
;;
key)
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
;;
Expand All @@ -553,13 +661,13 @@ _bpftool()
# map, depending on the type of the map to update.
case "$(_bpftool_map_guess_map_type)" in
array_of_maps|hash_of_maps)
local MAP_TYPE='id pinned'
local MAP_TYPE='id pinned name'
COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
-- "$cur" ) )
return 0
;;
prog_array)
local PROG_TYPE='id pinned tag'
local PROG_TYPE='id pinned tag name'
COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
-- "$cur" ) )
return 0
Expand Down Expand Up @@ -621,6 +729,10 @@ _bpftool()
_bpftool_get_map_ids_for_type perf_event_array
return 0
;;
name)
_bpftool_get_map_names_for_type perf_event_array
return 0
;;
cpu)
return 0
;;
Expand All @@ -644,8 +756,8 @@ _bpftool()
esac
;;
btf)
local PROG_TYPE='id pinned tag'
local MAP_TYPE='id pinned'
local PROG_TYPE='id pinned tag name'
local MAP_TYPE='id pinned name'
case $command in
dump)
case $prev in
Expand Down Expand Up @@ -676,6 +788,17 @@ _bpftool()
esac
return 0
;;
name)
case $pprev in
prog)
_bpftool_get_prog_names
;;
map)
_bpftool_get_map_names
;;
esac
return 0
;;
format)
COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
;;
Expand Down Expand Up @@ -735,7 +858,7 @@ _bpftool()
connect6 sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl \
getsockopt setsockopt'
local ATTACH_FLAGS='multi override'
local PROG_TYPE='id pinned tag'
local PROG_TYPE='id pinned tag name'
case $prev in
$command)
_filedir
Expand All @@ -760,7 +883,7 @@ _bpftool()
elif [[ "$command" == "attach" ]]; then
# We have an attach type on the command line,
# but it is not the previous word, or
# "id|pinned|tag" (we already checked for
# "id|pinned|tag|name" (we already checked for
# that). This should only leave the case when
# we need attach flags for "attach" commamnd.
_bpftool_one_of_list "$ATTACH_FLAGS"
Expand All @@ -786,7 +909,7 @@ _bpftool()
esac
;;
net)
local PROG_TYPE='id pinned tag'
local PROG_TYPE='id pinned tag name'
local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
case $command in
show|list)
Expand Down
4 changes: 2 additions & 2 deletions tools/bpf/bpftool/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@
#define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"

#define HELP_SPEC_PROGRAM \
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG | name PROG_NAME }"
#define HELP_SPEC_OPTIONS \
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} |\n" \
"\t {-m|--mapcompat} | {-n|--nomount} }"
#define HELP_SPEC_MAP \
"MAP := { id MAP_ID | pinned FILE }"
"MAP := { id MAP_ID | pinned FILE | name MAP_NAME }"

static const char * const prog_type_name[] = {
[BPF_PROG_TYPE_UNSPEC] = "unspec",
Expand Down
Loading

0 comments on commit a06ae6a

Please sign in to comment.