xref: /openbmc/linux/tools/bpf/bpftool/cgroup.c (revision 13a370b9)
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						       \
20393de512SAndrey Ignatov 	"       ATTACH_TYPE := { ingress | egress | sock_create |\n"	       \
21393de512SAndrey Ignatov 	"                        sock_ops | device | bind4 | bind6 |\n"	       \
22393de512SAndrey Ignatov 	"                        post_bind4 | post_bind6 | connect4 |\n"       \
2313a370b9SAndrey Ignatov 	"                        connect6 | sendmsg4 | sendmsg6 }"
245ccda64dSRoman Gushchin 
255ccda64dSRoman Gushchin static const char * const attach_type_strings[] = {
265ccda64dSRoman Gushchin 	[BPF_CGROUP_INET_INGRESS] = "ingress",
275ccda64dSRoman Gushchin 	[BPF_CGROUP_INET_EGRESS] = "egress",
285ccda64dSRoman Gushchin 	[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
295ccda64dSRoman Gushchin 	[BPF_CGROUP_SOCK_OPS] = "sock_ops",
305ccda64dSRoman Gushchin 	[BPF_CGROUP_DEVICE] = "device",
31393de512SAndrey Ignatov 	[BPF_CGROUP_INET4_BIND] = "bind4",
32393de512SAndrey Ignatov 	[BPF_CGROUP_INET6_BIND] = "bind6",
33393de512SAndrey Ignatov 	[BPF_CGROUP_INET4_CONNECT] = "connect4",
34393de512SAndrey Ignatov 	[BPF_CGROUP_INET6_CONNECT] = "connect6",
35393de512SAndrey Ignatov 	[BPF_CGROUP_INET4_POST_BIND] = "post_bind4",
36393de512SAndrey Ignatov 	[BPF_CGROUP_INET6_POST_BIND] = "post_bind6",
3713a370b9SAndrey Ignatov 	[BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4",
3813a370b9SAndrey Ignatov 	[BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6",
395ccda64dSRoman Gushchin 	[__MAX_BPF_ATTACH_TYPE] = NULL,
405ccda64dSRoman Gushchin };
415ccda64dSRoman Gushchin 
425ccda64dSRoman Gushchin static enum bpf_attach_type parse_attach_type(const char *str)
435ccda64dSRoman Gushchin {
445ccda64dSRoman Gushchin 	enum bpf_attach_type type;
455ccda64dSRoman Gushchin 
465ccda64dSRoman Gushchin 	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
475ccda64dSRoman Gushchin 		if (attach_type_strings[type] &&
485ccda64dSRoman Gushchin 		    is_prefix(str, attach_type_strings[type]))
495ccda64dSRoman Gushchin 			return type;
505ccda64dSRoman Gushchin 	}
515ccda64dSRoman Gushchin 
525ccda64dSRoman Gushchin 	return __MAX_BPF_ATTACH_TYPE;
535ccda64dSRoman Gushchin }
545ccda64dSRoman Gushchin 
5565b875bcSJakub Kicinski static int show_bpf_prog(int id, const char *attach_type_str,
565ccda64dSRoman Gushchin 			 const char *attach_flags_str)
575ccda64dSRoman Gushchin {
585ccda64dSRoman Gushchin 	struct bpf_prog_info info = {};
595ccda64dSRoman Gushchin 	__u32 info_len = sizeof(info);
605ccda64dSRoman Gushchin 	int prog_fd;
615ccda64dSRoman Gushchin 
625ccda64dSRoman Gushchin 	prog_fd = bpf_prog_get_fd_by_id(id);
635ccda64dSRoman Gushchin 	if (prog_fd < 0)
645ccda64dSRoman Gushchin 		return -1;
655ccda64dSRoman Gushchin 
665ccda64dSRoman Gushchin 	if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
675ccda64dSRoman Gushchin 		close(prog_fd);
685ccda64dSRoman Gushchin 		return -1;
695ccda64dSRoman Gushchin 	}
705ccda64dSRoman Gushchin 
715ccda64dSRoman Gushchin 	if (json_output) {
725ccda64dSRoman Gushchin 		jsonw_start_object(json_wtr);
735ccda64dSRoman Gushchin 		jsonw_uint_field(json_wtr, "id", info.id);
745ccda64dSRoman Gushchin 		jsonw_string_field(json_wtr, "attach_type",
755ccda64dSRoman Gushchin 				   attach_type_str);
765ccda64dSRoman Gushchin 		jsonw_string_field(json_wtr, "attach_flags",
775ccda64dSRoman Gushchin 				   attach_flags_str);
785ccda64dSRoman Gushchin 		jsonw_string_field(json_wtr, "name", info.name);
795ccda64dSRoman Gushchin 		jsonw_end_object(json_wtr);
805ccda64dSRoman Gushchin 	} else {
815ccda64dSRoman Gushchin 		printf("%-8u %-15s %-15s %-15s\n", info.id,
825ccda64dSRoman Gushchin 		       attach_type_str,
835ccda64dSRoman Gushchin 		       attach_flags_str,
845ccda64dSRoman Gushchin 		       info.name);
855ccda64dSRoman Gushchin 	}
865ccda64dSRoman Gushchin 
875ccda64dSRoman Gushchin 	close(prog_fd);
885ccda64dSRoman Gushchin 	return 0;
895ccda64dSRoman Gushchin }
905ccda64dSRoman Gushchin 
9165b875bcSJakub Kicinski static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
925ccda64dSRoman Gushchin {
935ccda64dSRoman Gushchin 	__u32 prog_ids[1024] = {0};
945ccda64dSRoman Gushchin 	char *attach_flags_str;
955ccda64dSRoman Gushchin 	__u32 prog_cnt, iter;
965ccda64dSRoman Gushchin 	__u32 attach_flags;
975ccda64dSRoman Gushchin 	char buf[32];
985ccda64dSRoman Gushchin 	int ret;
995ccda64dSRoman Gushchin 
1005ccda64dSRoman Gushchin 	prog_cnt = ARRAY_SIZE(prog_ids);
1015ccda64dSRoman Gushchin 	ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids,
1025ccda64dSRoman Gushchin 			     &prog_cnt);
1035ccda64dSRoman Gushchin 	if (ret)
1045ccda64dSRoman Gushchin 		return ret;
1055ccda64dSRoman Gushchin 
1065ccda64dSRoman Gushchin 	if (prog_cnt == 0)
1075ccda64dSRoman Gushchin 		return 0;
1085ccda64dSRoman Gushchin 
1095ccda64dSRoman Gushchin 	switch (attach_flags) {
1105ccda64dSRoman Gushchin 	case BPF_F_ALLOW_MULTI:
1115ccda64dSRoman Gushchin 		attach_flags_str = "multi";
1125ccda64dSRoman Gushchin 		break;
1135ccda64dSRoman Gushchin 	case BPF_F_ALLOW_OVERRIDE:
1145ccda64dSRoman Gushchin 		attach_flags_str = "override";
1155ccda64dSRoman Gushchin 		break;
1165ccda64dSRoman Gushchin 	case 0:
1175ccda64dSRoman Gushchin 		attach_flags_str = "";
1185ccda64dSRoman Gushchin 		break;
1195ccda64dSRoman Gushchin 	default:
1205ccda64dSRoman Gushchin 		snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
1215ccda64dSRoman Gushchin 		attach_flags_str = buf;
1225ccda64dSRoman Gushchin 	}
1235ccda64dSRoman Gushchin 
1245ccda64dSRoman Gushchin 	for (iter = 0; iter < prog_cnt; iter++)
12565b875bcSJakub Kicinski 		show_bpf_prog(prog_ids[iter], attach_type_strings[type],
1265ccda64dSRoman Gushchin 			      attach_flags_str);
1275ccda64dSRoman Gushchin 
1285ccda64dSRoman Gushchin 	return 0;
1295ccda64dSRoman Gushchin }
1305ccda64dSRoman Gushchin 
13165b875bcSJakub Kicinski static int do_show(int argc, char **argv)
1325ccda64dSRoman Gushchin {
1335ccda64dSRoman Gushchin 	enum bpf_attach_type type;
1345ccda64dSRoman Gushchin 	int cgroup_fd;
1355ccda64dSRoman Gushchin 	int ret = -1;
1365ccda64dSRoman Gushchin 
1375ccda64dSRoman Gushchin 	if (argc < 1) {
138b4fac96dSJakub Kicinski 		p_err("too few parameters for cgroup show");
1395ccda64dSRoman Gushchin 		goto exit;
1405ccda64dSRoman Gushchin 	} else if (argc > 1) {
141b4fac96dSJakub Kicinski 		p_err("too many parameters for cgroup show");
1425ccda64dSRoman Gushchin 		goto exit;
1435ccda64dSRoman Gushchin 	}
1445ccda64dSRoman Gushchin 
1455ccda64dSRoman Gushchin 	cgroup_fd = open(argv[0], O_RDONLY);
1465ccda64dSRoman Gushchin 	if (cgroup_fd < 0) {
147b4fac96dSJakub Kicinski 		p_err("can't open cgroup %s", argv[1]);
1485ccda64dSRoman Gushchin 		goto exit;
1495ccda64dSRoman Gushchin 	}
1505ccda64dSRoman Gushchin 
1515ccda64dSRoman Gushchin 	if (json_output)
1525ccda64dSRoman Gushchin 		jsonw_start_array(json_wtr);
1535ccda64dSRoman Gushchin 	else
1545ccda64dSRoman Gushchin 		printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
1555ccda64dSRoman Gushchin 		       "AttachFlags", "Name");
1565ccda64dSRoman Gushchin 
1575ccda64dSRoman Gushchin 	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
1585ccda64dSRoman Gushchin 		/*
1595ccda64dSRoman Gushchin 		 * Not all attach types may be supported, so it's expected,
1605ccda64dSRoman Gushchin 		 * that some requests will fail.
16165b875bcSJakub Kicinski 		 * If we were able to get the show for at least one
1625ccda64dSRoman Gushchin 		 * attach type, let's return 0.
1635ccda64dSRoman Gushchin 		 */
16465b875bcSJakub Kicinski 		if (show_attached_bpf_progs(cgroup_fd, type) == 0)
1655ccda64dSRoman Gushchin 			ret = 0;
1665ccda64dSRoman Gushchin 	}
1675ccda64dSRoman Gushchin 
1685ccda64dSRoman Gushchin 	if (json_output)
1695ccda64dSRoman Gushchin 		jsonw_end_array(json_wtr);
1705ccda64dSRoman Gushchin 
1715ccda64dSRoman Gushchin 	close(cgroup_fd);
1725ccda64dSRoman Gushchin exit:
1735ccda64dSRoman Gushchin 	return ret;
1745ccda64dSRoman Gushchin }
1755ccda64dSRoman Gushchin 
1765ccda64dSRoman Gushchin static int do_attach(int argc, char **argv)
1775ccda64dSRoman Gushchin {
1785ccda64dSRoman Gushchin 	enum bpf_attach_type attach_type;
1795ccda64dSRoman Gushchin 	int cgroup_fd, prog_fd;
1805ccda64dSRoman Gushchin 	int attach_flags = 0;
1815ccda64dSRoman Gushchin 	int ret = -1;
1825ccda64dSRoman Gushchin 	int i;
1835ccda64dSRoman Gushchin 
1845ccda64dSRoman Gushchin 	if (argc < 4) {
185b4fac96dSJakub Kicinski 		p_err("too few parameters for cgroup attach");
1865ccda64dSRoman Gushchin 		goto exit;
1875ccda64dSRoman Gushchin 	}
1885ccda64dSRoman Gushchin 
1895ccda64dSRoman Gushchin 	cgroup_fd = open(argv[0], O_RDONLY);
1905ccda64dSRoman Gushchin 	if (cgroup_fd < 0) {
191b4fac96dSJakub Kicinski 		p_err("can't open cgroup %s", argv[1]);
1925ccda64dSRoman Gushchin 		goto exit;
1935ccda64dSRoman Gushchin 	}
1945ccda64dSRoman Gushchin 
1955ccda64dSRoman Gushchin 	attach_type = parse_attach_type(argv[1]);
1965ccda64dSRoman Gushchin 	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
197b4fac96dSJakub Kicinski 		p_err("invalid attach type");
1985ccda64dSRoman Gushchin 		goto exit_cgroup;
1995ccda64dSRoman Gushchin 	}
2005ccda64dSRoman Gushchin 
2015ccda64dSRoman Gushchin 	argc -= 2;
2025ccda64dSRoman Gushchin 	argv = &argv[2];
2035ccda64dSRoman Gushchin 	prog_fd = prog_parse_fd(&argc, &argv);
2045ccda64dSRoman Gushchin 	if (prog_fd < 0)
2055ccda64dSRoman Gushchin 		goto exit_cgroup;
2065ccda64dSRoman Gushchin 
2075ccda64dSRoman Gushchin 	for (i = 0; i < argc; i++) {
2085ccda64dSRoman Gushchin 		if (is_prefix(argv[i], "multi")) {
2095ccda64dSRoman Gushchin 			attach_flags |= BPF_F_ALLOW_MULTI;
2105ccda64dSRoman Gushchin 		} else if (is_prefix(argv[i], "override")) {
2115ccda64dSRoman Gushchin 			attach_flags |= BPF_F_ALLOW_OVERRIDE;
2125ccda64dSRoman Gushchin 		} else {
213b4fac96dSJakub Kicinski 			p_err("unknown option: %s", argv[i]);
2145ccda64dSRoman Gushchin 			goto exit_cgroup;
2155ccda64dSRoman Gushchin 		}
2165ccda64dSRoman Gushchin 	}
2175ccda64dSRoman Gushchin 
2185ccda64dSRoman Gushchin 	if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
2195ccda64dSRoman Gushchin 		p_err("failed to attach program");
2205ccda64dSRoman Gushchin 		goto exit_prog;
2215ccda64dSRoman Gushchin 	}
2225ccda64dSRoman Gushchin 
2235ccda64dSRoman Gushchin 	if (json_output)
2245ccda64dSRoman Gushchin 		jsonw_null(json_wtr);
2255ccda64dSRoman Gushchin 
2265ccda64dSRoman Gushchin 	ret = 0;
2275ccda64dSRoman Gushchin 
2285ccda64dSRoman Gushchin exit_prog:
2295ccda64dSRoman Gushchin 	close(prog_fd);
2305ccda64dSRoman Gushchin exit_cgroup:
2315ccda64dSRoman Gushchin 	close(cgroup_fd);
2325ccda64dSRoman Gushchin exit:
2335ccda64dSRoman Gushchin 	return ret;
2345ccda64dSRoman Gushchin }
2355ccda64dSRoman Gushchin 
2365ccda64dSRoman Gushchin static int do_detach(int argc, char **argv)
2375ccda64dSRoman Gushchin {
2385ccda64dSRoman Gushchin 	enum bpf_attach_type attach_type;
2395ccda64dSRoman Gushchin 	int prog_fd, cgroup_fd;
2405ccda64dSRoman Gushchin 	int ret = -1;
2415ccda64dSRoman Gushchin 
2425ccda64dSRoman Gushchin 	if (argc < 4) {
243b4fac96dSJakub Kicinski 		p_err("too few parameters for cgroup detach");
2445ccda64dSRoman Gushchin 		goto exit;
2455ccda64dSRoman Gushchin 	}
2465ccda64dSRoman Gushchin 
2475ccda64dSRoman Gushchin 	cgroup_fd = open(argv[0], O_RDONLY);
2485ccda64dSRoman Gushchin 	if (cgroup_fd < 0) {
249b4fac96dSJakub Kicinski 		p_err("can't open cgroup %s", argv[1]);
2505ccda64dSRoman Gushchin 		goto exit;
2515ccda64dSRoman Gushchin 	}
2525ccda64dSRoman Gushchin 
2535ccda64dSRoman Gushchin 	attach_type = parse_attach_type(argv[1]);
2545ccda64dSRoman Gushchin 	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
2555ccda64dSRoman Gushchin 		p_err("invalid attach type");
2565ccda64dSRoman Gushchin 		goto exit_cgroup;
2575ccda64dSRoman Gushchin 	}
2585ccda64dSRoman Gushchin 
2595ccda64dSRoman Gushchin 	argc -= 2;
2605ccda64dSRoman Gushchin 	argv = &argv[2];
2615ccda64dSRoman Gushchin 	prog_fd = prog_parse_fd(&argc, &argv);
2625ccda64dSRoman Gushchin 	if (prog_fd < 0)
2635ccda64dSRoman Gushchin 		goto exit_cgroup;
2645ccda64dSRoman Gushchin 
2655ccda64dSRoman Gushchin 	if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
2665ccda64dSRoman Gushchin 		p_err("failed to detach program");
2675ccda64dSRoman Gushchin 		goto exit_prog;
2685ccda64dSRoman Gushchin 	}
2695ccda64dSRoman Gushchin 
2705ccda64dSRoman Gushchin 	if (json_output)
2715ccda64dSRoman Gushchin 		jsonw_null(json_wtr);
2725ccda64dSRoman Gushchin 
2735ccda64dSRoman Gushchin 	ret = 0;
2745ccda64dSRoman Gushchin 
2755ccda64dSRoman Gushchin exit_prog:
2765ccda64dSRoman Gushchin 	close(prog_fd);
2775ccda64dSRoman Gushchin exit_cgroup:
2785ccda64dSRoman Gushchin 	close(cgroup_fd);
2795ccda64dSRoman Gushchin exit:
2805ccda64dSRoman Gushchin 	return ret;
2815ccda64dSRoman Gushchin }
2825ccda64dSRoman Gushchin 
2835ccda64dSRoman Gushchin static int do_help(int argc, char **argv)
2845ccda64dSRoman Gushchin {
2855ccda64dSRoman Gushchin 	if (json_output) {
2865ccda64dSRoman Gushchin 		jsonw_null(json_wtr);
2875ccda64dSRoman Gushchin 		return 0;
2885ccda64dSRoman Gushchin 	}
2895ccda64dSRoman Gushchin 
2905ccda64dSRoman Gushchin 	fprintf(stderr,
2916ebe6dbdSJakub Kicinski 		"Usage: %s %s { show | list } CGROUP\n"
2925ccda64dSRoman Gushchin 		"       %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
2935ccda64dSRoman Gushchin 		"       %s %s detach CGROUP ATTACH_TYPE PROG\n"
2945ccda64dSRoman Gushchin 		"       %s %s help\n"
2955ccda64dSRoman Gushchin 		"\n"
296393de512SAndrey Ignatov 		HELP_SPEC_ATTACH_TYPES "\n"
2975ccda64dSRoman Gushchin 		"       " HELP_SPEC_ATTACH_FLAGS "\n"
2985ccda64dSRoman Gushchin 		"       " HELP_SPEC_PROGRAM "\n"
2995ccda64dSRoman Gushchin 		"       " HELP_SPEC_OPTIONS "\n"
3005ccda64dSRoman Gushchin 		"",
3015ccda64dSRoman Gushchin 		bin_name, argv[-2], bin_name, argv[-2],
3025ccda64dSRoman Gushchin 		bin_name, argv[-2], bin_name, argv[-2]);
3035ccda64dSRoman Gushchin 
3045ccda64dSRoman Gushchin 	return 0;
3055ccda64dSRoman Gushchin }
3065ccda64dSRoman Gushchin 
3075ccda64dSRoman Gushchin static const struct cmd cmds[] = {
3086ebe6dbdSJakub Kicinski 	{ "show",	do_show },
30965b875bcSJakub Kicinski 	{ "list",	do_show },
3105ccda64dSRoman Gushchin 	{ "attach",	do_attach },
3115ccda64dSRoman Gushchin 	{ "detach",	do_detach },
3125ccda64dSRoman Gushchin 	{ "help",	do_help },
3135ccda64dSRoman Gushchin 	{ 0 }
3145ccda64dSRoman Gushchin };
3155ccda64dSRoman Gushchin 
3165ccda64dSRoman Gushchin int do_cgroup(int argc, char **argv)
3175ccda64dSRoman Gushchin {
3185ccda64dSRoman Gushchin 	return cmd_select(cmds, argc, argv, do_help);
3195ccda64dSRoman Gushchin }
320