Commit a7d22ca2 authored by Paul Chaignon's avatar Paul Chaignon Committed by Alexei Starovoitov

bpftool: Match programs by name

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 patch implements lookup by name for programs.  The show and dump
commands will return all programs with the given name, whereas other
commands will error out if several programs have the same name.
Signed-off-by: default avatarPaul Chaignon <paul.chaignon@orange.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Reviewed-by: default avatarQuentin Monnet <quentin.monnet@netronome.com>
Link: https://lore.kernel.org/bpf/b5fc1a5dcfaeb5f16fc80295cdaa606dd2d91534.1576263640.git.paul.chaignon@gmail.com
parent ec202509
...@@ -41,7 +41,7 @@ MAP COMMANDS ...@@ -41,7 +41,7 @@ MAP COMMANDS
| |
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
| *DATA* := { [**hex**] *BYTES* } | *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* } | *VALUE* := { *DATA* | *MAP* | *PROG* }
| *UPDATE_FLAGS* := { **any** | **exist** | **noexist** } | *UPDATE_FLAGS* := { **any** | **exist** | **noexist** }
| *TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash** | *TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash**
......
...@@ -33,7 +33,7 @@ PROG COMMANDS ...@@ -33,7 +33,7 @@ PROG COMMANDS
| **bpftool** **prog help** | **bpftool** **prog help**
| |
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | *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* := { | *TYPE* := {
| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** | | **socket** | **kprobe** | **kretprobe** | **classifier** | **action** |
| **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** | | **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** |
...@@ -55,8 +55,8 @@ DESCRIPTION ...@@ -55,8 +55,8 @@ DESCRIPTION
Show information about loaded programs. If *PROG* is Show information about loaded programs. If *PROG* is
specified show information only about given programs, specified show information only about given programs,
otherwise list all programs currently loaded on the system. otherwise list all programs currently loaded on the system.
In case of **tag**, *PROG* may match several programs which In case of **tag** or **name**, *PROG* may match several
will all be shown. programs which will all be shown.
Output will start with program ID followed by program type and Output will start with program ID followed by program type and
zero or more named attributes (depending on kernel version). zero or more named attributes (depending on kernel version).
...@@ -75,9 +75,9 @@ DESCRIPTION ...@@ -75,9 +75,9 @@ DESCRIPTION
output in human-readable format. In this case, **opcodes** output in human-readable format. In this case, **opcodes**
controls if raw opcodes should be printed as well. controls if raw opcodes should be printed as well.
In case of **tag**, *PROG* may match several programs which In case of **tag** or **name**, *PROG* may match several
will all be dumped. However, if **file** or **visual** is programs which will all be dumped. However, if **file** or
specified, *PROG* must match a single program. **visual** is specified, *PROG* must match a single program.
If **file** is specified, the binary image will instead be If **file** is specified, the binary image will instead be
written to *FILE*. written to *FILE*.
......
...@@ -71,6 +71,12 @@ _bpftool_get_prog_tags() ...@@ -71,6 +71,12 @@ _bpftool_get_prog_tags()
command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) 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() _bpftool_get_btf_ids()
{ {
COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \ COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \
...@@ -201,6 +207,10 @@ _bpftool() ...@@ -201,6 +207,10 @@ _bpftool()
_bpftool_get_prog_tags _bpftool_get_prog_tags
return 0 return 0
;; ;;
name)
_bpftool_get_prog_names
return 0
;;
dev) dev)
_sysfs_get_netdevs _sysfs_get_netdevs
return 0 return 0
...@@ -263,7 +273,7 @@ _bpftool() ...@@ -263,7 +273,7 @@ _bpftool()
;; ;;
esac esac
local PROG_TYPE='id pinned tag' local PROG_TYPE='id pinned tag name'
local MAP_TYPE='id pinned' local MAP_TYPE='id pinned'
case $command in case $command in
show|list) show|list)
...@@ -559,7 +569,7 @@ _bpftool() ...@@ -559,7 +569,7 @@ _bpftool()
return 0 return 0
;; ;;
prog_array) prog_array)
local PROG_TYPE='id pinned tag' local PROG_TYPE='id pinned tag name'
COMPREPLY+=( $( compgen -W "$PROG_TYPE" \ COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
-- "$cur" ) ) -- "$cur" ) )
return 0 return 0
...@@ -644,7 +654,7 @@ _bpftool() ...@@ -644,7 +654,7 @@ _bpftool()
esac esac
;; ;;
btf) btf)
local PROG_TYPE='id pinned tag' local PROG_TYPE='id pinned tag name'
local MAP_TYPE='id pinned' local MAP_TYPE='id pinned'
case $command in case $command in
dump) dump)
...@@ -735,7 +745,7 @@ _bpftool() ...@@ -735,7 +745,7 @@ _bpftool()
connect6 sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl \ connect6 sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl \
getsockopt setsockopt' getsockopt setsockopt'
local ATTACH_FLAGS='multi override' local ATTACH_FLAGS='multi override'
local PROG_TYPE='id pinned tag' local PROG_TYPE='id pinned tag name'
case $prev in case $prev in
$command) $command)
_filedir _filedir
...@@ -760,7 +770,7 @@ _bpftool() ...@@ -760,7 +770,7 @@ _bpftool()
elif [[ "$command" == "attach" ]]; then elif [[ "$command" == "attach" ]]; then
# We have an attach type on the command line, # We have an attach type on the command line,
# but it is not the previous word, or # 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 # that). This should only leave the case when
# we need attach flags for "attach" commamnd. # we need attach flags for "attach" commamnd.
_bpftool_one_of_list "$ATTACH_FLAGS" _bpftool_one_of_list "$ATTACH_FLAGS"
...@@ -786,7 +796,7 @@ _bpftool() ...@@ -786,7 +796,7 @@ _bpftool()
esac esac
;; ;;
net) net)
local PROG_TYPE='id pinned tag' local PROG_TYPE='id pinned tag name'
local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload' local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
case $command in case $command in
show|list) show|list)
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" #define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
#define HELP_SPEC_PROGRAM \ #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 \ #define HELP_SPEC_OPTIONS \
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} |\n" \ "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} |\n" \
"\t {-m|--mapcompat} | {-n|--nomount} }" "\t {-m|--mapcompat} | {-n|--nomount} }"
......
...@@ -82,7 +82,7 @@ static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) ...@@ -82,7 +82,7 @@ static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
strftime(buf, size, "%FT%T%z", &load_tm); strftime(buf, size, "%FT%T%z", &load_tm);
} }
static int prog_fd_by_tag(unsigned char *tag, int **fds) static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
{ {
unsigned int id = 0; unsigned int id = 0;
int fd, nb_fds = 0; int fd, nb_fds = 0;
...@@ -116,7 +116,8 @@ static int prog_fd_by_tag(unsigned char *tag, int **fds) ...@@ -116,7 +116,8 @@ static int prog_fd_by_tag(unsigned char *tag, int **fds)
goto err_close_fd; goto err_close_fd;
} }
if (memcmp(tag, info.tag, BPF_TAG_SIZE)) { if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
(!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
close(fd); close(fd);
continue; continue;
} }
...@@ -174,7 +175,20 @@ static int prog_parse_fds(int *argc, char ***argv, int **fds) ...@@ -174,7 +175,20 @@ static int prog_parse_fds(int *argc, char ***argv, int **fds)
} }
NEXT_ARGP(); NEXT_ARGP();
return prog_fd_by_tag(tag, fds); return prog_fd_by_nametag(tag, fds, true);
} else if (is_prefix(**argv, "name")) {
char *name;
NEXT_ARGP();
name = **argv;
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
p_err("can't parse name");
return -1;
}
NEXT_ARGP();
return prog_fd_by_nametag(name, fds, false);
} else if (is_prefix(**argv, "pinned")) { } else if (is_prefix(**argv, "pinned")) {
char *path; char *path;
...@@ -189,7 +203,7 @@ static int prog_parse_fds(int *argc, char ***argv, int **fds) ...@@ -189,7 +203,7 @@ static int prog_parse_fds(int *argc, char ***argv, int **fds)
return 1; return 1;
} }
p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
return -1; return -1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment