Commit 831a0aaf authored by Quentin Monnet's avatar Quentin Monnet Committed by David S. Miller

tools: bpftool: add JSON output for `bpftool map *` commands

Reuse the json_writer API introduced in an earlier commit to make
bpftool able to generate JSON output on
`bpftool map { show | dump | lookup | getnext }` commands. Remaining
commands produce no output.

Some functions have been spit into plain-output and JSON versions in
order to remain readable.

Outputs for sample maps have been successfully tested against a JSON
validator.
Signed-off-by: default avatarQuentin Monnet <quentin.monnet@netronome.com>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f05e2c32
...@@ -205,8 +205,45 @@ map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) ...@@ -205,8 +205,45 @@ map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
return fd; return fd;
} }
static void print_entry(struct bpf_map_info *info, unsigned char *key, static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
unsigned char *value) unsigned char *value)
{
jsonw_start_object(json_wtr);
if (!map_is_per_cpu(info->type)) {
jsonw_name(json_wtr, "key");
print_hex_data_json(key, info->key_size);
jsonw_name(json_wtr, "value");
print_hex_data_json(value, info->value_size);
} else {
unsigned int i, n;
n = get_possible_cpus();
jsonw_name(json_wtr, "key");
print_hex_data_json(key, info->key_size);
jsonw_name(json_wtr, "values");
jsonw_start_array(json_wtr);
for (i = 0; i < n; i++) {
jsonw_start_object(json_wtr);
jsonw_int_field(json_wtr, "cpu", i);
jsonw_name(json_wtr, "value");
print_hex_data_json(value + i * info->value_size,
info->value_size);
jsonw_end_object(json_wtr);
}
jsonw_end_array(json_wtr);
}
jsonw_end_object(json_wtr);
}
static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
unsigned char *value)
{ {
if (!map_is_per_cpu(info->type)) { if (!map_is_per_cpu(info->type)) {
bool single_line, break_names; bool single_line, break_names;
...@@ -370,7 +407,41 @@ static int parse_elem(char **argv, struct bpf_map_info *info, ...@@ -370,7 +407,41 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
return -1; return -1;
} }
static int show_map_close(int fd, struct bpf_map_info *info) static int show_map_close_json(int fd, struct bpf_map_info *info)
{
char *memlock;
memlock = get_fdinfo(fd, "memlock");
close(fd);
jsonw_start_object(json_wtr);
jsonw_uint_field(json_wtr, "id", info->id);
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, "%#x", info->map_flags);
jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
if (memlock)
jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
free(memlock);
jsonw_end_object(json_wtr);
return 0;
}
static int show_map_close_plain(int fd, struct bpf_map_info *info)
{ {
char *memlock; char *memlock;
...@@ -412,12 +483,17 @@ static int do_show(int argc, char **argv) ...@@ -412,12 +483,17 @@ static int do_show(int argc, char **argv)
if (fd < 0) if (fd < 0)
return -1; return -1;
return show_map_close(fd, &info); 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();
if (json_output)
jsonw_start_array(json_wtr);
while (true) { while (true) {
err = bpf_map_get_next_id(id, &id); err = bpf_map_get_next_id(id, &id);
if (err) { if (err) {
...@@ -443,8 +519,13 @@ static int do_show(int argc, char **argv) ...@@ -443,8 +519,13 @@ static int do_show(int argc, char **argv)
return -1; return -1;
} }
show_map_close(fd, &info); if (json_output)
show_map_close_json(fd, &info);
else
show_map_close_plain(fd, &info);
} }
if (json_output)
jsonw_end_array(json_wtr);
return errno == ENOENT ? 0 : -1; return errno == ENOENT ? 0 : -1;
} }
...@@ -480,6 +561,8 @@ static int do_dump(int argc, char **argv) ...@@ -480,6 +561,8 @@ static int do_dump(int argc, char **argv)
} }
prev_key = NULL; prev_key = NULL;
if (json_output)
jsonw_start_array(json_wtr);
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) {
...@@ -489,7 +572,10 @@ static int do_dump(int argc, char **argv) ...@@ -489,7 +572,10 @@ static int do_dump(int argc, char **argv)
} }
if (!bpf_map_lookup_elem(fd, key, value)) { if (!bpf_map_lookup_elem(fd, key, value)) {
print_entry(&info, key, value); if (json_output)
print_entry_json(&info, key, value);
else
print_entry_plain(&info, key, value);
} else { } else {
info("can't lookup element with key: "); info("can't lookup element with key: ");
fprint_hex(stderr, key, info.key_size, " "); fprint_hex(stderr, key, info.key_size, " ");
...@@ -500,7 +586,11 @@ static int do_dump(int argc, char **argv) ...@@ -500,7 +586,11 @@ static int do_dump(int argc, char **argv)
num_elems++; num_elems++;
} }
printf("Found %u element%s\n", num_elems, num_elems != 1 ? "s" : ""); if (json_output)
jsonw_end_array(json_wtr);
else
printf("Found %u element%s\n", num_elems,
num_elems != 1 ? "s" : "");
exit_free: exit_free:
free(key); free(key);
...@@ -584,11 +674,18 @@ static int do_lookup(int argc, char **argv) ...@@ -584,11 +674,18 @@ static int do_lookup(int argc, char **argv)
err = bpf_map_lookup_elem(fd, key, value); err = bpf_map_lookup_elem(fd, key, value);
if (!err) { if (!err) {
print_entry(&info, key, value); if (json_output)
print_entry_json(&info, key, value);
else
print_entry_plain(&info, key, value);
} else if (errno == ENOENT) { } else if (errno == ENOENT) {
printf("key:\n"); if (json_output) {
fprint_hex(stdout, key, info.key_size, " "); jsonw_null(json_wtr);
printf("\n\nNot found\n"); } else {
printf("key:\n");
fprint_hex(stdout, key, info.key_size, " ");
printf("\n\nNot found\n");
}
} else { } else {
err("lookup failed: %s\n", strerror(errno)); err("lookup failed: %s\n", strerror(errno));
} }
...@@ -640,18 +737,30 @@ static int do_getnext(int argc, char **argv) ...@@ -640,18 +737,30 @@ static int do_getnext(int argc, char **argv)
goto exit_free; goto exit_free;
} }
if (key) { if (json_output) {
printf("key:\n"); jsonw_start_object(json_wtr);
fprint_hex(stdout, key, info.key_size, " "); if (key) {
printf("\n"); jsonw_name(json_wtr, "key");
print_hex_data_json(key, info.key_size);
} else {
jsonw_null_field(json_wtr, "key");
}
jsonw_name(json_wtr, "next_key");
print_hex_data_json(nextkey, info.key_size);
jsonw_end_object(json_wtr);
} else { } else {
printf("key: None\n"); if (key) {
printf("key:\n");
fprint_hex(stdout, key, info.key_size, " ");
printf("\n");
} else {
printf("key: None\n");
}
printf("next key:\n");
fprint_hex(stdout, nextkey, info.key_size, " ");
printf("\n");
} }
printf("next key:\n");
fprint_hex(stdout, nextkey, info.key_size, " ");
printf("\n");
exit_free: exit_free:
free(nextkey); free(nextkey);
free(key); free(key);
......
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