xref: /linux/tools/bpf/bpftool/cgroup.c (revision 3ad0876554cafa368f574d4d408468510543e9ff)
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright (C) 2017 Facebook
3 // Author: Roman Gushchin <guro@fb.com>
4 
5 #include <fcntl.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 
12 #include <bpf.h>
13 
14 #include "main.h"
15 
16 #define HELP_SPEC_ATTACH_FLAGS						\
17 	"ATTACH_FLAGS := { multi | override }"
18 
19 #define HELP_SPEC_ATTACH_TYPES						\
20 	"ATTACH_TYPE := { ingress | egress | sock_create | sock_ops | device }"
21 
22 static const char * const attach_type_strings[] = {
23 	[BPF_CGROUP_INET_INGRESS] = "ingress",
24 	[BPF_CGROUP_INET_EGRESS] = "egress",
25 	[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
26 	[BPF_CGROUP_SOCK_OPS] = "sock_ops",
27 	[BPF_CGROUP_DEVICE] = "device",
28 	[__MAX_BPF_ATTACH_TYPE] = NULL,
29 };
30 
31 static enum bpf_attach_type parse_attach_type(const char *str)
32 {
33 	enum bpf_attach_type type;
34 
35 	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
36 		if (attach_type_strings[type] &&
37 		    is_prefix(str, attach_type_strings[type]))
38 			return type;
39 	}
40 
41 	return __MAX_BPF_ATTACH_TYPE;
42 }
43 
44 static int show_bpf_prog(int id, const char *attach_type_str,
45 			 const char *attach_flags_str)
46 {
47 	struct bpf_prog_info info = {};
48 	__u32 info_len = sizeof(info);
49 	int prog_fd;
50 
51 	prog_fd = bpf_prog_get_fd_by_id(id);
52 	if (prog_fd < 0)
53 		return -1;
54 
55 	if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
56 		close(prog_fd);
57 		return -1;
58 	}
59 
60 	if (json_output) {
61 		jsonw_start_object(json_wtr);
62 		jsonw_uint_field(json_wtr, "id", info.id);
63 		jsonw_string_field(json_wtr, "attach_type",
64 				   attach_type_str);
65 		jsonw_string_field(json_wtr, "attach_flags",
66 				   attach_flags_str);
67 		jsonw_string_field(json_wtr, "name", info.name);
68 		jsonw_end_object(json_wtr);
69 	} else {
70 		printf("%-8u %-15s %-15s %-15s\n", info.id,
71 		       attach_type_str,
72 		       attach_flags_str,
73 		       info.name);
74 	}
75 
76 	close(prog_fd);
77 	return 0;
78 }
79 
80 static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
81 {
82 	__u32 prog_ids[1024] = {0};
83 	char *attach_flags_str;
84 	__u32 prog_cnt, iter;
85 	__u32 attach_flags;
86 	char buf[32];
87 	int ret;
88 
89 	prog_cnt = ARRAY_SIZE(prog_ids);
90 	ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids,
91 			     &prog_cnt);
92 	if (ret)
93 		return ret;
94 
95 	if (prog_cnt == 0)
96 		return 0;
97 
98 	switch (attach_flags) {
99 	case BPF_F_ALLOW_MULTI:
100 		attach_flags_str = "multi";
101 		break;
102 	case BPF_F_ALLOW_OVERRIDE:
103 		attach_flags_str = "override";
104 		break;
105 	case 0:
106 		attach_flags_str = "";
107 		break;
108 	default:
109 		snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
110 		attach_flags_str = buf;
111 	}
112 
113 	for (iter = 0; iter < prog_cnt; iter++)
114 		show_bpf_prog(prog_ids[iter], attach_type_strings[type],
115 			      attach_flags_str);
116 
117 	return 0;
118 }
119 
120 static int do_show(int argc, char **argv)
121 {
122 	enum bpf_attach_type type;
123 	int cgroup_fd;
124 	int ret = -1;
125 
126 	if (argc < 1) {
127 		p_err("too few parameters for cgroup show");
128 		goto exit;
129 	} else if (argc > 1) {
130 		p_err("too many parameters for cgroup show");
131 		goto exit;
132 	}
133 
134 	cgroup_fd = open(argv[0], O_RDONLY);
135 	if (cgroup_fd < 0) {
136 		p_err("can't open cgroup %s", argv[1]);
137 		goto exit;
138 	}
139 
140 	if (json_output)
141 		jsonw_start_array(json_wtr);
142 	else
143 		printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
144 		       "AttachFlags", "Name");
145 
146 	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
147 		/*
148 		 * Not all attach types may be supported, so it's expected,
149 		 * that some requests will fail.
150 		 * If we were able to get the show for at least one
151 		 * attach type, let's return 0.
152 		 */
153 		if (show_attached_bpf_progs(cgroup_fd, type) == 0)
154 			ret = 0;
155 	}
156 
157 	if (json_output)
158 		jsonw_end_array(json_wtr);
159 
160 	close(cgroup_fd);
161 exit:
162 	return ret;
163 }
164 
165 static int do_attach(int argc, char **argv)
166 {
167 	enum bpf_attach_type attach_type;
168 	int cgroup_fd, prog_fd;
169 	int attach_flags = 0;
170 	int ret = -1;
171 	int i;
172 
173 	if (argc < 4) {
174 		p_err("too few parameters for cgroup attach");
175 		goto exit;
176 	}
177 
178 	cgroup_fd = open(argv[0], O_RDONLY);
179 	if (cgroup_fd < 0) {
180 		p_err("can't open cgroup %s", argv[1]);
181 		goto exit;
182 	}
183 
184 	attach_type = parse_attach_type(argv[1]);
185 	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
186 		p_err("invalid attach type");
187 		goto exit_cgroup;
188 	}
189 
190 	argc -= 2;
191 	argv = &argv[2];
192 	prog_fd = prog_parse_fd(&argc, &argv);
193 	if (prog_fd < 0)
194 		goto exit_cgroup;
195 
196 	for (i = 0; i < argc; i++) {
197 		if (is_prefix(argv[i], "multi")) {
198 			attach_flags |= BPF_F_ALLOW_MULTI;
199 		} else if (is_prefix(argv[i], "override")) {
200 			attach_flags |= BPF_F_ALLOW_OVERRIDE;
201 		} else {
202 			p_err("unknown option: %s", argv[i]);
203 			goto exit_cgroup;
204 		}
205 	}
206 
207 	if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
208 		p_err("failed to attach program");
209 		goto exit_prog;
210 	}
211 
212 	if (json_output)
213 		jsonw_null(json_wtr);
214 
215 	ret = 0;
216 
217 exit_prog:
218 	close(prog_fd);
219 exit_cgroup:
220 	close(cgroup_fd);
221 exit:
222 	return ret;
223 }
224 
225 static int do_detach(int argc, char **argv)
226 {
227 	enum bpf_attach_type attach_type;
228 	int prog_fd, cgroup_fd;
229 	int ret = -1;
230 
231 	if (argc < 4) {
232 		p_err("too few parameters for cgroup detach");
233 		goto exit;
234 	}
235 
236 	cgroup_fd = open(argv[0], O_RDONLY);
237 	if (cgroup_fd < 0) {
238 		p_err("can't open cgroup %s", argv[1]);
239 		goto exit;
240 	}
241 
242 	attach_type = parse_attach_type(argv[1]);
243 	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
244 		p_err("invalid attach type");
245 		goto exit_cgroup;
246 	}
247 
248 	argc -= 2;
249 	argv = &argv[2];
250 	prog_fd = prog_parse_fd(&argc, &argv);
251 	if (prog_fd < 0)
252 		goto exit_cgroup;
253 
254 	if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
255 		p_err("failed to detach program");
256 		goto exit_prog;
257 	}
258 
259 	if (json_output)
260 		jsonw_null(json_wtr);
261 
262 	ret = 0;
263 
264 exit_prog:
265 	close(prog_fd);
266 exit_cgroup:
267 	close(cgroup_fd);
268 exit:
269 	return ret;
270 }
271 
272 static int do_help(int argc, char **argv)
273 {
274 	if (json_output) {
275 		jsonw_null(json_wtr);
276 		return 0;
277 	}
278 
279 	fprintf(stderr,
280 		"Usage: %s %s { show | list } CGROUP\n"
281 		"       %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
282 		"       %s %s detach CGROUP ATTACH_TYPE PROG\n"
283 		"       %s %s help\n"
284 		"\n"
285 		"       " HELP_SPEC_ATTACH_TYPES "\n"
286 		"       " HELP_SPEC_ATTACH_FLAGS "\n"
287 		"       " HELP_SPEC_PROGRAM "\n"
288 		"       " HELP_SPEC_OPTIONS "\n"
289 		"",
290 		bin_name, argv[-2], bin_name, argv[-2],
291 		bin_name, argv[-2], bin_name, argv[-2]);
292 
293 	return 0;
294 }
295 
296 static const struct cmd cmds[] = {
297 	{ "show",	do_show },
298 	{ "list",	do_show },
299 	{ "attach",	do_attach },
300 	{ "detach",	do_detach },
301 	{ "help",	do_help },
302 	{ 0 }
303 };
304 
305 int do_cgroup(int argc, char **argv)
306 {
307 	return cmd_select(cmds, argc, argv, do_help);
308 }
309