intel_idle: add SnowRidge C-state table
[linux-2.6-microblaze.git] / tools / bpf / bpftool / cgroup.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 // Copyright (C) 2017 Facebook
3 // Author: Roman Gushchin <guro@fb.com>
4
5 #define _XOPEN_SOURCE 500
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <ftw.h>
9 #include <mntent.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <bpf/bpf.h>
18
19 #include "main.h"
20
21 #define HELP_SPEC_ATTACH_FLAGS                                          \
22         "ATTACH_FLAGS := { multi | override }"
23
24 #define HELP_SPEC_ATTACH_TYPES                                                 \
25         "       ATTACH_TYPE := { ingress | egress | sock_create |\n"           \
26         "                        sock_ops | device | bind4 | bind6 |\n"        \
27         "                        post_bind4 | post_bind6 | connect4 |\n"       \
28         "                        connect6 | getpeername4 | getpeername6 |\n"   \
29         "                        getsockname4 | getsockname6 | sendmsg4 |\n"   \
30         "                        sendmsg6 | recvmsg4 | recvmsg6 |\n"           \
31         "                        sysctl | getsockopt | setsockopt }"
32
33 static unsigned int query_flags;
34
35 static enum bpf_attach_type parse_attach_type(const char *str)
36 {
37         enum bpf_attach_type type;
38
39         for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
40                 if (attach_type_name[type] &&
41                     is_prefix(str, attach_type_name[type]))
42                         return type;
43         }
44
45         return __MAX_BPF_ATTACH_TYPE;
46 }
47
48 static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
49                          const char *attach_flags_str,
50                          int level)
51 {
52         struct bpf_prog_info info = {};
53         __u32 info_len = sizeof(info);
54         int prog_fd;
55
56         prog_fd = bpf_prog_get_fd_by_id(id);
57         if (prog_fd < 0)
58                 return -1;
59
60         if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
61                 close(prog_fd);
62                 return -1;
63         }
64
65         if (json_output) {
66                 jsonw_start_object(json_wtr);
67                 jsonw_uint_field(json_wtr, "id", info.id);
68                 if (attach_type < ARRAY_SIZE(attach_type_name))
69                         jsonw_string_field(json_wtr, "attach_type",
70                                            attach_type_name[attach_type]);
71                 else
72                         jsonw_uint_field(json_wtr, "attach_type", attach_type);
73                 jsonw_string_field(json_wtr, "attach_flags",
74                                    attach_flags_str);
75                 jsonw_string_field(json_wtr, "name", info.name);
76                 jsonw_end_object(json_wtr);
77         } else {
78                 printf("%s%-8u ", level ? "    " : "", info.id);
79                 if (attach_type < ARRAY_SIZE(attach_type_name))
80                         printf("%-15s", attach_type_name[attach_type]);
81                 else
82                         printf("type %-10u", attach_type);
83                 printf(" %-15s %-15s\n", attach_flags_str, info.name);
84         }
85
86         close(prog_fd);
87         return 0;
88 }
89
90 static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
91 {
92         __u32 prog_cnt = 0;
93         int ret;
94
95         ret = bpf_prog_query(cgroup_fd, type, query_flags, NULL,
96                              NULL, &prog_cnt);
97         if (ret)
98                 return -1;
99
100         return prog_cnt;
101 }
102
103 static int cgroup_has_attached_progs(int cgroup_fd)
104 {
105         enum bpf_attach_type type;
106         bool no_prog = true;
107
108         for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
109                 int count = count_attached_bpf_progs(cgroup_fd, type);
110
111                 if (count < 0 && errno != EINVAL)
112                         return -1;
113
114                 if (count > 0) {
115                         no_prog = false;
116                         break;
117                 }
118         }
119
120         return no_prog ? 0 : 1;
121 }
122 static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
123                                    int level)
124 {
125         const char *attach_flags_str;
126         __u32 prog_ids[1024] = {0};
127         __u32 prog_cnt, iter;
128         __u32 attach_flags;
129         char buf[32];
130         int ret;
131
132         prog_cnt = ARRAY_SIZE(prog_ids);
133         ret = bpf_prog_query(cgroup_fd, type, query_flags, &attach_flags,
134                              prog_ids, &prog_cnt);
135         if (ret)
136                 return ret;
137
138         if (prog_cnt == 0)
139                 return 0;
140
141         switch (attach_flags) {
142         case BPF_F_ALLOW_MULTI:
143                 attach_flags_str = "multi";
144                 break;
145         case BPF_F_ALLOW_OVERRIDE:
146                 attach_flags_str = "override";
147                 break;
148         case 0:
149                 attach_flags_str = "";
150                 break;
151         default:
152                 snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
153                 attach_flags_str = buf;
154         }
155
156         for (iter = 0; iter < prog_cnt; iter++)
157                 show_bpf_prog(prog_ids[iter], type,
158                               attach_flags_str, level);
159
160         return 0;
161 }
162
163 static int do_show(int argc, char **argv)
164 {
165         enum bpf_attach_type type;
166         int has_attached_progs;
167         const char *path;
168         int cgroup_fd;
169         int ret = -1;
170
171         query_flags = 0;
172
173         if (!REQ_ARGS(1))
174                 return -1;
175         path = GET_ARG();
176
177         while (argc) {
178                 if (is_prefix(*argv, "effective")) {
179                         if (query_flags & BPF_F_QUERY_EFFECTIVE) {
180                                 p_err("duplicated argument: %s", *argv);
181                                 return -1;
182                         }
183                         query_flags |= BPF_F_QUERY_EFFECTIVE;
184                         NEXT_ARG();
185                 } else {
186                         p_err("expected no more arguments, 'effective', got: '%s'?",
187                               *argv);
188                         return -1;
189                 }
190         }
191
192         cgroup_fd = open(path, O_RDONLY);
193         if (cgroup_fd < 0) {
194                 p_err("can't open cgroup %s", path);
195                 goto exit;
196         }
197
198         has_attached_progs = cgroup_has_attached_progs(cgroup_fd);
199         if (has_attached_progs < 0) {
200                 p_err("can't query bpf programs attached to %s: %s",
201                       path, strerror(errno));
202                 goto exit_cgroup;
203         } else if (!has_attached_progs) {
204                 ret = 0;
205                 goto exit_cgroup;
206         }
207
208         if (json_output)
209                 jsonw_start_array(json_wtr);
210         else
211                 printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
212                        "AttachFlags", "Name");
213
214         for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
215                 /*
216                  * Not all attach types may be supported, so it's expected,
217                  * that some requests will fail.
218                  * If we were able to get the show for at least one
219                  * attach type, let's return 0.
220                  */
221                 if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0)
222                         ret = 0;
223         }
224
225         if (json_output)
226                 jsonw_end_array(json_wtr);
227
228 exit_cgroup:
229         close(cgroup_fd);
230 exit:
231         return ret;
232 }
233
234 /*
235  * To distinguish nftw() errors and do_show_tree_fn() errors
236  * and avoid duplicating error messages, let's return -2
237  * from do_show_tree_fn() in case of error.
238  */
239 #define NFTW_ERR                -1
240 #define SHOW_TREE_FN_ERR        -2
241 static int do_show_tree_fn(const char *fpath, const struct stat *sb,
242                            int typeflag, struct FTW *ftw)
243 {
244         enum bpf_attach_type type;
245         int has_attached_progs;
246         int cgroup_fd;
247
248         if (typeflag != FTW_D)
249                 return 0;
250
251         cgroup_fd = open(fpath, O_RDONLY);
252         if (cgroup_fd < 0) {
253                 p_err("can't open cgroup %s: %s", fpath, strerror(errno));
254                 return SHOW_TREE_FN_ERR;
255         }
256
257         has_attached_progs = cgroup_has_attached_progs(cgroup_fd);
258         if (has_attached_progs < 0) {
259                 p_err("can't query bpf programs attached to %s: %s",
260                       fpath, strerror(errno));
261                 close(cgroup_fd);
262                 return SHOW_TREE_FN_ERR;
263         } else if (!has_attached_progs) {
264                 close(cgroup_fd);
265                 return 0;
266         }
267
268         if (json_output) {
269                 jsonw_start_object(json_wtr);
270                 jsonw_string_field(json_wtr, "cgroup", fpath);
271                 jsonw_name(json_wtr, "programs");
272                 jsonw_start_array(json_wtr);
273         } else {
274                 printf("%s\n", fpath);
275         }
276
277         for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++)
278                 show_attached_bpf_progs(cgroup_fd, type, ftw->level);
279
280         if (errno == EINVAL)
281                 /* Last attach type does not support query.
282                  * Do not report an error for this, especially because batch
283                  * mode would stop processing commands.
284                  */
285                 errno = 0;
286
287         if (json_output) {
288                 jsonw_end_array(json_wtr);
289                 jsonw_end_object(json_wtr);
290         }
291
292         close(cgroup_fd);
293
294         return 0;
295 }
296
297 static char *find_cgroup_root(void)
298 {
299         struct mntent *mnt;
300         FILE *f;
301
302         f = fopen("/proc/mounts", "r");
303         if (f == NULL)
304                 return NULL;
305
306         while ((mnt = getmntent(f))) {
307                 if (strcmp(mnt->mnt_type, "cgroup2") == 0) {
308                         fclose(f);
309                         return strdup(mnt->mnt_dir);
310                 }
311         }
312
313         fclose(f);
314         return NULL;
315 }
316
317 static int do_show_tree(int argc, char **argv)
318 {
319         char *cgroup_root, *cgroup_alloced = NULL;
320         int ret;
321
322         query_flags = 0;
323
324         if (!argc) {
325                 cgroup_alloced = find_cgroup_root();
326                 if (!cgroup_alloced) {
327                         p_err("cgroup v2 isn't mounted");
328                         return -1;
329                 }
330                 cgroup_root = cgroup_alloced;
331         } else {
332                 cgroup_root = GET_ARG();
333
334                 while (argc) {
335                         if (is_prefix(*argv, "effective")) {
336                                 if (query_flags & BPF_F_QUERY_EFFECTIVE) {
337                                         p_err("duplicated argument: %s", *argv);
338                                         return -1;
339                                 }
340                                 query_flags |= BPF_F_QUERY_EFFECTIVE;
341                                 NEXT_ARG();
342                         } else {
343                                 p_err("expected no more arguments, 'effective', got: '%s'?",
344                                       *argv);
345                                 return -1;
346                         }
347                 }
348         }
349
350         if (json_output)
351                 jsonw_start_array(json_wtr);
352         else
353                 printf("%s\n"
354                        "%-8s %-15s %-15s %-15s\n",
355                        "CgroupPath",
356                        "ID", "AttachType", "AttachFlags", "Name");
357
358         switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) {
359         case NFTW_ERR:
360                 p_err("can't iterate over %s: %s", cgroup_root,
361                       strerror(errno));
362                 ret = -1;
363                 break;
364         case SHOW_TREE_FN_ERR:
365                 ret = -1;
366                 break;
367         default:
368                 ret = 0;
369         }
370
371         if (json_output)
372                 jsonw_end_array(json_wtr);
373
374         free(cgroup_alloced);
375
376         return ret;
377 }
378
379 static int do_attach(int argc, char **argv)
380 {
381         enum bpf_attach_type attach_type;
382         int cgroup_fd, prog_fd;
383         int attach_flags = 0;
384         int ret = -1;
385         int i;
386
387         if (argc < 4) {
388                 p_err("too few parameters for cgroup attach");
389                 goto exit;
390         }
391
392         cgroup_fd = open(argv[0], O_RDONLY);
393         if (cgroup_fd < 0) {
394                 p_err("can't open cgroup %s", argv[0]);
395                 goto exit;
396         }
397
398         attach_type = parse_attach_type(argv[1]);
399         if (attach_type == __MAX_BPF_ATTACH_TYPE) {
400                 p_err("invalid attach type");
401                 goto exit_cgroup;
402         }
403
404         argc -= 2;
405         argv = &argv[2];
406         prog_fd = prog_parse_fd(&argc, &argv);
407         if (prog_fd < 0)
408                 goto exit_cgroup;
409
410         for (i = 0; i < argc; i++) {
411                 if (is_prefix(argv[i], "multi")) {
412                         attach_flags |= BPF_F_ALLOW_MULTI;
413                 } else if (is_prefix(argv[i], "override")) {
414                         attach_flags |= BPF_F_ALLOW_OVERRIDE;
415                 } else {
416                         p_err("unknown option: %s", argv[i]);
417                         goto exit_cgroup;
418                 }
419         }
420
421         if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
422                 p_err("failed to attach program");
423                 goto exit_prog;
424         }
425
426         if (json_output)
427                 jsonw_null(json_wtr);
428
429         ret = 0;
430
431 exit_prog:
432         close(prog_fd);
433 exit_cgroup:
434         close(cgroup_fd);
435 exit:
436         return ret;
437 }
438
439 static int do_detach(int argc, char **argv)
440 {
441         enum bpf_attach_type attach_type;
442         int prog_fd, cgroup_fd;
443         int ret = -1;
444
445         if (argc < 4) {
446                 p_err("too few parameters for cgroup detach");
447                 goto exit;
448         }
449
450         cgroup_fd = open(argv[0], O_RDONLY);
451         if (cgroup_fd < 0) {
452                 p_err("can't open cgroup %s", argv[0]);
453                 goto exit;
454         }
455
456         attach_type = parse_attach_type(argv[1]);
457         if (attach_type == __MAX_BPF_ATTACH_TYPE) {
458                 p_err("invalid attach type");
459                 goto exit_cgroup;
460         }
461
462         argc -= 2;
463         argv = &argv[2];
464         prog_fd = prog_parse_fd(&argc, &argv);
465         if (prog_fd < 0)
466                 goto exit_cgroup;
467
468         if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
469                 p_err("failed to detach program");
470                 goto exit_prog;
471         }
472
473         if (json_output)
474                 jsonw_null(json_wtr);
475
476         ret = 0;
477
478 exit_prog:
479         close(prog_fd);
480 exit_cgroup:
481         close(cgroup_fd);
482 exit:
483         return ret;
484 }
485
486 static int do_help(int argc, char **argv)
487 {
488         if (json_output) {
489                 jsonw_null(json_wtr);
490                 return 0;
491         }
492
493         fprintf(stderr,
494                 "Usage: %1$s %2$s { show | list } CGROUP [**effective**]\n"
495                 "       %1$s %2$s tree [CGROUP_ROOT] [**effective**]\n"
496                 "       %1$s %2$s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
497                 "       %1$s %2$s detach CGROUP ATTACH_TYPE PROG\n"
498                 "       %1$s %2$s help\n"
499                 "\n"
500                 HELP_SPEC_ATTACH_TYPES "\n"
501                 "       " HELP_SPEC_ATTACH_FLAGS "\n"
502                 "       " HELP_SPEC_PROGRAM "\n"
503                 "       " HELP_SPEC_OPTIONS "\n"
504                 "",
505                 bin_name, argv[-2]);
506
507         return 0;
508 }
509
510 static const struct cmd cmds[] = {
511         { "show",       do_show },
512         { "list",       do_show },
513         { "tree",       do_show_tree },
514         { "attach",     do_attach },
515         { "detach",     do_detach },
516         { "help",       do_help },
517         { 0 }
518 };
519
520 int do_cgroup(int argc, char **argv)
521 {
522         return cmd_select(cmds, argc, argv, do_help);
523 }