Implement cgattach command to list bpf progrrams attached to the given cgroup:
Example: $ ./bpftool cgattach dev_cgroup.o /sys/fs/cgroup/user.slice/ device $ ./bpftool cglist /sys/fs/cgroup/user.slice/ ID AttachType Name 1 device bpf_prog1 Signed-off-by: Roman Gushchin <g...@fb.com> Cc: Alexei Starovoitov <a...@kernel.org> Cc: Daniel Borkmann <dan...@iogearbox.net> Cc: Jakub Kicinski <jakub.kicin...@netronome.com> Cc: Martin KaFai Lau <ka...@fb.com> --- tools/bpf/bpftool/main.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 77fcc1a0bd5d..8a48f6a32adc 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -82,12 +82,13 @@ static int do_help(int argc, char **argv) " %s batch file FILE\n" " %s cgattach FILE CGROUP TYPE\n" " %s cgdetach CGROUP TYPE ID\n" + " %s cglist CGROUP TYPE\n" " %s version\n" "\n" " OBJECT := { prog | map }\n" " " HELP_SPEC_OPTIONS "\n" "", - bin_name, bin_name, bin_name, bin_name, bin_name); + bin_name, bin_name, bin_name, bin_name, bin_name, bin_name); return 0; } @@ -168,6 +169,7 @@ void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep) static int do_batch(int argc, char **argv); static int do_cgattach(int argc, char **argv); static int do_cgdetach(int argc, char **argv); +static int do_cglist(int argc, char **argv); static const struct cmd cmds[] = { { "help", do_help }, @@ -176,6 +178,7 @@ static const struct cmd cmds[] = { { "map", do_map }, { "cgattach", do_cgattach }, { "cgdetach", do_cgdetach }, + { "cglist", do_cglist }, { "version", do_version }, { 0 } }; @@ -386,6 +389,83 @@ static int do_cgdetach(int argc, char **argv) return 0; } +static int do_cglist(int argc, char **argv) +{ + enum bpf_attach_type type; + int prog_fd, cgroup_fd; + __u32 attach_flags; + __u32 prog_ids[1024] = {0}; + __u32 prog_cnt, iter; + int ret = -1; + struct bpf_prog_info info = {}; + __u32 info_len = sizeof(info); + + if (argc < 1) { + p_err("too few parameters for cglist\n"); + return -1; + } else if (argc > 1) { + p_err("too many parameters for cglist\n"); + return -1; + } + + cgroup_fd = open(argv[0], O_RDONLY); + if (cgroup_fd < 0) { + p_err("can't open cgroup %s\n", argv[1]); + return -1; + } + + if (json_output) + jsonw_start_array(json_wtr); + + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { + prog_cnt = ARRAY_SIZE(prog_ids); + if (bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids, + &prog_cnt)) + continue; + + ret = 0; + + if (prog_cnt == 0) + continue; + + if (!json_output) + printf("%-8s %-15s %-15s\n", "ID", "AttachType", + "Name"); + + for (iter = 0; iter < prog_cnt; iter++) { + prog_fd = bpf_prog_get_fd_by_id(prog_ids[iter]); + if (prog_fd < 0) + continue; + + if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { + close(prog_fd); + continue; + } + + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "id", info.id); + jsonw_string_field(json_wtr, "attach_type", + attach_type_strings[type]); + jsonw_string_field(json_wtr, "name", info.name); + jsonw_end_object(json_wtr); + } else { + printf("%-8u %-15s %-15s\n", info.id, + attach_type_strings[type], info.name); + } + + close(prog_fd); + } + } + + if (json_output) + jsonw_end_array(json_wtr); + + close(cgroup_fd); + + return ret; +} + int main(int argc, char **argv) { static const struct option options[] = { -- 2.14.3