bpftool: Match maps by name
This patch implements lookup by name for maps and changes the behavior of lookups by tag to be consistent with prog subcommands. Similarly to program subcommands, the show and dump commands will return all maps with the given name (or tag), whereas other commands will error out if several maps have the same name (resp. tag). When a map has BTF info, it is dumped in JSON with available BTF info. This patch requires that all matched maps have BTF info before switching the output format to JSON. Signed-off-by: Paul Chaignon <paul.chaignon@orange.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/8de1c9f273860b3ea1680502928f4da2336b853e.1576263640.git.paul.chaignon@gmail.com
This commit is contained in:
parent
a7d22ca2a4
commit
99f9863a0c
@ -39,7 +39,7 @@ MAP COMMANDS
|
|||||||
| **bpftool** **map freeze** *MAP*
|
| **bpftool** **map freeze** *MAP*
|
||||||
| **bpftool** **map help**
|
| **bpftool** **map help**
|
||||||
|
|
|
|
||||||
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
|
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* | **name** *MAP_NAME* }
|
||||||
| *DATA* := { [**hex**] *BYTES* }
|
| *DATA* := { [**hex**] *BYTES* }
|
||||||
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* }
|
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* }
|
||||||
| *VALUE* := { *DATA* | *MAP* | *PROG* }
|
| *VALUE* := { *DATA* | *MAP* | *PROG* }
|
||||||
@ -55,8 +55,9 @@ DESCRIPTION
|
|||||||
===========
|
===========
|
||||||
**bpftool map { show | list }** [*MAP*]
|
**bpftool map { show | list }** [*MAP*]
|
||||||
Show information about loaded maps. If *MAP* is specified
|
Show information about loaded maps. If *MAP* is specified
|
||||||
show information only about given map, otherwise list all
|
show information only about given maps, otherwise list all
|
||||||
maps currently loaded on the system.
|
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
|
Output will start with map ID followed by map type and
|
||||||
zero or more named attributes (depending on kernel version).
|
zero or more named attributes (depending on kernel version).
|
||||||
@ -66,7 +67,8 @@ DESCRIPTION
|
|||||||
as *FILE*.
|
as *FILE*.
|
||||||
|
|
||||||
**bpftool map dump** *MAP*
|
**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*]
|
**bpftool map update** *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*]
|
||||||
Update map entry for a given *KEY*.
|
Update map entry for a given *KEY*.
|
||||||
|
@ -59,6 +59,21 @@ _bpftool_get_map_ids_for_type()
|
|||||||
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
|
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()
|
_bpftool_get_prog_ids()
|
||||||
{
|
{
|
||||||
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
|
||||||
@ -186,6 +201,52 @@ _bpftool_map_update_get_id()
|
|||||||
esac
|
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()
|
_bpftool()
|
||||||
{
|
{
|
||||||
local cur prev words objword
|
local cur prev words objword
|
||||||
@ -207,10 +268,6 @@ _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
|
||||||
@ -261,7 +318,8 @@ _bpftool()
|
|||||||
# Completion depends on object and command in use
|
# Completion depends on object and command in use
|
||||||
case $object in
|
case $object in
|
||||||
prog)
|
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
|
case $command in
|
||||||
show|list|dump|pin)
|
show|list|dump|pin)
|
||||||
case $prev in
|
case $prev in
|
||||||
@ -269,12 +327,16 @@ _bpftool()
|
|||||||
_bpftool_get_prog_ids
|
_bpftool_get_prog_ids
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_get_prog_names
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
local PROG_TYPE='id pinned tag name'
|
local PROG_TYPE='id pinned tag name'
|
||||||
local MAP_TYPE='id pinned'
|
local MAP_TYPE='id pinned name'
|
||||||
case $command in
|
case $command in
|
||||||
show|list)
|
show|list)
|
||||||
[[ $prev != "$command" ]] && return 0
|
[[ $prev != "$command" ]] && return 0
|
||||||
@ -325,6 +387,9 @@ _bpftool()
|
|||||||
id)
|
id)
|
||||||
_bpftool_get_prog_ids
|
_bpftool_get_prog_ids
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_get_map_names
|
||||||
|
;;
|
||||||
pinned)
|
pinned)
|
||||||
_filedir
|
_filedir
|
||||||
;;
|
;;
|
||||||
@ -345,6 +410,9 @@ _bpftool()
|
|||||||
id)
|
id)
|
||||||
_bpftool_get_map_ids
|
_bpftool_get_map_ids
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_get_map_names
|
||||||
|
;;
|
||||||
pinned)
|
pinned)
|
||||||
_filedir
|
_filedir
|
||||||
;;
|
;;
|
||||||
@ -409,6 +477,10 @@ _bpftool()
|
|||||||
_bpftool_get_map_ids
|
_bpftool_get_map_ids
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_get_map_names
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
pinned|pinmaps)
|
pinned|pinmaps)
|
||||||
_filedir
|
_filedir
|
||||||
return 0
|
return 0
|
||||||
@ -457,7 +529,7 @@ _bpftool()
|
|||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
map)
|
map)
|
||||||
local MAP_TYPE='id pinned'
|
local MAP_TYPE='id pinned name'
|
||||||
case $command in
|
case $command in
|
||||||
show|list|dump|peek|pop|dequeue|freeze)
|
show|list|dump|peek|pop|dequeue|freeze)
|
||||||
case $prev in
|
case $prev in
|
||||||
@ -483,6 +555,24 @@ _bpftool()
|
|||||||
esac
|
esac
|
||||||
return 0
|
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
|
return 0
|
||||||
;;
|
;;
|
||||||
@ -530,6 +620,10 @@ _bpftool()
|
|||||||
_bpftool_get_map_ids
|
_bpftool_get_map_ids
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_get_map_names
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
key)
|
key)
|
||||||
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
@ -555,6 +649,10 @@ _bpftool()
|
|||||||
_bpftool_map_update_get_id $command
|
_bpftool_map_update_get_id $command
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_map_update_get_name $command
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
key)
|
key)
|
||||||
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
@ -563,7 +661,7 @@ _bpftool()
|
|||||||
# map, depending on the type of the map to update.
|
# map, depending on the type of the map to update.
|
||||||
case "$(_bpftool_map_guess_map_type)" in
|
case "$(_bpftool_map_guess_map_type)" in
|
||||||
array_of_maps|hash_of_maps)
|
array_of_maps|hash_of_maps)
|
||||||
local MAP_TYPE='id pinned'
|
local MAP_TYPE='id pinned name'
|
||||||
COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
|
COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
|
||||||
-- "$cur" ) )
|
-- "$cur" ) )
|
||||||
return 0
|
return 0
|
||||||
@ -631,6 +729,10 @@ _bpftool()
|
|||||||
_bpftool_get_map_ids_for_type perf_event_array
|
_bpftool_get_map_ids_for_type perf_event_array
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
_bpftool_get_map_names_for_type perf_event_array
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
cpu)
|
cpu)
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@ -655,7 +757,7 @@ _bpftool()
|
|||||||
;;
|
;;
|
||||||
btf)
|
btf)
|
||||||
local PROG_TYPE='id pinned tag name'
|
local PROG_TYPE='id pinned tag name'
|
||||||
local MAP_TYPE='id pinned'
|
local MAP_TYPE='id pinned name'
|
||||||
case $command in
|
case $command in
|
||||||
dump)
|
dump)
|
||||||
case $prev in
|
case $prev in
|
||||||
@ -686,6 +788,17 @@ _bpftool()
|
|||||||
esac
|
esac
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
name)
|
||||||
|
case $pprev in
|
||||||
|
prog)
|
||||||
|
_bpftool_get_prog_names
|
||||||
|
;;
|
||||||
|
map)
|
||||||
|
_bpftool_get_map_names
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
format)
|
format)
|
||||||
COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
"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} }"
|
||||||
#define HELP_SPEC_MAP \
|
#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[] = {
|
static const char * const prog_type_name[] = {
|
||||||
[BPF_PROG_TYPE_UNSPEC] = "unspec",
|
[BPF_PROG_TYPE_UNSPEC] = "unspec",
|
||||||
|
@ -91,10 +91,66 @@ static void *alloc_value(struct bpf_map_info *info)
|
|||||||
return malloc(info->value_size);
|
return malloc(info->value_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int map_parse_fd(int *argc, char ***argv)
|
static int map_fd_by_name(char *name, int **fds)
|
||||||
{
|
{
|
||||||
int fd;
|
unsigned int id = 0;
|
||||||
|
int fd, nb_fds = 0;
|
||||||
|
void *tmp;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct bpf_map_info info = {};
|
||||||
|
__u32 len = sizeof(info);
|
||||||
|
|
||||||
|
err = bpf_map_get_next_id(id, &id);
|
||||||
|
if (err) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
p_err("%s", strerror(errno));
|
||||||
|
goto err_close_fds;
|
||||||
|
}
|
||||||
|
return nb_fds;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = bpf_map_get_fd_by_id(id);
|
||||||
|
if (fd < 0) {
|
||||||
|
p_err("can't get map by id (%u): %s",
|
||||||
|
id, strerror(errno));
|
||||||
|
goto err_close_fds;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
||||||
|
if (err) {
|
||||||
|
p_err("can't get map info (%u): %s",
|
||||||
|
id, strerror(errno));
|
||||||
|
goto err_close_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nb_fds > 0) {
|
||||||
|
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
|
||||||
|
if (!tmp) {
|
||||||
|
p_err("failed to realloc");
|
||||||
|
goto err_close_fd;
|
||||||
|
}
|
||||||
|
*fds = tmp;
|
||||||
|
}
|
||||||
|
(*fds)[nb_fds++] = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_close_fd:
|
||||||
|
close(fd);
|
||||||
|
err_close_fds:
|
||||||
|
while (--nb_fds >= 0)
|
||||||
|
close((*fds)[nb_fds]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int map_parse_fds(int *argc, char ***argv, int **fds)
|
||||||
|
{
|
||||||
if (is_prefix(**argv, "id")) {
|
if (is_prefix(**argv, "id")) {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
@ -108,10 +164,25 @@ int map_parse_fd(int *argc, char ***argv)
|
|||||||
}
|
}
|
||||||
NEXT_ARGP();
|
NEXT_ARGP();
|
||||||
|
|
||||||
fd = bpf_map_get_fd_by_id(id);
|
(*fds)[0] = bpf_map_get_fd_by_id(id);
|
||||||
if (fd < 0)
|
if ((*fds)[0] < 0) {
|
||||||
p_err("get map by id (%u): %s", id, strerror(errno));
|
p_err("get map by id (%u): %s", id, strerror(errno));
|
||||||
return fd;
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} 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 map_fd_by_name(name, fds);
|
||||||
} else if (is_prefix(**argv, "pinned")) {
|
} else if (is_prefix(**argv, "pinned")) {
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
@ -120,13 +191,43 @@ int map_parse_fd(int *argc, char ***argv)
|
|||||||
path = **argv;
|
path = **argv;
|
||||||
NEXT_ARGP();
|
NEXT_ARGP();
|
||||||
|
|
||||||
return open_obj_pinned_any(path, BPF_OBJ_MAP);
|
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
|
||||||
|
if ((*fds)[0] < 0)
|
||||||
|
return -1;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
|
p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int map_parse_fd(int *argc, char ***argv)
|
||||||
|
{
|
||||||
|
int *fds = NULL;
|
||||||
|
int nb_fds, fd;
|
||||||
|
|
||||||
|
fds = malloc(sizeof(int));
|
||||||
|
if (!fds) {
|
||||||
|
p_err("mem alloc failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nb_fds = map_parse_fds(argc, argv, &fds);
|
||||||
|
if (nb_fds != 1) {
|
||||||
|
if (nb_fds > 1) {
|
||||||
|
p_err("several maps match this handle");
|
||||||
|
while (nb_fds--)
|
||||||
|
close(fds[nb_fds]);
|
||||||
|
}
|
||||||
|
fd = -1;
|
||||||
|
goto exit_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = fds[0];
|
||||||
|
exit_free:
|
||||||
|
free(fds);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
|
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -479,6 +580,21 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
|
||||||
|
{
|
||||||
|
jsonw_uint_field(wtr, "id", info->id);
|
||||||
|
if (info->type < ARRAY_SIZE(map_type_name))
|
||||||
|
jsonw_string_field(wtr, "type", map_type_name[info->type]);
|
||||||
|
else
|
||||||
|
jsonw_uint_field(wtr, "type", info->type);
|
||||||
|
|
||||||
|
if (*info->name)
|
||||||
|
jsonw_string_field(wtr, "name", info->name);
|
||||||
|
|
||||||
|
jsonw_name(wtr, "flags");
|
||||||
|
jsonw_printf(wtr, "%d", info->map_flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int show_map_close_json(int fd, struct bpf_map_info *info)
|
static int show_map_close_json(int fd, struct bpf_map_info *info)
|
||||||
{
|
{
|
||||||
char *memlock, *frozen_str;
|
char *memlock, *frozen_str;
|
||||||
@ -489,18 +605,7 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
|
|||||||
|
|
||||||
jsonw_start_object(json_wtr);
|
jsonw_start_object(json_wtr);
|
||||||
|
|
||||||
jsonw_uint_field(json_wtr, "id", info->id);
|
show_map_header_json(info, json_wtr);
|
||||||
if (info->type < ARRAY_SIZE(map_type_name))
|
|
||||||
jsonw_string_field(json_wtr, "type",
|
|
||||||
map_type_name[info->type]);
|
|
||||||
else
|
|
||||||
jsonw_uint_field(json_wtr, "type", info->type);
|
|
||||||
|
|
||||||
if (*info->name)
|
|
||||||
jsonw_string_field(json_wtr, "name", info->name);
|
|
||||||
|
|
||||||
jsonw_name(json_wtr, "flags");
|
|
||||||
jsonw_printf(json_wtr, "%d", info->map_flags);
|
|
||||||
|
|
||||||
print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
|
print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
|
||||||
|
|
||||||
@ -561,14 +666,8 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_map_close_plain(int fd, struct bpf_map_info *info)
|
static void show_map_header_plain(struct bpf_map_info *info)
|
||||||
{
|
{
|
||||||
char *memlock, *frozen_str;
|
|
||||||
int frozen = 0;
|
|
||||||
|
|
||||||
memlock = get_fdinfo(fd, "memlock");
|
|
||||||
frozen_str = get_fdinfo(fd, "frozen");
|
|
||||||
|
|
||||||
printf("%u: ", info->id);
|
printf("%u: ", info->id);
|
||||||
if (info->type < ARRAY_SIZE(map_type_name))
|
if (info->type < ARRAY_SIZE(map_type_name))
|
||||||
printf("%s ", map_type_name[info->type]);
|
printf("%s ", map_type_name[info->type]);
|
||||||
@ -581,6 +680,17 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
|
|||||||
printf("flags 0x%x", info->map_flags);
|
printf("flags 0x%x", info->map_flags);
|
||||||
print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
|
print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_map_close_plain(int fd, struct bpf_map_info *info)
|
||||||
|
{
|
||||||
|
char *memlock, *frozen_str;
|
||||||
|
int frozen = 0;
|
||||||
|
|
||||||
|
memlock = get_fdinfo(fd, "memlock");
|
||||||
|
frozen_str = get_fdinfo(fd, "frozen");
|
||||||
|
|
||||||
|
show_map_header_plain(info);
|
||||||
printf("\tkey %uB value %uB max_entries %u",
|
printf("\tkey %uB value %uB max_entries %u",
|
||||||
info->key_size, info->value_size, info->max_entries);
|
info->key_size, info->value_size, info->max_entries);
|
||||||
|
|
||||||
@ -642,6 +752,50 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_show_subset(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct bpf_map_info info = {};
|
||||||
|
__u32 len = sizeof(info);
|
||||||
|
int *fds = NULL;
|
||||||
|
int nb_fds, i;
|
||||||
|
int err = -1;
|
||||||
|
|
||||||
|
fds = malloc(sizeof(int));
|
||||||
|
if (!fds) {
|
||||||
|
p_err("mem alloc failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nb_fds = map_parse_fds(&argc, &argv, &fds);
|
||||||
|
if (nb_fds < 1)
|
||||||
|
goto exit_free;
|
||||||
|
|
||||||
|
if (json_output && nb_fds > 1)
|
||||||
|
jsonw_start_array(json_wtr); /* root array */
|
||||||
|
for (i = 0; i < nb_fds; i++) {
|
||||||
|
err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
|
||||||
|
if (err) {
|
||||||
|
p_err("can't get map info: %s",
|
||||||
|
strerror(errno));
|
||||||
|
for (; i < nb_fds; i++)
|
||||||
|
close(fds[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_output)
|
||||||
|
show_map_close_json(fds[i], &info);
|
||||||
|
else
|
||||||
|
show_map_close_plain(fds[i], &info);
|
||||||
|
|
||||||
|
close(fds[i]);
|
||||||
|
}
|
||||||
|
if (json_output && nb_fds > 1)
|
||||||
|
jsonw_end_array(json_wtr); /* root array */
|
||||||
|
|
||||||
|
exit_free:
|
||||||
|
free(fds);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_show(int argc, char **argv)
|
static int do_show(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bpf_map_info info = {};
|
struct bpf_map_info info = {};
|
||||||
@ -653,16 +807,8 @@ static int do_show(int argc, char **argv)
|
|||||||
if (show_pinned)
|
if (show_pinned)
|
||||||
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
|
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
|
||||||
|
|
||||||
if (argc == 2) {
|
if (argc == 2)
|
||||||
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
return do_show_subset(argc, argv);
|
||||||
if (fd < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (json_output)
|
|
||||||
return show_map_close_json(fd, &info);
|
|
||||||
else
|
|
||||||
return show_map_close_plain(fd, &info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc)
|
if (argc)
|
||||||
return BAD_ARG();
|
return BAD_ARG();
|
||||||
@ -765,26 +911,49 @@ static int dump_map_elem(int fd, void *key, void *value,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_dump(int argc, char **argv)
|
static int maps_have_btf(int *fds, int nb_fds)
|
||||||
{
|
{
|
||||||
struct bpf_map_info info = {};
|
struct bpf_map_info info = {};
|
||||||
|
__u32 len = sizeof(info);
|
||||||
|
struct btf *btf = NULL;
|
||||||
|
int err, i;
|
||||||
|
|
||||||
|
for (i = 0; i < nb_fds; i++) {
|
||||||
|
err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
|
||||||
|
if (err) {
|
||||||
|
p_err("can't get map info: %s", strerror(errno));
|
||||||
|
goto err_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = btf__get_from_id(info.btf_id, &btf);
|
||||||
|
if (err) {
|
||||||
|
p_err("failed to get btf");
|
||||||
|
goto err_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!btf)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
err_close:
|
||||||
|
for (; i < nb_fds; i++)
|
||||||
|
close(fds[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
|
||||||
|
bool enable_btf, bool show_header)
|
||||||
|
{
|
||||||
void *key, *value, *prev_key;
|
void *key, *value, *prev_key;
|
||||||
unsigned int num_elems = 0;
|
unsigned int num_elems = 0;
|
||||||
__u32 len = sizeof(info);
|
|
||||||
json_writer_t *btf_wtr;
|
|
||||||
struct btf *btf = NULL;
|
struct btf *btf = NULL;
|
||||||
int err;
|
int err;
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (argc != 2)
|
key = malloc(info->key_size);
|
||||||
usage();
|
value = alloc_value(info);
|
||||||
|
|
||||||
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
||||||
if (fd < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
key = malloc(info.key_size);
|
|
||||||
value = alloc_value(&info);
|
|
||||||
if (!key || !value) {
|
if (!key || !value) {
|
||||||
p_err("mem alloc failed");
|
p_err("mem alloc failed");
|
||||||
err = -1;
|
err = -1;
|
||||||
@ -793,30 +962,32 @@ static int do_dump(int argc, char **argv)
|
|||||||
|
|
||||||
prev_key = NULL;
|
prev_key = NULL;
|
||||||
|
|
||||||
err = btf__get_from_id(info.btf_id, &btf);
|
if (enable_btf) {
|
||||||
if (err) {
|
err = btf__get_from_id(info->btf_id, &btf);
|
||||||
p_err("failed to get btf");
|
if (err || !btf) {
|
||||||
goto exit_free;
|
/* enable_btf is true only if we've already checked
|
||||||
|
* that all maps have BTF information.
|
||||||
|
*/
|
||||||
|
p_err("failed to get btf");
|
||||||
|
goto exit_free;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json_output)
|
if (wtr) {
|
||||||
jsonw_start_array(json_wtr);
|
if (show_header) {
|
||||||
else
|
jsonw_start_object(wtr); /* map object */
|
||||||
if (btf) {
|
show_map_header_json(info, wtr);
|
||||||
btf_wtr = get_btf_writer();
|
jsonw_name(wtr, "elements");
|
||||||
if (!btf_wtr) {
|
|
||||||
p_info("failed to create json writer for btf. falling back to plain output");
|
|
||||||
btf__free(btf);
|
|
||||||
btf = NULL;
|
|
||||||
} else {
|
|
||||||
jsonw_start_array(btf_wtr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
jsonw_start_array(wtr); /* elements */
|
||||||
|
} else if (show_header) {
|
||||||
|
show_map_header_plain(info);
|
||||||
|
}
|
||||||
|
|
||||||
if (info.type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
|
if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
|
||||||
info.value_size != 8)
|
info->value_size != 8)
|
||||||
p_info("Warning: cannot read values from %s map with value_size != 8",
|
p_info("Warning: cannot read values from %s map with value_size != 8",
|
||||||
map_type_name[info.type]);
|
map_type_name[info->type]);
|
||||||
while (true) {
|
while (true) {
|
||||||
err = bpf_map_get_next_key(fd, prev_key, key);
|
err = bpf_map_get_next_key(fd, prev_key, key);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -824,15 +995,14 @@ static int do_dump(int argc, char **argv)
|
|||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
num_elems += dump_map_elem(fd, key, value, &info, btf, btf_wtr);
|
num_elems += dump_map_elem(fd, key, value, info, btf, wtr);
|
||||||
prev_key = key;
|
prev_key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json_output)
|
if (wtr) {
|
||||||
jsonw_end_array(json_wtr);
|
jsonw_end_array(wtr); /* elements */
|
||||||
else if (btf) {
|
if (show_header)
|
||||||
jsonw_end_array(btf_wtr);
|
jsonw_end_object(wtr); /* map object */
|
||||||
jsonw_destroy(&btf_wtr);
|
|
||||||
} else {
|
} else {
|
||||||
printf("Found %u element%s\n", num_elems,
|
printf("Found %u element%s\n", num_elems,
|
||||||
num_elems != 1 ? "s" : "");
|
num_elems != 1 ? "s" : "");
|
||||||
@ -847,6 +1017,72 @@ exit_free:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_dump(int argc, char **argv)
|
||||||
|
{
|
||||||
|
json_writer_t *wtr = NULL, *btf_wtr = NULL;
|
||||||
|
struct bpf_map_info info = {};
|
||||||
|
int nb_fds, i = 0, btf = 0;
|
||||||
|
__u32 len = sizeof(info);
|
||||||
|
int *fds = NULL;
|
||||||
|
int err = -1;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
fds = malloc(sizeof(int));
|
||||||
|
if (!fds) {
|
||||||
|
p_err("mem alloc failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nb_fds = map_parse_fds(&argc, &argv, &fds);
|
||||||
|
if (nb_fds < 1)
|
||||||
|
goto exit_free;
|
||||||
|
|
||||||
|
if (json_output) {
|
||||||
|
wtr = json_wtr;
|
||||||
|
} else {
|
||||||
|
btf = maps_have_btf(fds, nb_fds);
|
||||||
|
if (btf < 0)
|
||||||
|
goto exit_close;
|
||||||
|
if (btf) {
|
||||||
|
btf_wtr = get_btf_writer();
|
||||||
|
if (btf_wtr) {
|
||||||
|
wtr = btf_wtr;
|
||||||
|
} else {
|
||||||
|
p_info("failed to create json writer for btf. falling back to plain output");
|
||||||
|
btf = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wtr && nb_fds > 1)
|
||||||
|
jsonw_start_array(wtr); /* root array */
|
||||||
|
for (i = 0; i < nb_fds; i++) {
|
||||||
|
if (bpf_obj_get_info_by_fd(fds[i], &info, &len)) {
|
||||||
|
p_err("can't get map info: %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
err = map_dump(fds[i], &info, wtr, btf, nb_fds > 1);
|
||||||
|
if (!wtr && i != nb_fds - 1)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
close(fds[i]);
|
||||||
|
}
|
||||||
|
if (wtr && nb_fds > 1)
|
||||||
|
jsonw_end_array(wtr); /* root array */
|
||||||
|
|
||||||
|
if (btf)
|
||||||
|
jsonw_destroy(&btf_wtr);
|
||||||
|
exit_close:
|
||||||
|
for (; i < nb_fds; i++)
|
||||||
|
close(fds[i]);
|
||||||
|
exit_free:
|
||||||
|
free(fds);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
|
static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
|
||||||
{
|
{
|
||||||
*key = NULL;
|
*key = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user