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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ 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/bpf.h>
 18 #include <bpf/btf.h>
 19 
 20 #include "main.h"
 21 
 22 static const int cgroup_attach_types[] = {
 23         BPF_CGROUP_INET_INGRESS,
 24         BPF_CGROUP_INET_EGRESS,
 25         BPF_CGROUP_INET_SOCK_CREATE,
 26         BPF_CGROUP_INET_SOCK_RELEASE,
 27         BPF_CGROUP_INET4_BIND,
 28         BPF_CGROUP_INET6_BIND,
 29         BPF_CGROUP_INET4_POST_BIND,
 30         BPF_CGROUP_INET6_POST_BIND,
 31         BPF_CGROUP_INET4_CONNECT,
 32         BPF_CGROUP_INET6_CONNECT,
 33         BPF_CGROUP_UNIX_CONNECT,
 34         BPF_CGROUP_INET4_GETPEERNAME,
 35         BPF_CGROUP_INET6_GETPEERNAME,
 36         BPF_CGROUP_UNIX_GETPEERNAME,
 37         BPF_CGROUP_INET4_GETSOCKNAME,
 38         BPF_CGROUP_INET6_GETSOCKNAME,
 39         BPF_CGROUP_UNIX_GETSOCKNAME,
 40         BPF_CGROUP_UDP4_SENDMSG,
 41         BPF_CGROUP_UDP6_SENDMSG,
 42         BPF_CGROUP_UNIX_SENDMSG,
 43         BPF_CGROUP_UDP4_RECVMSG,
 44         BPF_CGROUP_UDP6_RECVMSG,
 45         BPF_CGROUP_UNIX_RECVMSG,
 46         BPF_CGROUP_SOCK_OPS,
 47         BPF_CGROUP_DEVICE,
 48         BPF_CGROUP_SYSCTL,
 49         BPF_CGROUP_GETSOCKOPT,
 50         BPF_CGROUP_SETSOCKOPT,
 51         BPF_LSM_CGROUP
 52 };
 53 
 54 #define HELP_SPEC_ATTACH_FLAGS                                          \
 55         "ATTACH_FLAGS := { multi | override }"
 56 
 57 #define HELP_SPEC_ATTACH_TYPES                                          \
 58         "       ATTACH_TYPE := { cgroup_inet_ingress | cgroup_inet_egress |\n" \
 59         "                        cgroup_inet_sock_create | cgroup_sock_ops |\n" \
 60         "                        cgroup_device | cgroup_inet4_bind |\n" \
 61         "                        cgroup_inet6_bind | cgroup_inet4_post_bind |\n" \
 62         "                        cgroup_inet6_post_bind | cgroup_inet4_connect |\n" \
 63         "                        cgroup_inet6_connect | cgroup_unix_connect |\n" \
 64         "                        cgroup_inet4_getpeername | cgroup_inet6_getpeername |\n" \
 65         "                        cgroup_unix_getpeername | cgroup_inet4_getsockname |\n" \
 66         "                        cgroup_inet6_getsockname | cgroup_unix_getsockname |\n" \
 67         "                        cgroup_udp4_sendmsg | cgroup_udp6_sendmsg |\n" \
 68         "                        cgroup_unix_sendmsg | cgroup_udp4_recvmsg |\n" \
 69         "                        cgroup_udp6_recvmsg | cgroup_unix_recvmsg |\n" \
 70         "                        cgroup_sysctl | cgroup_getsockopt |\n" \
 71         "                        cgroup_setsockopt | cgroup_inet_sock_release }"
 72 
 73 static unsigned int query_flags;
 74 static struct btf *btf_vmlinux;
 75 static __u32 btf_vmlinux_id;
 76 
 77 static enum bpf_attach_type parse_attach_type(const char *str)
 78 {
 79         const char *attach_type_str;
 80         enum bpf_attach_type type;
 81 
 82         for (type = 0; ; type++) {
 83                 attach_type_str = libbpf_bpf_attach_type_str(type);
 84                 if (!attach_type_str)
 85                         break;
 86                 if (!strcmp(str, attach_type_str))
 87                         return type;
 88         }
 89 
 90         /* Also check traditionally used attach type strings. For these we keep
 91          * allowing prefixed usage.
 92          */
 93         for (type = 0; ; type++) {
 94                 attach_type_str = bpf_attach_type_input_str(type);
 95                 if (!attach_type_str)
 96                         break;
 97                 if (is_prefix(str, attach_type_str))
 98                         return type;
 99         }
100 
101         return __MAX_BPF_ATTACH_TYPE;
102 }
103 
104 static void guess_vmlinux_btf_id(__u32 attach_btf_obj_id)
105 {
106         struct bpf_btf_info btf_info = {};
107         __u32 btf_len = sizeof(btf_info);
108         char name[16] = {};
109         int err;
110         int fd;
111 
112         btf_info.name = ptr_to_u64(name);
113         btf_info.name_len = sizeof(name);
114 
115         fd = bpf_btf_get_fd_by_id(attach_btf_obj_id);
116         if (fd < 0)
117                 return;
118 
119         err = bpf_btf_get_info_by_fd(fd, &btf_info, &btf_len);
120         if (err)
121                 goto out;
122 
123         if (btf_info.kernel_btf && strncmp(name, "vmlinux", sizeof(name)) == 0)
124                 btf_vmlinux_id = btf_info.id;
125 
126 out:
127         close(fd);
128 }
129 
130 static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
131                          const char *attach_flags_str,
132                          int level)
133 {
134         char prog_name[MAX_PROG_FULL_NAME];
135         const char *attach_btf_name = NULL;
136         struct bpf_prog_info info = {};
137         const char *attach_type_str;
138         __u32 info_len = sizeof(info);
139         int prog_fd;
140 
141         prog_fd = bpf_prog_get_fd_by_id(id);
142         if (prog_fd < 0)
143                 return -1;
144 
145         if (bpf_prog_get_info_by_fd(prog_fd, &info, &info_len)) {
146                 close(prog_fd);
147                 return -1;
148         }
149 
150         attach_type_str = libbpf_bpf_attach_type_str(attach_type);
151 
152         if (btf_vmlinux) {
153                 if (!btf_vmlinux_id)
154                         guess_vmlinux_btf_id(info.attach_btf_obj_id);
155 
156                 if (btf_vmlinux_id == info.attach_btf_obj_id &&
157                     info.attach_btf_id < btf__type_cnt(btf_vmlinux)) {
158                         const struct btf_type *t =
159                                 btf__type_by_id(btf_vmlinux, info.attach_btf_id);
160                         attach_btf_name =
161                                 btf__name_by_offset(btf_vmlinux, t->name_off);
162                 }
163         }
164 
165         get_prog_full_name(&info, prog_fd, prog_name, sizeof(prog_name));
166         if (json_output) {
167                 jsonw_start_object(json_wtr);
168                 jsonw_uint_field(json_wtr, "id", info.id);
169                 if (attach_type_str)
170                         jsonw_string_field(json_wtr, "attach_type", attach_type_str);
171                 else
172                         jsonw_uint_field(json_wtr, "attach_type", attach_type);
173                 if (!(query_flags & BPF_F_QUERY_EFFECTIVE))
174                         jsonw_string_field(json_wtr, "attach_flags", attach_flags_str);
175                 jsonw_string_field(json_wtr, "name", prog_name);
176                 if (attach_btf_name)
177                         jsonw_string_field(json_wtr, "attach_btf_name", attach_btf_name);
178                 jsonw_uint_field(json_wtr, "attach_btf_obj_id", info.attach_btf_obj_id);
179                 jsonw_uint_field(json_wtr, "attach_btf_id", info.attach_btf_id);
180                 jsonw_end_object(json_wtr);
181         } else {
182                 printf("%s%-8u ", level ? "    " : "", info.id);
183                 if (attach_type_str)
184                         printf("%-15s", attach_type_str);
185                 else
186                         printf("type %-10u", attach_type);
187                 if (query_flags & BPF_F_QUERY_EFFECTIVE)
188                         printf(" %-15s", prog_name);
189                 else
190                         printf(" %-15s %-15s", attach_flags_str, prog_name);
191                 if (attach_btf_name)
192                         printf(" %-15s", attach_btf_name);
193                 else if (info.attach_btf_id)
194                         printf(" attach_btf_obj_id=%d attach_btf_id=%d",
195                                info.attach_btf_obj_id, info.attach_btf_id);
196                 printf("\n");
197         }
198 
199         close(prog_fd);
200         return 0;
201 }
202 
203 static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
204 {
205         __u32 prog_cnt = 0;
206         int ret;
207 
208         ret = bpf_prog_query(cgroup_fd, type, query_flags, NULL,
209                              NULL, &prog_cnt);
210         if (ret)
211                 return -1;
212 
213         return prog_cnt;
214 }
215 
216 static int cgroup_has_attached_progs(int cgroup_fd)
217 {
218         unsigned int i = 0;
219         bool no_prog = true;
220 
221         for (i = 0; i < ARRAY_SIZE(cgroup_attach_types); i++) {
222                 int count = count_attached_bpf_progs(cgroup_fd, cgroup_attach_types[i]);
223 
224                 if (count < 0)
225                         return -1;
226 
227                 if (count > 0) {
228                         no_prog = false;
229                         break;
230                 }
231         }
232 
233         return no_prog ? 0 : 1;
234 }
235 
236 static int show_effective_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
237                                     int level)
238 {
239         LIBBPF_OPTS(bpf_prog_query_opts, p);
240         __u32 prog_ids[1024] = {0};
241         __u32 iter;
242         int ret;
243 
244         p.query_flags = query_flags;
245         p.prog_cnt = ARRAY_SIZE(prog_ids);
246         p.prog_ids = prog_ids;
247 
248         ret = bpf_prog_query_opts(cgroup_fd, type, &p);
249         if (ret)
250                 return ret;
251 
252         if (p.prog_cnt == 0)
253                 return 0;
254 
255         for (iter = 0; iter < p.prog_cnt; iter++)
256                 show_bpf_prog(prog_ids[iter], type, NULL, level);
257 
258         return 0;
259 }
260 
261 static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
262                                    int level)
263 {
264         LIBBPF_OPTS(bpf_prog_query_opts, p);
265         __u32 prog_attach_flags[1024] = {0};
266         const char *attach_flags_str;
267         __u32 prog_ids[1024] = {0};
268         char buf[32];
269         __u32 iter;
270         int ret;
271 
272         p.query_flags = query_flags;
273         p.prog_cnt = ARRAY_SIZE(prog_ids);
274         p.prog_ids = prog_ids;
275         p.prog_attach_flags = prog_attach_flags;
276 
277         ret = bpf_prog_query_opts(cgroup_fd, type, &p);
278         if (ret)
279                 return ret;
280 
281         if (p.prog_cnt == 0)
282                 return 0;
283 
284         for (iter = 0; iter < p.prog_cnt; iter++) {
285                 __u32 attach_flags;
286 
287                 attach_flags = prog_attach_flags[iter] ?: p.attach_flags;
288 
289                 switch (attach_flags) {
290                 case BPF_F_ALLOW_MULTI:
291                         attach_flags_str = "multi";
292                         break;
293                 case BPF_F_ALLOW_OVERRIDE:
294                         attach_flags_str = "override";
295                         break;
296                 case 0:
297                         attach_flags_str = "";
298                         break;
299                 default:
300                         snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
301                         attach_flags_str = buf;
302                 }
303 
304                 show_bpf_prog(prog_ids[iter], type,
305                               attach_flags_str, level);
306         }
307 
308         return 0;
309 }
310 
311 static int show_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
312                           int level)
313 {
314         return query_flags & BPF_F_QUERY_EFFECTIVE ?
315                show_effective_bpf_progs(cgroup_fd, type, level) :
316                show_attached_bpf_progs(cgroup_fd, type, level);
317 }
318 
319 static int do_show(int argc, char **argv)
320 {
321         enum bpf_attach_type type;
322         int has_attached_progs;
323         const char *path;
324         int cgroup_fd;
325         int ret = -1;
326 
327         query_flags = 0;
328 
329         if (!REQ_ARGS(1))
330                 return -1;
331         path = GET_ARG();
332 
333         while (argc) {
334                 if (is_prefix(*argv, "effective")) {
335                         if (query_flags & BPF_F_QUERY_EFFECTIVE) {
336                                 p_err("duplicated argument: %s", *argv);
337                                 return -1;
338                         }
339                         query_flags |= BPF_F_QUERY_EFFECTIVE;
340                         NEXT_ARG();
341                 } else {
342                         p_err("expected no more arguments, 'effective', got: '%s'?",
343                               *argv);
344                         return -1;
345                 }
346         }
347 
348         cgroup_fd = open(path, O_RDONLY);
349         if (cgroup_fd < 0) {
350                 p_err("can't open cgroup %s", path);
351                 goto exit;
352         }
353 
354         has_attached_progs = cgroup_has_attached_progs(cgroup_fd);
355         if (has_attached_progs < 0) {
356                 p_err("can't query bpf programs attached to %s: %s",
357                       path, strerror(errno));
358                 goto exit_cgroup;
359         } else if (!has_attached_progs) {
360                 ret = 0;
361                 goto exit_cgroup;
362         }
363 
364         if (json_output)
365                 jsonw_start_array(json_wtr);
366         else if (query_flags & BPF_F_QUERY_EFFECTIVE)
367                 printf("%-8s %-15s %-15s\n", "ID", "AttachType", "Name");
368         else
369                 printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
370                        "AttachFlags", "Name");
371 
372         btf_vmlinux = libbpf_find_kernel_btf();
373         for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
374                 /*
375                  * Not all attach types may be supported, so it's expected,
376                  * that some requests will fail.
377                  * If we were able to get the show for at least one
378                  * attach type, let's return 0.
379                  */
380                 if (show_bpf_progs(cgroup_fd, type, 0) == 0)
381                         ret = 0;
382         }
383 
384         if (json_output)
385                 jsonw_end_array(json_wtr);
386 
387 exit_cgroup:
388         close(cgroup_fd);
389 exit:
390         return ret;
391 }
392 
393 /*
394  * To distinguish nftw() errors and do_show_tree_fn() errors
395  * and avoid duplicating error messages, let's return -2
396  * from do_show_tree_fn() in case of error.
397  */
398 #define NFTW_ERR                -1
399 #define SHOW_TREE_FN_ERR        -2
400 static int do_show_tree_fn(const char *fpath, const struct stat *sb,
401                            int typeflag, struct FTW *ftw)
402 {
403         enum bpf_attach_type type;
404         int has_attached_progs;
405         int cgroup_fd;
406 
407         if (typeflag != FTW_D)
408                 return 0;
409 
410         cgroup_fd = open(fpath, O_RDONLY);
411         if (cgroup_fd < 0) {
412                 p_err("can't open cgroup %s: %s", fpath, strerror(errno));
413                 return SHOW_TREE_FN_ERR;
414         }
415 
416         has_attached_progs = cgroup_has_attached_progs(cgroup_fd);
417         if (has_attached_progs < 0) {
418                 p_err("can't query bpf programs attached to %s: %s",
419                       fpath, strerror(errno));
420                 close(cgroup_fd);
421                 return SHOW_TREE_FN_ERR;
422         } else if (!has_attached_progs) {
423                 close(cgroup_fd);
424                 return 0;
425         }
426 
427         if (json_output) {
428                 jsonw_start_object(json_wtr);
429                 jsonw_string_field(json_wtr, "cgroup", fpath);
430                 jsonw_name(json_wtr, "programs");
431                 jsonw_start_array(json_wtr);
432         } else {
433                 printf("%s\n", fpath);
434         }
435 
436         btf_vmlinux = libbpf_find_kernel_btf();
437         for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++)
438                 show_bpf_progs(cgroup_fd, type, ftw->level);
439 
440         if (errno == EINVAL)
441                 /* Last attach type does not support query.
442                  * Do not report an error for this, especially because batch
443                  * mode would stop processing commands.
444                  */
445                 errno = 0;
446 
447         if (json_output) {
448                 jsonw_end_array(json_wtr);
449                 jsonw_end_object(json_wtr);
450         }
451 
452         close(cgroup_fd);
453 
454         return 0;
455 }
456 
457 static char *find_cgroup_root(void)
458 {
459         struct mntent *mnt;
460         FILE *f;
461 
462         f = fopen("/proc/mounts", "r");
463         if (f == NULL)
464                 return NULL;
465 
466         while ((mnt = getmntent(f))) {
467                 if (strcmp(mnt->mnt_type, "cgroup2") == 0) {
468                         fclose(f);
469                         return strdup(mnt->mnt_dir);
470                 }
471         }
472 
473         fclose(f);
474         return NULL;
475 }
476 
477 static int do_show_tree(int argc, char **argv)
478 {
479         char *cgroup_root, *cgroup_alloced = NULL;
480         int ret;
481 
482         query_flags = 0;
483 
484         if (!argc) {
485                 cgroup_alloced = find_cgroup_root();
486                 if (!cgroup_alloced) {
487                         p_err("cgroup v2 isn't mounted");
488                         return -1;
489                 }
490                 cgroup_root = cgroup_alloced;
491         } else {
492                 cgroup_root = GET_ARG();
493 
494                 while (argc) {
495                         if (is_prefix(*argv, "effective")) {
496                                 if (query_flags & BPF_F_QUERY_EFFECTIVE) {
497                                         p_err("duplicated argument: %s", *argv);
498                                         return -1;
499                                 }
500                                 query_flags |= BPF_F_QUERY_EFFECTIVE;
501                                 NEXT_ARG();
502                         } else {
503                                 p_err("expected no more arguments, 'effective', got: '%s'?",
504                                       *argv);
505                                 return -1;
506                         }
507                 }
508         }
509 
510         if (json_output)
511                 jsonw_start_array(json_wtr);
512         else if (query_flags & BPF_F_QUERY_EFFECTIVE)
513                 printf("%s\n"
514                        "%-8s %-15s %-15s\n",
515                        "CgroupPath",
516                        "ID", "AttachType", "Name");
517         else
518                 printf("%s\n"
519                        "%-8s %-15s %-15s %-15s\n",
520                        "CgroupPath",
521                        "ID", "AttachType", "AttachFlags", "Name");
522 
523         switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) {
524         case NFTW_ERR:
525                 p_err("can't iterate over %s: %s", cgroup_root,
526                       strerror(errno));
527                 ret = -1;
528                 break;
529         case SHOW_TREE_FN_ERR:
530                 ret = -1;
531                 break;
532         default:
533                 ret = 0;
534         }
535 
536         if (json_output)
537                 jsonw_end_array(json_wtr);
538 
539         free(cgroup_alloced);
540 
541         return ret;
542 }
543 
544 static int do_attach(int argc, char **argv)
545 {
546         enum bpf_attach_type attach_type;
547         int cgroup_fd, prog_fd;
548         int attach_flags = 0;
549         int ret = -1;
550         int i;
551 
552         if (argc < 4) {
553                 p_err("too few parameters for cgroup attach");
554                 goto exit;
555         }
556 
557         cgroup_fd = open(argv[0], O_RDONLY);
558         if (cgroup_fd < 0) {
559                 p_err("can't open cgroup %s", argv[0]);
560                 goto exit;
561         }
562 
563         attach_type = parse_attach_type(argv[1]);
564         if (attach_type == __MAX_BPF_ATTACH_TYPE) {
565                 p_err("invalid attach type");
566                 goto exit_cgroup;
567         }
568 
569         argc -= 2;
570         argv = &argv[2];
571         prog_fd = prog_parse_fd(&argc, &argv);
572         if (prog_fd < 0)
573                 goto exit_cgroup;
574 
575         for (i = 0; i < argc; i++) {
576                 if (is_prefix(argv[i], "multi")) {
577                         attach_flags |= BPF_F_ALLOW_MULTI;
578                 } else if (is_prefix(argv[i], "override")) {
579                         attach_flags |= BPF_F_ALLOW_OVERRIDE;
580                 } else {
581                         p_err("unknown option: %s", argv[i]);
582                         goto exit_cgroup;
583                 }
584         }
585 
586         if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
587                 p_err("failed to attach program");
588                 goto exit_prog;
589         }
590 
591         if (json_output)
592                 jsonw_null(json_wtr);
593 
594         ret = 0;
595 
596 exit_prog:
597         close(prog_fd);
598 exit_cgroup:
599         close(cgroup_fd);
600 exit:
601         return ret;
602 }
603 
604 static int do_detach(int argc, char **argv)
605 {
606         enum bpf_attach_type attach_type;
607         int prog_fd, cgroup_fd;
608         int ret = -1;
609 
610         if (argc < 4) {
611                 p_err("too few parameters for cgroup detach");
612                 goto exit;
613         }
614 
615         cgroup_fd = open(argv[0], O_RDONLY);
616         if (cgroup_fd < 0) {
617                 p_err("can't open cgroup %s", argv[0]);
618                 goto exit;
619         }
620 
621         attach_type = parse_attach_type(argv[1]);
622         if (attach_type == __MAX_BPF_ATTACH_TYPE) {
623                 p_err("invalid attach type");
624                 goto exit_cgroup;
625         }
626 
627         argc -= 2;
628         argv = &argv[2];
629         prog_fd = prog_parse_fd(&argc, &argv);
630         if (prog_fd < 0)
631                 goto exit_cgroup;
632 
633         if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
634                 p_err("failed to detach program");
635                 goto exit_prog;
636         }
637 
638         if (json_output)
639                 jsonw_null(json_wtr);
640 
641         ret = 0;
642 
643 exit_prog:
644         close(prog_fd);
645 exit_cgroup:
646         close(cgroup_fd);
647 exit:
648         return ret;
649 }
650 
651 static int do_help(int argc, char **argv)
652 {
653         if (json_output) {
654                 jsonw_null(json_wtr);
655                 return 0;
656         }
657 
658         fprintf(stderr,
659                 "Usage: %1$s %2$s { show | list } CGROUP [**effective**]\n"
660                 "       %1$s %2$s tree [CGROUP_ROOT] [**effective**]\n"
661                 "       %1$s %2$s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
662                 "       %1$s %2$s detach CGROUP ATTACH_TYPE PROG\n"
663                 "       %1$s %2$s help\n"
664                 "\n"
665                 HELP_SPEC_ATTACH_TYPES "\n"
666                 "       " HELP_SPEC_ATTACH_FLAGS "\n"
667                 "       " HELP_SPEC_PROGRAM "\n"
668                 "       " HELP_SPEC_OPTIONS " |\n"
669                 "                    {-f|--bpffs} }\n"
670                 "",
671                 bin_name, argv[-2]);
672 
673         return 0;
674 }
675 
676 static const struct cmd cmds[] = {
677         { "show",       do_show },
678         { "list",       do_show },
679         { "tree",       do_show_tree },
680         { "attach",     do_attach },
681         { "detach",     do_detach },
682         { "help",       do_help },
683         { 0 }
684 };
685 
686 int do_cgroup(int argc, char **argv)
687 {
688         return cmd_select(cmds, argc, argv, do_help);
689 }
690 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php