Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 22static 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
 31static 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
 44static 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
 80static 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
120static 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);
161exit:
162	return ret;
163}
164
165static 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
217exit_prog:
218	close(prog_fd);
219exit_cgroup:
220	close(cgroup_fd);
221exit:
222	return ret;
223}
224
225static 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
264exit_prog:
265	close(prog_fd);
266exit_cgroup:
267	close(cgroup_fd);
268exit:
269	return ret;
270}
271
272static 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
296static 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
305int do_cgroup(int argc, char **argv)
306{
307	return cmd_select(cmds, argc, argv, do_help);
308}