Yonghong Song <yhs@xxxxxx> writes: > On 8/20/20 2:42 AM, YiFei Zhu wrote: >> From: YiFei Zhu <zhuyifei@xxxxxxxxxx> >> >> Added a flag "--metadata" to `bpftool prog list` to dump the metadata >> contents. For some formatting some BTF code is put directly in the >> metadata dumping. Sanity checks on the map and the kind of the btf_type >> to make sure we are actually dumping what we are expecting. >> >> A helper jsonw_reset is added to json writer so we can reuse the same >> json writer without having extraneous commas. >> >> Sample output: >> >> $ bpftool prog --metadata >> 6: cgroup_skb name prog tag bcf7977d3b93787c gpl >> [...] >> btf_id 4 >> metadata: >> metadata_a = "foo" >> metadata_b = 1 >> >> $ bpftool prog --metadata --json --pretty >> [{ >> "id": 6, >> [...] >> "btf_id": 4, >> "metadata": { >> "metadata_a": "foo", >> "metadata_b": 1 >> } >> } >> ] >> >> Signed-off-by: YiFei Zhu <zhuyifei@xxxxxxxxxx> >> --- >> tools/bpf/bpftool/json_writer.c | 6 ++ >> tools/bpf/bpftool/json_writer.h | 3 + >> tools/bpf/bpftool/main.c | 10 +++ >> tools/bpf/bpftool/main.h | 1 + >> tools/bpf/bpftool/prog.c | 135 ++++++++++++++++++++++++++++++++ >> 5 files changed, 155 insertions(+) >> >> diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c >> index 86501cd3c763..7fea83bedf48 100644 >> --- a/tools/bpf/bpftool/json_writer.c >> +++ b/tools/bpf/bpftool/json_writer.c >> @@ -119,6 +119,12 @@ void jsonw_pretty(json_writer_t *self, bool on) >> self->pretty = on; >> } >> >> +void jsonw_reset(json_writer_t *self) >> +{ >> + assert(self->depth == 0); >> + self->sep = '\0'; >> +} >> + >> /* Basic blocks */ >> static void jsonw_begin(json_writer_t *self, int c) >> { >> diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h >> index 35cf1f00f96c..8ace65cdb92f 100644 >> --- a/tools/bpf/bpftool/json_writer.h >> +++ b/tools/bpf/bpftool/json_writer.h >> @@ -27,6 +27,9 @@ void jsonw_destroy(json_writer_t **self_p); >> /* Cause output to have pretty whitespace */ >> void jsonw_pretty(json_writer_t *self, bool on); >> >> +/* Reset separator to create new JSON */ >> +void jsonw_reset(json_writer_t *self); >> + >> /* Add property name */ >> void jsonw_name(json_writer_t *self, const char *name); >> >> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c >> index 4a191fcbeb82..a681d568cfa7 100644 >> --- a/tools/bpf/bpftool/main.c >> +++ b/tools/bpf/bpftool/main.c >> @@ -28,6 +28,7 @@ bool show_pinned; >> bool block_mount; >> bool verifier_logs; >> bool relaxed_maps; >> +bool dump_metadata; >> struct pinned_obj_table prog_table; >> struct pinned_obj_table map_table; >> struct pinned_obj_table link_table; >> @@ -351,6 +352,10 @@ static int do_batch(int argc, char **argv) >> return err; >> } >> >> +enum bpftool_longonly_opts { >> + OPT_METADATA = 256, >> +}; >> + >> int main(int argc, char **argv) >> { >> static const struct option options[] = { >> @@ -362,6 +367,7 @@ int main(int argc, char **argv) >> { "mapcompat", no_argument, NULL, 'm' }, >> { "nomount", no_argument, NULL, 'n' }, >> { "debug", no_argument, NULL, 'd' }, >> + { "metadata", no_argument, NULL, OPT_METADATA }, >> { 0 } >> }; >> int opt, ret; >> @@ -371,6 +377,7 @@ int main(int argc, char **argv) >> json_output = false; >> show_pinned = false; >> block_mount = false; >> + dump_metadata = false; >> bin_name = argv[0]; >> >> hash_init(prog_table.table); >> @@ -412,6 +419,9 @@ int main(int argc, char **argv) >> libbpf_set_print(print_all_levels); >> verifier_logs = true; >> break; >> + case OPT_METADATA: >> + dump_metadata = true; >> + break; >> default: >> p_err("unrecognized option '%s'", argv[optind - 1]); >> if (json_output) >> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h >> index c46e52137b87..8750758e9150 100644 >> --- a/tools/bpf/bpftool/main.h >> +++ b/tools/bpf/bpftool/main.h >> @@ -90,6 +90,7 @@ extern bool show_pids; >> extern bool block_mount; >> extern bool verifier_logs; >> extern bool relaxed_maps; >> +extern bool dump_metadata; >> extern struct pinned_obj_table prog_table; >> extern struct pinned_obj_table map_table; >> extern struct pinned_obj_table link_table; >> diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c >> index d393eb8263a6..ee767b8d90fb 100644 >> --- a/tools/bpf/bpftool/prog.c >> +++ b/tools/bpf/bpftool/prog.c >> @@ -151,6 +151,135 @@ static void show_prog_maps(int fd, __u32 num_maps) >> } >> } >> >> +static void show_prog_metadata(int fd, __u32 num_maps) >> +{ >> + struct bpf_prog_info prog_info = {}; >> + struct bpf_map_info map_info = {}; >> + __u32 prog_info_len = sizeof(prog_info); >> + __u32 map_info_len = sizeof(map_info); >> + __u32 map_ids[num_maps]; >> + void *value = NULL; >> + struct btf *btf = NULL; >> + const struct btf_type *t_datasec, *t_var; >> + struct btf_var_secinfo *vsi; >> + int key = 0; >> + unsigned int i, vlen; >> + int map_fd; >> + int err; > > try to follow reverse christmas tree coding styple? > >> + >> + prog_info.nr_map_ids = num_maps; >> + prog_info.map_ids = ptr_to_u64(map_ids); >> + >> + err = bpf_obj_get_info_by_fd(fd, &prog_info, &prog_info_len); >> + if (err || !prog_info.nr_map_ids) >> + return; > > print out something for "err" case and "!prog_info.nr_map_ids" case? > The same for some other below returns. > >> + >> + for (i = 0; i < prog_info.nr_map_ids; i++) { >> + map_fd = bpf_map_get_fd_by_id(map_ids[i]); >> + if (map_fd < 0) >> + return; >> + >> + err = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); >> + if (err) >> + goto out_close; >> + >> + if (map_info.type != BPF_MAP_TYPE_ARRAY) >> + goto next_map; >> + if (map_info.key_size != sizeof(int)) >> + goto next_map; >> + if (map_info.max_entries != 1) >> + goto next_map; >> + if (!map_info.btf_value_type_id) >> + goto next_map; >> + if (!strstr(map_info.name, ".metadata")) >> + goto next_map; >> + >> + goto found; >> + >> +next_map: >> + close(map_fd); >> + } >> + >> + return; >> + >> +found: >> + value = malloc(map_info.value_size); >> + if (!value) >> + goto out_close; >> + >> + if (bpf_map_lookup_elem(map_fd, &key, value)) >> + goto out_free; > > Not sure whether we need formal libbpf API to access metadata or not. > This may help other applications too. But we can delay until it is > necessary. Yeah, please put in a libbpf accessor as well; I would like to use this from libxdp - without a skeleton :) -Toke