xref: /openbmc/linux/tools/bpf/bpftool/cgroup.c (revision 5ccda64d)
15ccda64dSRoman Gushchin // SPDX-License-Identifier: GPL-2.0+
25ccda64dSRoman Gushchin // Copyright (C) 2017 Facebook
35ccda64dSRoman Gushchin // Author: Roman Gushchin <guro@fb.com>
45ccda64dSRoman Gushchin 
55ccda64dSRoman Gushchin #include <fcntl.h>
65ccda64dSRoman Gushchin #include <stdlib.h>
75ccda64dSRoman Gushchin #include <string.h>
85ccda64dSRoman Gushchin #include <sys/stat.h>
95ccda64dSRoman Gushchin #include <sys/types.h>
105ccda64dSRoman Gushchin #include <unistd.h>
115ccda64dSRoman Gushchin 
125ccda64dSRoman Gushchin #include <bpf.h>
135ccda64dSRoman Gushchin 
145ccda64dSRoman Gushchin #include "main.h"
155ccda64dSRoman Gushchin 
165ccda64dSRoman Gushchin #define HELP_SPEC_ATTACH_FLAGS						\
175ccda64dSRoman Gushchin 	"ATTACH_FLAGS := { multi | override }"
185ccda64dSRoman Gushchin 
195ccda64dSRoman Gushchin #define HELP_SPEC_ATTACH_TYPES						\
205ccda64dSRoman Gushchin 	"ATTACH_TYPE := { ingress | egress | sock_create | sock_ops | device }"
215ccda64dSRoman Gushchin 
225ccda64dSRoman Gushchin static const char * const attach_type_strings[] = {
235ccda64dSRoman Gushchin 	[BPF_CGROUP_INET_INGRESS] = "ingress",
245ccda64dSRoman Gushchin 	[BPF_CGROUP_INET_EGRESS] = "egress",
255ccda64dSRoman Gushchin 	[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
265ccda64dSRoman Gushchin 	[BPF_CGROUP_SOCK_OPS] = "sock_ops",
275ccda64dSRoman Gushchin 	[BPF_CGROUP_DEVICE] = "device",
285ccda64dSRoman Gushchin 	[__MAX_BPF_ATTACH_TYPE] = NULL,
295ccda64dSRoman Gushchin };
305ccda64dSRoman Gushchin 
315ccda64dSRoman Gushchin static enum bpf_attach_type parse_attach_type(const char *str)
325ccda64dSRoman Gushchin {
335ccda64dSRoman Gushchin 	enum bpf_attach_type type;
345ccda64dSRoman Gushchin 
355ccda64dSRoman Gushchin 	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
365ccda64dSRoman Gushchin 		if (attach_type_strings[type] &&
375ccda64dSRoman Gushchin 		    is_prefix(str, attach_type_strings[type]))
385ccda64dSRoman Gushchin 			return type;
395ccda64dSRoman Gushchin 	}
405ccda64dSRoman Gushchin 
415ccda64dSRoman Gushchin 	return __MAX_BPF_ATTACH_TYPE;
425ccda64dSRoman Gushchin }
435ccda64dSRoman Gushchin 
445ccda64dSRoman Gushchin static int list_bpf_prog(int id, const char *attach_type_str,
455ccda64dSRoman Gushchin 			 const char *attach_flags_str)
465ccda64dSRoman Gushchin {
475ccda64dSRoman Gushchin 	struct bpf_prog_info info = {};
485ccda64dSRoman Gushchin 	__u32 info_len = sizeof(info);
495ccda64dSRoman Gushchin 	int prog_fd;
505ccda64dSRoman Gushchin 
515ccda64dSRoman Gushchin 	prog_fd = bpf_prog_get_fd_by_id(id);
525ccda64dSRoman Gushchin 	if (prog_fd < 0)
535ccda64dSRoman Gushchin 		return -1;
545ccda64dSRoman Gushchin 
555ccda64dSRoman Gushchin 	if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
565ccda64dSRoman Gushchin 		close(prog_fd);
575ccda64dSRoman Gushchin 		return -1;
585ccda64dSRoman Gushchin 	}
595ccda64dSRoman Gushchin 
605ccda64dSRoman Gushchin 	if (json_output) {
615ccda64dSRoman Gushchin 		jsonw_start_object(json_wtr);
625ccda64dSRoman Gushchin 		jsonw_uint_field(json_wtr, "id", info.id);
635ccda64dSRoman Gushchin 		jsonw_string_field(json_wtr, "attach_type",
645ccda64dSRoman Gushchin 				   attach_type_str);
655ccda64dSRoman Gushchin 		jsonw_string_field(json_wtr, "attach_flags",
665ccda64dSRoman Gushchin 				   attach_flags_str);
675ccda64dSRoman Gushchin 		jsonw_string_field(json_wtr, "name", info.name);
685ccda64dSRoman Gushchin 		jsonw_end_object(json_wtr);
695ccda64dSRoman Gushchin 	} else {
705ccda64dSRoman Gushchin 		printf("%-8u %-15s %-15s %-15s\n", info.id,
715ccda64dSRoman Gushchin 		       attach_type_str,
725ccda64dSRoman Gushchin 		       attach_flags_str,
735ccda64dSRoman Gushchin 		       info.name);
745ccda64dSRoman Gushchin 	}
755ccda64dSRoman Gushchin 
765ccda64dSRoman Gushchin 	close(prog_fd);
775ccda64dSRoman Gushchin 	return 0;
785ccda64dSRoman Gushchin }
795ccda64dSRoman Gushchin 
805ccda64dSRoman Gushchin static int list_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
815ccda64dSRoman Gushchin {
825ccda64dSRoman Gushchin 	__u32 prog_ids[1024] = {0};
835ccda64dSRoman Gushchin 	char *attach_flags_str;
845ccda64dSRoman Gushchin 	__u32 prog_cnt, iter;
855ccda64dSRoman Gushchin 	__u32 attach_flags;
865ccda64dSRoman Gushchin 	char buf[32];
875ccda64dSRoman Gushchin 	int ret;
885ccda64dSRoman Gushchin 
895ccda64dSRoman Gushchin 	prog_cnt = ARRAY_SIZE(prog_ids);
905ccda64dSRoman Gushchin 	ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids,
915ccda64dSRoman Gushchin 			     &prog_cnt);
925ccda64dSRoman Gushchin 	if (ret)
935ccda64dSRoman Gushchin 		return ret;
945ccda64dSRoman Gushchin 
955ccda64dSRoman Gushchin 	if (prog_cnt == 0)
965ccda64dSRoman Gushchin 		return 0;
975ccda64dSRoman Gushchin 
985ccda64dSRoman Gushchin 	switch (attach_flags) {
995ccda64dSRoman Gushchin 	case BPF_F_ALLOW_MULTI:
1005ccda64dSRoman Gushchin 		attach_flags_str = "multi";
1015ccda64dSRoman Gushchin 		break;
1025ccda64dSRoman Gushchin 	case BPF_F_ALLOW_OVERRIDE:
1035ccda64dSRoman Gushchin 		attach_flags_str = "override";
1045ccda64dSRoman Gushchin 		break;
1055ccda64dSRoman Gushchin 	case 0:
1065ccda64dSRoman Gushchin 		attach_flags_str = "";
1075ccda64dSRoman Gushchin 		break;
1085ccda64dSRoman Gushchin 	default:
1095ccda64dSRoman Gushchin 		snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
1105ccda64dSRoman Gushchin 		attach_flags_str = buf;
1115ccda64dSRoman Gushchin 	}
1125ccda64dSRoman Gushchin 
1135ccda64dSRoman Gushchin 	for (iter = 0; iter < prog_cnt; iter++)
1145ccda64dSRoman Gushchin 		list_bpf_prog(prog_ids[iter], attach_type_strings[type],
1155ccda64dSRoman Gushchin 			      attach_flags_str);
1165ccda64dSRoman Gushchin 
1175ccda64dSRoman Gushchin 	return 0;
1185ccda64dSRoman Gushchin }
1195ccda64dSRoman Gushchin 
1205ccda64dSRoman Gushchin static int do_list(int argc, char **argv)
1215ccda64dSRoman Gushchin {
1225ccda64dSRoman Gushchin 	enum bpf_attach_type type;
1235ccda64dSRoman Gushchin 	int cgroup_fd;
1245ccda64dSRoman Gushchin 	int ret = -1;
1255ccda64dSRoman Gushchin 
1265ccda64dSRoman Gushchin 	if (argc < 1) {
1275ccda64dSRoman Gushchin 		p_err("too few parameters for cgroup list\n");
1285ccda64dSRoman Gushchin 		goto exit;
1295ccda64dSRoman Gushchin 	} else if (argc > 1) {
1305ccda64dSRoman Gushchin 		p_err("too many parameters for cgroup list\n");
1315ccda64dSRoman Gushchin 		goto exit;
1325ccda64dSRoman Gushchin 	}
1335ccda64dSRoman Gushchin 
1345ccda64dSRoman Gushchin 	cgroup_fd = open(argv[0], O_RDONLY);
1355ccda64dSRoman Gushchin 	if (cgroup_fd < 0) {
1365ccda64dSRoman Gushchin 		p_err("can't open cgroup %s\n", argv[1]);
1375ccda64dSRoman Gushchin 		goto exit;
1385ccda64dSRoman Gushchin 	}
1395ccda64dSRoman Gushchin 
1405ccda64dSRoman Gushchin 	if (json_output)
1415ccda64dSRoman Gushchin 		jsonw_start_array(json_wtr);
1425ccda64dSRoman Gushchin 	else
1435ccda64dSRoman Gushchin 		printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
1445ccda64dSRoman Gushchin 		       "AttachFlags", "Name");
1455ccda64dSRoman Gushchin 
1465ccda64dSRoman Gushchin 	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
1475ccda64dSRoman Gushchin 		/*
1485ccda64dSRoman Gushchin 		 * Not all attach types may be supported, so it's expected,
1495ccda64dSRoman Gushchin 		 * that some requests will fail.
1505ccda64dSRoman Gushchin 		 * If we were able to get the list for at least one
1515ccda64dSRoman Gushchin 		 * attach type, let's return 0.
1525ccda64dSRoman Gushchin 		 */
1535ccda64dSRoman Gushchin 		if (list_attached_bpf_progs(cgroup_fd, type) == 0)
1545ccda64dSRoman Gushchin 			ret = 0;
1555ccda64dSRoman Gushchin 	}
1565ccda64dSRoman Gushchin 
1575ccda64dSRoman Gushchin 	if (json_output)
1585ccda64dSRoman Gushchin 		jsonw_end_array(json_wtr);
1595ccda64dSRoman Gushchin 
1605ccda64dSRoman Gushchin 	close(cgroup_fd);
1615ccda64dSRoman Gushchin exit:
1625ccda64dSRoman Gushchin 	return ret;
1635ccda64dSRoman Gushchin }
1645ccda64dSRoman Gushchin 
1655ccda64dSRoman Gushchin static int do_attach(int argc, char **argv)
1665ccda64dSRoman Gushchin {
1675ccda64dSRoman Gushchin 	enum bpf_attach_type attach_type;
1685ccda64dSRoman Gushchin 	int cgroup_fd, prog_fd;
1695ccda64dSRoman Gushchin 	int attach_flags = 0;
1705ccda64dSRoman Gushchin 	int ret = -1;
1715ccda64dSRoman Gushchin 	int i;
1725ccda64dSRoman Gushchin 
1735ccda64dSRoman Gushchin 	if (argc < 4) {
1745ccda64dSRoman Gushchin 		p_err("too few parameters for cgroup attach\n");
1755ccda64dSRoman Gushchin 		goto exit;
1765ccda64dSRoman Gushchin 	}
1775ccda64dSRoman Gushchin 
1785ccda64dSRoman Gushchin 	cgroup_fd = open(argv[0], O_RDONLY);
1795ccda64dSRoman Gushchin 	if (cgroup_fd < 0) {
1805ccda64dSRoman Gushchin 		p_err("can't open cgroup %s\n", argv[1]);
1815ccda64dSRoman Gushchin 		goto exit;
1825ccda64dSRoman Gushchin 	}
1835ccda64dSRoman Gushchin 
1845ccda64dSRoman Gushchin 	attach_type = parse_attach_type(argv[1]);
1855ccda64dSRoman Gushchin 	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
1865ccda64dSRoman Gushchin 		p_err("invalid attach type\n");
1875ccda64dSRoman Gushchin 		goto exit_cgroup;
1885ccda64dSRoman Gushchin 	}
1895ccda64dSRoman Gushchin 
1905ccda64dSRoman Gushchin 	argc -= 2;
1915ccda64dSRoman Gushchin 	argv = &argv[2];
1925ccda64dSRoman Gushchin 	prog_fd = prog_parse_fd(&argc, &argv);
1935ccda64dSRoman Gushchin 	if (prog_fd < 0)
1945ccda64dSRoman Gushchin 		goto exit_cgroup;
1955ccda64dSRoman Gushchin 
1965ccda64dSRoman Gushchin 	for (i = 0; i < argc; i++) {
1975ccda64dSRoman Gushchin 		if (is_prefix(argv[i], "multi")) {
1985ccda64dSRoman Gushchin 			attach_flags |= BPF_F_ALLOW_MULTI;
1995ccda64dSRoman Gushchin 		} else if (is_prefix(argv[i], "override")) {
2005ccda64dSRoman Gushchin 			attach_flags |= BPF_F_ALLOW_OVERRIDE;
2015ccda64dSRoman Gushchin 		} else {
2025ccda64dSRoman Gushchin 			p_err("unknown option: %s\n", argv[i]);
2035ccda64dSRoman Gushchin 			goto exit_cgroup;
2045ccda64dSRoman Gushchin 		}
2055ccda64dSRoman Gushchin 	}
2065ccda64dSRoman Gushchin 
2075ccda64dSRoman Gushchin 	if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
2085ccda64dSRoman Gushchin 		p_err("failed to attach program");
2095ccda64dSRoman Gushchin 		goto exit_prog;
2105ccda64dSRoman Gushchin 	}
2115ccda64dSRoman Gushchin 
2125ccda64dSRoman Gushchin 	if (json_output)
2135ccda64dSRoman Gushchin 		jsonw_null(json_wtr);
2145ccda64dSRoman Gushchin 
2155ccda64dSRoman Gushchin 	ret = 0;
2165ccda64dSRoman Gushchin 
2175ccda64dSRoman Gushchin exit_prog:
2185ccda64dSRoman Gushchin 	close(prog_fd);
2195ccda64dSRoman Gushchin exit_cgroup:
2205ccda64dSRoman Gushchin 	close(cgroup_fd);
2215ccda64dSRoman Gushchin exit:
2225ccda64dSRoman Gushchin 	return ret;
2235ccda64dSRoman Gushchin }
2245ccda64dSRoman Gushchin 
2255ccda64dSRoman Gushchin static int do_detach(int argc, char **argv)
2265ccda64dSRoman Gushchin {
2275ccda64dSRoman Gushchin 	enum bpf_attach_type attach_type;
2285ccda64dSRoman Gushchin 	int prog_fd, cgroup_fd;
2295ccda64dSRoman Gushchin 	int ret = -1;
2305ccda64dSRoman Gushchin 
2315ccda64dSRoman Gushchin 	if (argc < 4) {
2325ccda64dSRoman Gushchin 		p_err("too few parameters for cgroup detach\n");
2335ccda64dSRoman Gushchin 		goto exit;
2345ccda64dSRoman Gushchin 	}
2355ccda64dSRoman Gushchin 
2365ccda64dSRoman Gushchin 	cgroup_fd = open(argv[0], O_RDONLY);
2375ccda64dSRoman Gushchin 	if (cgroup_fd < 0) {
2385ccda64dSRoman Gushchin 		p_err("can't open cgroup %s\n", argv[1]);
2395ccda64dSRoman Gushchin 		goto exit;
2405ccda64dSRoman Gushchin 	}
2415ccda64dSRoman Gushchin 
2425ccda64dSRoman Gushchin 	attach_type = parse_attach_type(argv[1]);
2435ccda64dSRoman Gushchin 	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
2445ccda64dSRoman Gushchin 		p_err("invalid attach type");
2455ccda64dSRoman Gushchin 		goto exit_cgroup;
2465ccda64dSRoman Gushchin 	}
2475ccda64dSRoman Gushchin 
2485ccda64dSRoman Gushchin 	argc -= 2;
2495ccda64dSRoman Gushchin 	argv = &argv[2];
2505ccda64dSRoman Gushchin 	prog_fd = prog_parse_fd(&argc, &argv);
2515ccda64dSRoman Gushchin 	if (prog_fd < 0)
2525ccda64dSRoman Gushchin 		goto exit_cgroup;
2535ccda64dSRoman Gushchin 
2545ccda64dSRoman Gushchin 	if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
2555ccda64dSRoman Gushchin 		p_err("failed to detach program");
2565ccda64dSRoman Gushchin 		goto exit_prog;
2575ccda64dSRoman Gushchin 	}
2585ccda64dSRoman Gushchin 
2595ccda64dSRoman Gushchin 	if (json_output)
2605ccda64dSRoman Gushchin 		jsonw_null(json_wtr);
2615ccda64dSRoman Gushchin 
2625ccda64dSRoman Gushchin 	ret = 0;
2635ccda64dSRoman Gushchin 
2645ccda64dSRoman Gushchin exit_prog:
2655ccda64dSRoman Gushchin 	close(prog_fd);
2665ccda64dSRoman Gushchin exit_cgroup:
2675ccda64dSRoman Gushchin 	close(cgroup_fd);
2685ccda64dSRoman Gushchin exit:
2695ccda64dSRoman Gushchin 	return ret;
2705ccda64dSRoman Gushchin }
2715ccda64dSRoman Gushchin 
2725ccda64dSRoman Gushchin static int do_help(int argc, char **argv)
2735ccda64dSRoman Gushchin {
2745ccda64dSRoman Gushchin 	if (json_output) {
2755ccda64dSRoman Gushchin 		jsonw_null(json_wtr);
2765ccda64dSRoman Gushchin 		return 0;
2775ccda64dSRoman Gushchin 	}
2785ccda64dSRoman Gushchin 
2795ccda64dSRoman Gushchin 	fprintf(stderr,
2805ccda64dSRoman Gushchin 		"Usage: %s %s list CGROUP\n"
2815ccda64dSRoman Gushchin 		"       %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
2825ccda64dSRoman Gushchin 		"       %s %s detach CGROUP ATTACH_TYPE PROG\n"
2835ccda64dSRoman Gushchin 		"       %s %s help\n"
2845ccda64dSRoman Gushchin 		"\n"
2855ccda64dSRoman Gushchin 		"       " HELP_SPEC_ATTACH_TYPES "\n"
2865ccda64dSRoman Gushchin 		"       " HELP_SPEC_ATTACH_FLAGS "\n"
2875ccda64dSRoman Gushchin 		"       " HELP_SPEC_PROGRAM "\n"
2885ccda64dSRoman Gushchin 		"       " HELP_SPEC_OPTIONS "\n"
2895ccda64dSRoman Gushchin 		"",
2905ccda64dSRoman Gushchin 		bin_name, argv[-2], bin_name, argv[-2],
2915ccda64dSRoman Gushchin 		bin_name, argv[-2], bin_name, argv[-2]);
2925ccda64dSRoman Gushchin 
2935ccda64dSRoman Gushchin 	return 0;
2945ccda64dSRoman Gushchin }
2955ccda64dSRoman Gushchin 
2965ccda64dSRoman Gushchin static const struct cmd cmds[] = {
2975ccda64dSRoman Gushchin 	{ "list",	do_list },
2985ccda64dSRoman Gushchin 	{ "attach",	do_attach },
2995ccda64dSRoman Gushchin 	{ "detach",	do_detach },
3005ccda64dSRoman Gushchin 	{ "help",	do_help },
3015ccda64dSRoman Gushchin 	{ 0 }
3025ccda64dSRoman Gushchin };
3035ccda64dSRoman Gushchin 
3045ccda64dSRoman Gushchin int do_cgroup(int argc, char **argv)
3055ccda64dSRoman Gushchin {
3065ccda64dSRoman Gushchin 	return cmd_select(cmds, argc, argv, do_help);
3075ccda64dSRoman Gushchin }
308