Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
c2779f8
Documentation
LICENSES
arch
block
certs
crypto
drivers
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
accounting
arch
bootconfig
bpf
bpftool
Documentation
bash-completion
skeleton
.gitignore
Makefile
btf.c
btf_dumper.c
cfg.c
cfg.h
cgroup.c
common.c
feature.c
gen.c
iter.c
jit_disasm.c
json_writer.c
json_writer.h
link.c
main.c
main.h
map.c
map_perf_ring.c
net.c
netlink_dumper.c
netlink_dumper.h
perf.c
pids.c
prog.c
struct_ops.c
tracelog.c
xlated_dumper.c
xlated_dumper.h
resolve_btfids
runqslower
.gitignore
Makefile
Makefile.helpers
bpf_asm.c
bpf_dbg.c
bpf_exp.l
bpf_exp.y
bpf_jit_disasm.c
build
cgroup
debugging
edid
firewire
firmware
gpio
hv
iio
include
io_uring
kvm
laptop
leds
lib
memory-model
objtool
pci
pcmcia
perf
power
scripts
spi
testing
thermal
time
usb
virtio
vm
wmi
Makefile
usr
virt
.clang-format
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
tools
/
bpf
/
bpftool
/
cgroup.c
Blame
Blame
Latest commit
History
History
524 lines (440 loc) · 11 KB
Breadcrumbs
linux
/
tools
/
bpf
/
bpftool
/
cgroup.c
Top
File metadata and controls
Code
Blame
524 lines (440 loc) · 11 KB
Raw
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) // 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> #include <sys/types.h> #include <unistd.h> #include <bpf/bpf.h> #include "main.h" #define HELP_SPEC_ATTACH_FLAGS \ "ATTACH_FLAGS := { multi | override }" #define HELP_SPEC_ATTACH_TYPES \ " ATTACH_TYPE := { ingress | egress | sock_create |\n" \ " sock_ops | device | bind4 | bind6 |\n" \ " post_bind4 | post_bind6 | connect4 |\n" \ " connect6 | getpeername4 | getpeername6 |\n" \ " getsockname4 | getsockname6 | sendmsg4 |\n" \ " sendmsg6 | recvmsg4 | recvmsg6 |\n" \ " sysctl | getsockopt | setsockopt |\n" \ " sock_release }" static unsigned int query_flags; static enum bpf_attach_type parse_attach_type(const char *str) { enum bpf_attach_type type; for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { if (attach_type_name[type] && is_prefix(str, attach_type_name[type])) return type; } return __MAX_BPF_ATTACH_TYPE; } static int show_bpf_prog(int id, enum bpf_attach_type attach_type, const char *attach_flags_str, int level) { struct bpf_prog_info info = {}; __u32 info_len = sizeof(info); int prog_fd; prog_fd = bpf_prog_get_fd_by_id(id); if (prog_fd < 0) return -1; if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { close(prog_fd); return -1; } if (json_output) { jsonw_start_object(json_wtr); jsonw_uint_field(json_wtr, "id", info.id); if (attach_type < ARRAY_SIZE(attach_type_name)) jsonw_string_field(json_wtr, "attach_type", attach_type_name[attach_type]); else jsonw_uint_field(json_wtr, "attach_type", attach_type); jsonw_string_field(json_wtr, "attach_flags", attach_flags_str); jsonw_string_field(json_wtr, "name", info.name); jsonw_end_object(json_wtr); } else { printf("%s%-8u ", level ? " " : "", info.id); if (attach_type < ARRAY_SIZE(attach_type_name)) printf("%-15s", attach_type_name[attach_type]); else printf("type %-10u", attach_type); printf(" %-15s %-15s\n", attach_flags_str, info.name); } close(prog_fd); return 0; } 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, query_flags, NULL, NULL, &prog_cnt); if (ret) return -1; return prog_cnt; } static int cgroup_has_attached_progs(int cgroup_fd) { enum bpf_attach_type type; bool no_prog = true; for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { int count = count_attached_bpf_progs(cgroup_fd, type); if (count < 0 && errno != EINVAL) return -1; if (count > 0) { no_prog = false; break; } } return no_prog ? 0 : 1; } static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, int level) { const char *attach_flags_str; __u32 prog_ids[1024] = {0}; __u32 prog_cnt, iter; __u32 attach_flags; char buf[32]; int ret; prog_cnt = ARRAY_SIZE(prog_ids); ret = bpf_prog_query(cgroup_fd, type, query_flags, &attach_flags, prog_ids, &prog_cnt); if (ret) return ret; if (prog_cnt == 0) return 0; switch (attach_flags) { case BPF_F_ALLOW_MULTI: attach_flags_str = "multi"; break; case BPF_F_ALLOW_OVERRIDE: attach_flags_str = "override"; break; case 0: attach_flags_str = ""; break; default: snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags); attach_flags_str = buf; } for (iter = 0; iter < prog_cnt; iter++) show_bpf_prog(prog_ids[iter], type, attach_flags_str, level); return 0; } static int do_show(int argc, char **argv) { enum bpf_attach_type type; int has_attached_progs; const char *path; int cgroup_fd; int ret = -1; query_flags = 0; if (!REQ_ARGS(1)) return -1; path = GET_ARG(); while (argc) { if (is_prefix(*argv, "effective")) { if (query_flags & BPF_F_QUERY_EFFECTIVE) { p_err("duplicated argument: %s", *argv); return -1; } query_flags |= BPF_F_QUERY_EFFECTIVE; NEXT_ARG(); } else { p_err("expected no more arguments, 'effective', got: '%s'?", *argv); return -1; } } cgroup_fd = open(path, O_RDONLY); if (cgroup_fd < 0) { p_err("can't open cgroup %s", path); goto exit; } has_attached_progs = cgroup_has_attached_progs(cgroup_fd); if (has_attached_progs < 0) { p_err("can't query bpf programs attached to %s: %s", path, strerror(errno)); goto exit_cgroup; } else if (!has_attached_progs) { ret = 0; goto exit_cgroup; } if (json_output) jsonw_start_array(json_wtr); else printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType", "AttachFlags", "Name"); for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { /* * Not all attach types may be supported, so it's expected, * that some requests will fail. * 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) == 0) ret = 0; } if (json_output) jsonw_end_array(json_wtr); exit_cgroup: close(cgroup_fd); exit: return ret; } /* * To distinguish nftw() errors and do_show_tree_fn() errors * and avoid duplicating error messages, let's return -2 * from do_show_tree_fn() in case of error. */ #define NFTW_ERR -1 #define SHOW_TREE_FN_ERR -2 static int do_show_tree_fn(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftw) { enum bpf_attach_type type; int has_attached_progs; 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 SHOW_TREE_FN_ERR; } has_attached_progs = cgroup_has_attached_progs(cgroup_fd); if (has_attached_progs < 0) { p_err("can't query bpf programs attached to %s: %s", fpath, strerror(errno)); close(cgroup_fd); return SHOW_TREE_FN_ERR; } else if (!has_attached_progs) { 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 (errno == EINVAL) /* Last attach type does not support query. * Do not report an error for this, especially because batch * mode would stop processing commands. */ errno = 0; 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, *cgroup_alloced = NULL; int ret; query_flags = 0; if (!argc) { cgroup_alloced = find_cgroup_root(); if (!cgroup_alloced) { p_err("cgroup v2 isn't mounted"); return -1; } cgroup_root = cgroup_alloced; } else { cgroup_root = GET_ARG(); while (argc) { if (is_prefix(*argv, "effective")) { if (query_flags & BPF_F_QUERY_EFFECTIVE) { p_err("duplicated argument: %s", *argv); return -1; } query_flags |= BPF_F_QUERY_EFFECTIVE; NEXT_ARG(); } else { p_err("expected no more arguments, 'effective', got: '%s'?", *argv); return -1; } } } if (json_output) jsonw_start_array(json_wtr); else printf("%s\n" "%-8s %-15s %-15s %-15s\n", "CgroupPath", "ID", "AttachType", "AttachFlags", "Name"); switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) { case NFTW_ERR: p_err("can't iterate over %s: %s", cgroup_root, strerror(errno)); ret = -1; break; case SHOW_TREE_FN_ERR: ret = -1; break; default: ret = 0; } if (json_output) jsonw_end_array(json_wtr); free(cgroup_alloced); return ret; } static int do_attach(int argc, char **argv) { enum bpf_attach_type attach_type; int cgroup_fd, prog_fd; int attach_flags = 0; int ret = -1; int i; if (argc < 4) { p_err("too few parameters for cgroup attach"); goto exit; } cgroup_fd = open(argv[0], O_RDONLY); if (cgroup_fd < 0) { p_err("can't open cgroup %s", argv[0]); goto exit; } attach_type = parse_attach_type(argv[1]); if (attach_type == __MAX_BPF_ATTACH_TYPE) { p_err("invalid attach type"); goto exit_cgroup; } argc -= 2; argv = &argv[2]; prog_fd = prog_parse_fd(&argc, &argv); if (prog_fd < 0) goto exit_cgroup; for (i = 0; i < argc; i++) { if (is_prefix(argv[i], "multi")) { attach_flags |= BPF_F_ALLOW_MULTI; } else if (is_prefix(argv[i], "override")) { attach_flags |= BPF_F_ALLOW_OVERRIDE; } else { p_err("unknown option: %s", argv[i]); goto exit_cgroup; } } if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) { p_err("failed to attach program"); goto exit_prog; } if (json_output) jsonw_null(json_wtr); ret = 0; exit_prog: close(prog_fd); exit_cgroup: close(cgroup_fd); exit: return ret; } static int do_detach(int argc, char **argv) { enum bpf_attach_type attach_type; int prog_fd, cgroup_fd; int ret = -1; if (argc < 4) { p_err("too few parameters for cgroup detach"); goto exit; } cgroup_fd = open(argv[0], O_RDONLY); if (cgroup_fd < 0) { p_err("can't open cgroup %s", argv[0]); goto exit; } attach_type = parse_attach_type(argv[1]); if (attach_type == __MAX_BPF_ATTACH_TYPE) { p_err("invalid attach type"); goto exit_cgroup; } argc -= 2; argv = &argv[2]; prog_fd = prog_parse_fd(&argc, &argv); if (prog_fd < 0) goto exit_cgroup; if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) { p_err("failed to detach program"); goto exit_prog; } if (json_output) jsonw_null(json_wtr); ret = 0; exit_prog: close(prog_fd); exit_cgroup: close(cgroup_fd); exit: return ret; } static int do_help(int argc, char **argv) { if (json_output) { jsonw_null(json_wtr); return 0; } fprintf(stderr, "Usage: %1$s %2$s { show | list } CGROUP [**effective**]\n" " %1$s %2$s tree [CGROUP_ROOT] [**effective**]\n" " %1$s %2$s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" " %1$s %2$s detach CGROUP ATTACH_TYPE PROG\n" " %1$s %2$s help\n" "\n" HELP_SPEC_ATTACH_TYPES "\n" " " HELP_SPEC_ATTACH_FLAGS "\n" " " HELP_SPEC_PROGRAM "\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2]); return 0; } static const struct cmd cmds[] = { { "show", do_show }, { "list", do_show }, { "tree", do_show_tree }, { "attach", do_attach }, { "detach", do_detach }, { "help", do_help }, { 0 } }; int do_cgroup(int argc, char **argv) { return cmd_select(cmds, argc, argv, do_help); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
You can’t perform that action at this time.