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