* [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command
@ 2018-07-06 1:05 Roman Gushchin
2018-07-06 1:05 ` [PATCH bpf-next 2/2] bpftool: document " Roman Gushchin
2018-07-06 2:01 ` [PATCH bpf-next 1/2] bpftool: introduce " Jakub Kicinski
0 siblings, 2 replies; 6+ messages in thread
From: Roman Gushchin @ 2018-07-06 1:05 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel-team, Roman Gushchin, Jakub Kicinski,
Quentin Monnet, Daniel Borkmann, Alexei Starovoitov
This commit introduces a new bpftool command: cgroup tree.
The idea is to iterate over the whole cgroup tree and print
all attached programs.
I was debugging a bpf/systemd issue, and found, that there is
no simple way to listen all bpf programs attached to cgroups.
I did master something in bash, but after some time got tired of it,
and decided, that adding a dedicated bpftool command could be
a better idea.
So, here it is:
$ sudo ./bpftool cgroup tree
CgroupPath
ID AttachType AttachFlags Name
/sys/fs/cgroup/system.slice/systemd-machined.service
18 ingress
17 egress
/sys/fs/cgroup/system.slice/systemd-logind.service
20 ingress
19 egress
/sys/fs/cgroup/system.slice/systemd-udevd.service
16 ingress
15 egress
/sys/fs/cgroup/system.slice/systemd-journald.service
14 ingress
13 egress
Signed-off-by: Roman Gushchin <guro@fb.com>
Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
Cc: Quentin Monnet <quentin.monnet@netronome.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
---
tools/bpf/bpftool/cgroup.c | 150 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 145 insertions(+), 5 deletions(-)
diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
index 16bee011e16c..125d5b6db568 100644
--- a/tools/bpf/bpftool/cgroup.c
+++ b/tools/bpf/bpftool/cgroup.c
@@ -2,7 +2,12 @@
// Copyright (C) 2017 Facebook
// Author: Roman Gushchin <guro@fb.com>
+#define _XOPEN_SOURCE 500
+#include <errno.h>
#include <fcntl.h>
+#include <ftw.h>
+#include <mntent.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
@@ -53,7 +58,8 @@ static enum bpf_attach_type parse_attach_type(const char *str)
}
static int show_bpf_prog(int id, const char *attach_type_str,
- const char *attach_flags_str)
+ const char *attach_flags_str,
+ int level)
{
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
@@ -78,7 +84,8 @@ static int show_bpf_prog(int id, const char *attach_type_str,
jsonw_string_field(json_wtr, "name", info.name);
jsonw_end_object(json_wtr);
} else {
- printf("%-8u %-15s %-15s %-15s\n", info.id,
+ printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "",
+ info.id,
attach_type_str,
attach_flags_str,
info.name);
@@ -88,7 +95,20 @@ static int show_bpf_prog(int id, const char *attach_type_str,
return 0;
}
-static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
+static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
+{
+ __u32 prog_cnt = 0;
+ int ret;
+
+ ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt);
+ if (ret)
+ return -1;
+
+ return prog_cnt;
+}
+
+static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
+ int level)
{
__u32 prog_ids[1024] = {0};
char *attach_flags_str;
@@ -123,7 +143,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
for (iter = 0; iter < prog_cnt; iter++)
show_bpf_prog(prog_ids[iter], attach_type_strings[type],
- attach_flags_str);
+ attach_flags_str, level);
return 0;
}
@@ -161,7 +181,7 @@ static int do_show(int argc, char **argv)
* If we were able to get the show for at least one
* attach type, let's return 0.
*/
- if (show_attached_bpf_progs(cgroup_fd, type) == 0)
+ if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0)
ret = 0;
}
@@ -173,6 +193,123 @@ static int do_show(int argc, char **argv)
return ret;
}
+static int do_show_tree_fn(const char *fpath, const struct stat *sb,
+ int typeflag, struct FTW *ftw)
+{
+ enum bpf_attach_type type;
+ bool skip = true;
+ int cgroup_fd;
+
+ if (typeflag != FTW_D)
+ return 0;
+
+ cgroup_fd = open(fpath, O_RDONLY);
+ if (cgroup_fd < 0) {
+ p_err("can't open cgroup %s: %s", fpath, strerror(errno));
+ return -1;
+ }
+
+ for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
+ int count = count_attached_bpf_progs(cgroup_fd, type);
+
+ if (count < 0 && errno != EINVAL) {
+ p_err("can't query bpf programs attached to %s: %s",
+ fpath, strerror(errno));
+ close(cgroup_fd);
+ return -1;
+ }
+ if (count > 0) {
+ skip = false;
+ break;
+ }
+ }
+
+ if (skip) {
+ close(cgroup_fd);
+ return 0;
+ }
+
+ if (json_output) {
+ jsonw_start_object(json_wtr);
+ jsonw_string_field(json_wtr, "cgroup", fpath);
+ jsonw_name(json_wtr, "programs");
+ jsonw_start_array(json_wtr);
+ } else {
+ printf("%s\n", fpath);
+ }
+
+ for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++)
+ show_attached_bpf_progs(cgroup_fd, type, ftw->level);
+
+ if (json_output) {
+ jsonw_end_array(json_wtr);
+ jsonw_end_object(json_wtr);
+ }
+
+ close(cgroup_fd);
+
+ return 0;
+}
+
+static char *find_cgroup_root(void)
+{
+ struct mntent *mnt;
+ FILE *f;
+
+ f = fopen("/proc/mounts", "r");
+ if (f == NULL)
+ return NULL;
+
+ while ((mnt = getmntent(f))) {
+ if (strcmp(mnt->mnt_type, "cgroup2") == 0) {
+ fclose(f);
+ return strdup(mnt->mnt_dir);
+ }
+ }
+
+ fclose(f);
+ return NULL;
+}
+
+static int do_show_tree(int argc, char **argv)
+{
+ char *cgroup_root;
+ int ret;
+
+ if (argc > 1) {
+ p_err("too many parameters for cgroup tree");
+ return -1;
+ }
+
+ if (argc == 1) {
+ cgroup_root = argv[0];
+ } else {
+ cgroup_root = find_cgroup_root();
+ if (!cgroup_root) {
+ p_err("cgroup v2 isn't mounted");
+ return -1;
+ }
+ }
+
+ if (json_output)
+ jsonw_start_array(json_wtr);
+ else
+ printf("%s\n"
+ "%-8s %-15s %-15s %-15s\n",
+ "CgroupPath",
+ "ID", "AttachType", "AttachFlags", "Name");
+
+ ret = nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT);
+ if (ret && errno == ENOENT)
+ p_err("can't iterate over %s: %s", cgroup_root,
+ strerror(errno));
+
+ if (json_output)
+ jsonw_end_array(json_wtr);
+
+ return ret;
+}
+
static int do_attach(int argc, char **argv)
{
enum bpf_attach_type attach_type;
@@ -289,6 +426,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } CGROUP\n"
+ " %s %s tree [CGROUP_ROOT]\n"
" %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
" %s %s detach CGROUP ATTACH_TYPE PROG\n"
" %s %s help\n"
@@ -298,6 +436,7 @@ static int do_help(int argc, char **argv)
" " HELP_SPEC_PROGRAM "\n"
" " HELP_SPEC_OPTIONS "\n"
"",
+ bin_name, argv[-2],
bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2], bin_name, argv[-2]);
@@ -307,6 +446,7 @@ static int do_help(int argc, char **argv)
static const struct cmd cmds[] = {
{ "show", do_show },
{ "list", do_show },
+ { "tree", do_show_tree },
{ "attach", do_attach },
{ "detach", do_detach },
{ "help", do_help },
--
2.14.4
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH bpf-next 2/2] bpftool: document cgroup tree command 2018-07-06 1:05 [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command Roman Gushchin @ 2018-07-06 1:05 ` Roman Gushchin 2018-07-06 2:01 ` Jakub Kicinski 2018-07-06 2:01 ` [PATCH bpf-next 1/2] bpftool: introduce " Jakub Kicinski 1 sibling, 1 reply; 6+ messages in thread From: Roman Gushchin @ 2018-07-06 1:05 UTC (permalink / raw) To: netdev Cc: linux-kernel, kernel-team, Roman Gushchin, Jakub Kicinski, Quentin Monnet, Daniel Borkmann, Alexei Starovoitov Describe cgroup tree command in the corresponding bpftool man page. Signed-off-by: Roman Gushchin <guro@fb.com> Cc: Jakub Kicinski <jakub.kicinski@netronome.com> Cc: Quentin Monnet <quentin.monnet@netronome.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Alexei Starovoitov <ast@kernel.org> --- tools/bpf/bpftool/Documentation/bpftool-cgroup.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst index 7b0e6d453e92..3b3d6c534317 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst @@ -21,6 +21,7 @@ MAP COMMANDS ============= | **bpftool** **cgroup { show | list }** *CGROUP* +| **bpftool** **cgroup tree** [*CGROUP_ROOT*] | **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] | **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG* | **bpftool** **cgroup help** @@ -39,6 +40,15 @@ DESCRIPTION Output will start with program ID followed by attach type, attach flags and program name. + **bpftool cgroup tree** [*CGROUP_ROOT*] + Iterate over all cgroups in *CGROUP_ROOT* and list all + attached programs. If *CGROUP_ROOT* is not specified, + bpftool uses cgroup v2 mountpoint. + + The output is similar to the output of cgroup show/list + commands: it starts with absolute cgroup path, followed by + program ID, attach type, attach flags and program name. + **bpftool cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] Attach program *PROG* to the cgroup *CGROUP* with attach type *ATTACH_TYPE* and optional *ATTACH_FLAGS*. -- 2.14.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next 2/2] bpftool: document cgroup tree command 2018-07-06 1:05 ` [PATCH bpf-next 2/2] bpftool: document " Roman Gushchin @ 2018-07-06 2:01 ` Jakub Kicinski 0 siblings, 0 replies; 6+ messages in thread From: Jakub Kicinski @ 2018-07-06 2:01 UTC (permalink / raw) To: Roman Gushchin Cc: netdev, linux-kernel, kernel-team, Quentin Monnet, Daniel Borkmann, Alexei Starovoitov On Thu, 5 Jul 2018 18:05:21 -0700, Roman Gushchin wrote: > Describe cgroup tree command in the corresponding bpftool man page. > > Signed-off-by: Roman Gushchin <guro@fb.com> > Cc: Jakub Kicinski <jakub.kicinski@netronome.com> > Cc: Quentin Monnet <quentin.monnet@netronome.com> > Cc: Daniel Borkmann <daniel@iogearbox.net> > Cc: Alexei Starovoitov <ast@kernel.org> Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command 2018-07-06 1:05 [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command Roman Gushchin 2018-07-06 1:05 ` [PATCH bpf-next 2/2] bpftool: document " Roman Gushchin @ 2018-07-06 2:01 ` Jakub Kicinski 2018-07-06 18:25 ` Roman Gushchin 1 sibling, 1 reply; 6+ messages in thread From: Jakub Kicinski @ 2018-07-06 2:01 UTC (permalink / raw) To: Roman Gushchin Cc: netdev, linux-kernel, kernel-team, Quentin Monnet, Daniel Borkmann, Alexei Starovoitov, David Ahern On Thu, 5 Jul 2018 18:05:20 -0700, Roman Gushchin wrote: > This commit introduces a new bpftool command: cgroup tree. > The idea is to iterate over the whole cgroup tree and print > all attached programs. > > I was debugging a bpf/systemd issue, and found, that there is > no simple way to listen all bpf programs attached to cgroups. > I did master something in bash, but after some time got tired of it, > and decided, that adding a dedicated bpftool command could be > a better idea. > > So, here it is: > $ sudo ./bpftool cgroup tree > CgroupPath > ID AttachType AttachFlags Name > /sys/fs/cgroup/system.slice/systemd-machined.service > 18 ingress > 17 egress > /sys/fs/cgroup/system.slice/systemd-logind.service > 20 ingress > 19 egress > /sys/fs/cgroup/system.slice/systemd-udevd.service > 16 ingress > 15 egress > /sys/fs/cgroup/system.slice/systemd-journald.service > 14 ingress > 13 egress > > Signed-off-by: Roman Gushchin <guro@fb.com> > Cc: Jakub Kicinski <jakub.kicinski@netronome.com> > Cc: Quentin Monnet <quentin.monnet@netronome.com> > Cc: Daniel Borkmann <daniel@iogearbox.net> > Cc: Alexei Starovoitov <ast@kernel.org> Looks very useful! Minor nits/questions below. I think the reverse mapping could also be interesting - similar to how -f flag shows where program is pinned, we could add a flag which in # bpftool prog show/list adds info about cgroups where the program is attached? Obviously as a future extension. > diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c > index 16bee011e16c..125d5b6db568 100644 > --- a/tools/bpf/bpftool/cgroup.c > +++ b/tools/bpf/bpftool/cgroup.c > @@ -2,7 +2,12 @@ > // Copyright (C) 2017 Facebook > // Author: Roman Gushchin <guro@fb.com> > > +#define _XOPEN_SOURCE 500 > +#include <errno.h> > #include <fcntl.h> > +#include <ftw.h> > +#include <mntent.h> > +#include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <sys/stat.h> > @@ -53,7 +58,8 @@ static enum bpf_attach_type parse_attach_type(const char *str) > } > > static int show_bpf_prog(int id, const char *attach_type_str, > - const char *attach_flags_str) > + const char *attach_flags_str, > + int level) > { > struct bpf_prog_info info = {}; > __u32 info_len = sizeof(info); > @@ -78,7 +84,8 @@ static int show_bpf_prog(int id, const char *attach_type_str, > jsonw_string_field(json_wtr, "name", info.name); > jsonw_end_object(json_wtr); > } else { > - printf("%-8u %-15s %-15s %-15s\n", info.id, > + printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "", > + info.id, > attach_type_str, > attach_flags_str, > info.name); > @@ -88,7 +95,20 @@ static int show_bpf_prog(int id, const char *attach_type_str, > return 0; > } > > -static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) > +static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) > +{ > + __u32 prog_cnt = 0; > + int ret; > + > + ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt); > + if (ret) > + return -1; > + > + return prog_cnt; > +} > + > +static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, > + int level) > { > __u32 prog_ids[1024] = {0}; > char *attach_flags_str; > @@ -123,7 +143,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) > > for (iter = 0; iter < prog_cnt; iter++) > show_bpf_prog(prog_ids[iter], attach_type_strings[type], > - attach_flags_str); > + attach_flags_str, level); > > return 0; > } > @@ -161,7 +181,7 @@ static int do_show(int argc, char **argv) > * If we were able to get the show for at least one > * attach type, let's return 0. > */ > - if (show_attached_bpf_progs(cgroup_fd, type) == 0) > + if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0) > ret = 0; > } > > @@ -173,6 +193,123 @@ static int do_show(int argc, char **argv) > return ret; > } > > +static int do_show_tree_fn(const char *fpath, const struct stat *sb, > + int typeflag, struct FTW *ftw) > +{ > + enum bpf_attach_type type; > + bool skip = true; > + int cgroup_fd; > + > + if (typeflag != FTW_D) > + return 0; > + > + cgroup_fd = open(fpath, O_RDONLY); > + if (cgroup_fd < 0) { > + p_err("can't open cgroup %s: %s", fpath, strerror(errno)); > + return -1; > + } > + > + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { > + int count = count_attached_bpf_progs(cgroup_fd, type); > + > + if (count < 0 && errno != EINVAL) { > + p_err("can't query bpf programs attached to %s: %s", > + fpath, strerror(errno)); > + close(cgroup_fd); > + return -1; > + } > + if (count > 0) { > + skip = false; > + break; > + } > + } > + > + if (skip) { > + close(cgroup_fd); > + return 0; > + } > + > + if (json_output) { > + jsonw_start_object(json_wtr); > + jsonw_string_field(json_wtr, "cgroup", fpath); > + jsonw_name(json_wtr, "programs"); > + jsonw_start_array(json_wtr); > + } else { > + printf("%s\n", fpath); > + } > + > + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) > + show_attached_bpf_progs(cgroup_fd, type, ftw->level); > + > + if (json_output) { > + jsonw_end_array(json_wtr); > + jsonw_end_object(json_wtr); > + } > + > + close(cgroup_fd); > + > + return 0; > +} > + > +static char *find_cgroup_root(void) > +{ > + struct mntent *mnt; > + FILE *f; > + > + f = fopen("/proc/mounts", "r"); > + if (f == NULL) > + return NULL; > + > + while ((mnt = getmntent(f))) { > + if (strcmp(mnt->mnt_type, "cgroup2") == 0) { > + fclose(f); > + return strdup(mnt->mnt_dir); FWIW you don't free this memory. > + } > + } > + > + fclose(f); > + return NULL; > +} > + > +static int do_show_tree(int argc, char **argv) > +{ > + char *cgroup_root; > + int ret; > + > + if (argc > 1) { > + p_err("too many parameters for cgroup tree"); > + return -1; > + } > + > + if (argc == 1) { > + cgroup_root = argv[0]; > + } else { > + cgroup_root = find_cgroup_root(); > + > + if (!cgroup_root) { > + p_err("cgroup v2 isn't mounted"); > + return -1; > + } > + } > + > + if (json_output) > + jsonw_start_array(json_wtr); > + else > + printf("%s\n" > + "%-8s %-15s %-15s %-15s\n", > + "CgroupPath", > + "ID", "AttachType", "AttachFlags", "Name"); > + > + ret = nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT); > + if (ret && errno == ENOENT) > + p_err("can't iterate over %s: %s", cgroup_root, > + strerror(errno)); I'm worried this could lead to a duplicated error in JSON output, no? Is it possible that do_show_tree_fn() would have already printed an error? > + > + if (json_output) > + jsonw_end_array(json_wtr); > + > + return ret; > +} > + > static int do_attach(int argc, char **argv) > { > enum bpf_attach_type attach_type; > @@ -289,6 +426,7 @@ static int do_help(int argc, char **argv) > > fprintf(stderr, > "Usage: %s %s { show | list } CGROUP\n" > + " %s %s tree [CGROUP_ROOT]\n" > " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" > " %s %s detach CGROUP ATTACH_TYPE PROG\n" > " %s %s help\n" > @@ -298,6 +436,7 @@ static int do_help(int argc, char **argv) > " " HELP_SPEC_PROGRAM "\n" > " " HELP_SPEC_OPTIONS "\n" > "", > + bin_name, argv[-2], > bin_name, argv[-2], bin_name, argv[-2], > bin_name, argv[-2], bin_name, argv[-2]); > > @@ -307,6 +446,7 @@ static int do_help(int argc, char **argv) > static const struct cmd cmds[] = { > { "show", do_show }, > { "list", do_show }, > + { "tree", do_show_tree }, > { "attach", do_attach }, > { "detach", do_detach }, > { "help", do_help }, Could you please also add this new command to bash completions? It should be fairly trivial to handle. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command 2018-07-06 2:01 ` [PATCH bpf-next 1/2] bpftool: introduce " Jakub Kicinski @ 2018-07-06 18:25 ` Roman Gushchin 2018-07-06 21:03 ` Jakub Kicinski 0 siblings, 1 reply; 6+ messages in thread From: Roman Gushchin @ 2018-07-06 18:25 UTC (permalink / raw) To: Jakub Kicinski Cc: netdev, linux-kernel, kernel-team, Quentin Monnet, Daniel Borkmann, Alexei Starovoitov, David Ahern On Thu, Jul 05, 2018 at 07:01:16PM -0700, Jakub Kicinski wrote: > On Thu, 5 Jul 2018 18:05:20 -0700, Roman Gushchin wrote: > > This commit introduces a new bpftool command: cgroup tree. > > The idea is to iterate over the whole cgroup tree and print > > all attached programs. > > > > I was debugging a bpf/systemd issue, and found, that there is > > no simple way to listen all bpf programs attached to cgroups. > > I did master something in bash, but after some time got tired of it, > > and decided, that adding a dedicated bpftool command could be > > a better idea. > > > > So, here it is: > > $ sudo ./bpftool cgroup tree > > CgroupPath > > ID AttachType AttachFlags Name > > /sys/fs/cgroup/system.slice/systemd-machined.service > > 18 ingress > > 17 egress > > /sys/fs/cgroup/system.slice/systemd-logind.service > > 20 ingress > > 19 egress > > /sys/fs/cgroup/system.slice/systemd-udevd.service > > 16 ingress > > 15 egress > > /sys/fs/cgroup/system.slice/systemd-journald.service > > 14 ingress > > 13 egress > > > > Signed-off-by: Roman Gushchin <guro@fb.com> > > Cc: Jakub Kicinski <jakub.kicinski@netronome.com> > > Cc: Quentin Monnet <quentin.monnet@netronome.com> > > Cc: Daniel Borkmann <daniel@iogearbox.net> > > Cc: Alexei Starovoitov <ast@kernel.org> > > Looks very useful! Minor nits/questions below. I think the reverse > mapping could also be interesting - similar to how -f flag shows where > program is pinned, we could add a flag which in > > # bpftool prog show/list > > adds info about cgroups where the program is attached? Obviously as a > future extension. Well, it would be convenient, but it's not always possible. A program can be attached to a dying cgroup (a cgroup which was deleted by a user, but still has some associated resources, e.g. pagecache). > > > diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c > > index 16bee011e16c..125d5b6db568 100644 > > --- a/tools/bpf/bpftool/cgroup.c > > +++ b/tools/bpf/bpftool/cgroup.c > > @@ -2,7 +2,12 @@ > > // Copyright (C) 2017 Facebook > > // Author: Roman Gushchin <guro@fb.com> > > > > +#define _XOPEN_SOURCE 500 > > +#include <errno.h> > > #include <fcntl.h> > > +#include <ftw.h> > > +#include <mntent.h> > > +#include <stdio.h> > > #include <stdlib.h> > > #include <string.h> > > #include <sys/stat.h> > > @@ -53,7 +58,8 @@ static enum bpf_attach_type parse_attach_type(const char *str) > > } > > > > static int show_bpf_prog(int id, const char *attach_type_str, > > - const char *attach_flags_str) > > + const char *attach_flags_str, > > + int level) > > { > > struct bpf_prog_info info = {}; > > __u32 info_len = sizeof(info); > > @@ -78,7 +84,8 @@ static int show_bpf_prog(int id, const char *attach_type_str, > > jsonw_string_field(json_wtr, "name", info.name); > > jsonw_end_object(json_wtr); > > } else { > > - printf("%-8u %-15s %-15s %-15s\n", info.id, > > + printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "", > > + info.id, > > attach_type_str, > > attach_flags_str, > > info.name); > > @@ -88,7 +95,20 @@ static int show_bpf_prog(int id, const char *attach_type_str, > > return 0; > > } > > > > -static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) > > +static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) > > +{ > > + __u32 prog_cnt = 0; > > + int ret; > > + > > + ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt); > > + if (ret) > > + return -1; > > + > > + return prog_cnt; > > +} > > + > > +static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, > > + int level) > > { > > __u32 prog_ids[1024] = {0}; > > char *attach_flags_str; > > @@ -123,7 +143,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) > > > > for (iter = 0; iter < prog_cnt; iter++) > > show_bpf_prog(prog_ids[iter], attach_type_strings[type], > > - attach_flags_str); > > + attach_flags_str, level); > > > > return 0; > > } > > @@ -161,7 +181,7 @@ static int do_show(int argc, char **argv) > > * If we were able to get the show for at least one > > * attach type, let's return 0. > > */ > > - if (show_attached_bpf_progs(cgroup_fd, type) == 0) > > + if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0) > > ret = 0; > > } > > > > @@ -173,6 +193,123 @@ static int do_show(int argc, char **argv) > > return ret; > > } > > > > +static int do_show_tree_fn(const char *fpath, const struct stat *sb, > > + int typeflag, struct FTW *ftw) > > +{ > > + enum bpf_attach_type type; > > + bool skip = true; > > + int cgroup_fd; > > + > > + if (typeflag != FTW_D) > > + return 0; > > + > > + cgroup_fd = open(fpath, O_RDONLY); > > + if (cgroup_fd < 0) { > > + p_err("can't open cgroup %s: %s", fpath, strerror(errno)); > > + return -1; > > + } > > + > > + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { > > + int count = count_attached_bpf_progs(cgroup_fd, type); > > + > > + if (count < 0 && errno != EINVAL) { > > + p_err("can't query bpf programs attached to %s: %s", > > + fpath, strerror(errno)); > > + close(cgroup_fd); > > + return -1; > > + } > > + if (count > 0) { > > + skip = false; > > + break; > > + } > > + } > > + > > + if (skip) { > > + close(cgroup_fd); > > + return 0; > > + } > > + > > + if (json_output) { > > + jsonw_start_object(json_wtr); > > + jsonw_string_field(json_wtr, "cgroup", fpath); > > + jsonw_name(json_wtr, "programs"); > > + jsonw_start_array(json_wtr); > > + } else { > > + printf("%s\n", fpath); > > + } > > + > > + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) > > + show_attached_bpf_progs(cgroup_fd, type, ftw->level); > > + > > + if (json_output) { > > + jsonw_end_array(json_wtr); > > + jsonw_end_object(json_wtr); > > + } > > + > > + close(cgroup_fd); > > + > > + return 0; > > +} > > + > > +static char *find_cgroup_root(void) > > +{ > > + struct mntent *mnt; > > + FILE *f; > > + > > + f = fopen("/proc/mounts", "r"); > > + if (f == NULL) > > + return NULL; > > + > > + while ((mnt = getmntent(f))) { > > + if (strcmp(mnt->mnt_type, "cgroup2") == 0) { > > + fclose(f); > > + return strdup(mnt->mnt_dir); > > FWIW you don't free this memory. Doesn't really matter, as we do exit immediately after, but fixed in v2 anyway. > > > + } > > + } > > + > > + fclose(f); > > + return NULL; > > +} > > + > > +static int do_show_tree(int argc, char **argv) > > +{ > > + char *cgroup_root; > > + int ret; > > + > > + if (argc > 1) { > > + p_err("too many parameters for cgroup tree"); > > + return -1; > > + } > > + > > + if (argc == 1) { > > + cgroup_root = argv[0]; > > + } else { > > + cgroup_root = find_cgroup_root(); > > + > > + if (!cgroup_root) { > > + p_err("cgroup v2 isn't mounted"); > > + return -1; > > + } > > + } > > + > > + if (json_output) > > + jsonw_start_array(json_wtr); > > + else > > + printf("%s\n" > > + "%-8s %-15s %-15s %-15s\n", > > + "CgroupPath", > > + "ID", "AttachType", "AttachFlags", "Name"); > > + > > + ret = nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT); > > + if (ret && errno == ENOENT) > > + p_err("can't iterate over %s: %s", cgroup_root, > > + strerror(errno)); > > I'm worried this could lead to a duplicated error in JSON output, no? > Is it possible that do_show_tree_fn() would have already printed an > error? Fixed in v2. > > > + > > + if (json_output) > > + jsonw_end_array(json_wtr); > > + > > + return ret; > > +} > > + > > static int do_attach(int argc, char **argv) > > { > > enum bpf_attach_type attach_type; > > @@ -289,6 +426,7 @@ static int do_help(int argc, char **argv) > > > > fprintf(stderr, > > "Usage: %s %s { show | list } CGROUP\n" > > + " %s %s tree [CGROUP_ROOT]\n" > > " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" > > " %s %s detach CGROUP ATTACH_TYPE PROG\n" > > " %s %s help\n" > > @@ -298,6 +436,7 @@ static int do_help(int argc, char **argv) > > " " HELP_SPEC_PROGRAM "\n" > > " " HELP_SPEC_OPTIONS "\n" > > "", > > + bin_name, argv[-2], > > bin_name, argv[-2], bin_name, argv[-2], > > bin_name, argv[-2], bin_name, argv[-2]); > > > > @@ -307,6 +446,7 @@ static int do_help(int argc, char **argv) > > static const struct cmd cmds[] = { > > { "show", do_show }, > > { "list", do_show }, > > + { "tree", do_show_tree }, > > { "attach", do_attach }, > > { "detach", do_detach }, > > { "help", do_help }, > > Could you please also add this new command to bash completions? It > should be fairly trivial to handle. Sure. Thanks! ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command 2018-07-06 18:25 ` Roman Gushchin @ 2018-07-06 21:03 ` Jakub Kicinski 0 siblings, 0 replies; 6+ messages in thread From: Jakub Kicinski @ 2018-07-06 21:03 UTC (permalink / raw) To: Roman Gushchin Cc: netdev, linux-kernel, kernel-team, Quentin Monnet, Daniel Borkmann, Alexei Starovoitov, David Ahern On Fri, 6 Jul 2018 11:25:45 -0700, Roman Gushchin wrote: > > Looks very useful! Minor nits/questions below. I think the reverse > > mapping could also be interesting - similar to how -f flag shows where > > program is pinned, we could add a flag which in > > > > # bpftool prog show/list > > > > adds info about cgroups where the program is attached? Obviously as a > > future extension. > > Well, it would be convenient, but it's not always possible. > A program can be attached to a dying cgroup (a cgroup which was deleted > by a user, but still has some associated resources, e.g. pagecache). Ack, the bpffs and cgroupfs searches are best effort by definition. Thanks for addressing the other comments! ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2018-07-06 21:03 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-07-06 1:05 [PATCH bpf-next 1/2] bpftool: introduce cgroup tree command Roman Gushchin 2018-07-06 1:05 ` [PATCH bpf-next 2/2] bpftool: document " Roman Gushchin 2018-07-06 2:01 ` Jakub Kicinski 2018-07-06 2:01 ` [PATCH bpf-next 1/2] bpftool: introduce " Jakub Kicinski 2018-07-06 18:25 ` Roman Gushchin 2018-07-06 21:03 ` Jakub Kicinski
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).