~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/bpf/bpftool/cgroup.c

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp