1907b2236SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 25ccda64dSRoman Gushchin // Copyright (C) 2017 Facebook 35ccda64dSRoman Gushchin // Author: Roman Gushchin <guro@fb.com> 45ccda64dSRoman Gushchin 52058b383SRoman Gushchin #define _XOPEN_SOURCE 500 62058b383SRoman Gushchin #include <errno.h> 75ccda64dSRoman Gushchin #include <fcntl.h> 82058b383SRoman Gushchin #include <ftw.h> 92058b383SRoman Gushchin #include <mntent.h> 102058b383SRoman Gushchin #include <stdio.h> 115ccda64dSRoman Gushchin #include <stdlib.h> 125ccda64dSRoman Gushchin #include <string.h> 135ccda64dSRoman Gushchin #include <sys/stat.h> 145ccda64dSRoman Gushchin #include <sys/types.h> 155ccda64dSRoman Gushchin #include <unistd.h> 165ccda64dSRoman Gushchin 175ccda64dSRoman Gushchin #include <bpf.h> 185ccda64dSRoman Gushchin 195ccda64dSRoman Gushchin #include "main.h" 205ccda64dSRoman Gushchin 215ccda64dSRoman Gushchin #define HELP_SPEC_ATTACH_FLAGS \ 225ccda64dSRoman Gushchin "ATTACH_FLAGS := { multi | override }" 235ccda64dSRoman Gushchin 245ccda64dSRoman Gushchin #define HELP_SPEC_ATTACH_TYPES \ 25393de512SAndrey Ignatov " ATTACH_TYPE := { ingress | egress | sock_create |\n" \ 26393de512SAndrey Ignatov " sock_ops | device | bind4 | bind6 |\n" \ 27393de512SAndrey Ignatov " post_bind4 | post_bind6 | connect4 |\n" \ 28000aa125SDaniel Borkmann " connect6 | sendmsg4 | sendmsg6 |\n" \ 29000aa125SDaniel Borkmann " recvmsg4 | recvmsg6 | sysctl }" 305ccda64dSRoman Gushchin 315ccda64dSRoman Gushchin static const char * const attach_type_strings[] = { 325ccda64dSRoman Gushchin [BPF_CGROUP_INET_INGRESS] = "ingress", 335ccda64dSRoman Gushchin [BPF_CGROUP_INET_EGRESS] = "egress", 345ccda64dSRoman Gushchin [BPF_CGROUP_INET_SOCK_CREATE] = "sock_create", 355ccda64dSRoman Gushchin [BPF_CGROUP_SOCK_OPS] = "sock_ops", 365ccda64dSRoman Gushchin [BPF_CGROUP_DEVICE] = "device", 37393de512SAndrey Ignatov [BPF_CGROUP_INET4_BIND] = "bind4", 38393de512SAndrey Ignatov [BPF_CGROUP_INET6_BIND] = "bind6", 39393de512SAndrey Ignatov [BPF_CGROUP_INET4_CONNECT] = "connect4", 40393de512SAndrey Ignatov [BPF_CGROUP_INET6_CONNECT] = "connect6", 41393de512SAndrey Ignatov [BPF_CGROUP_INET4_POST_BIND] = "post_bind4", 42393de512SAndrey Ignatov [BPF_CGROUP_INET6_POST_BIND] = "post_bind6", 4313a370b9SAndrey Ignatov [BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4", 4413a370b9SAndrey Ignatov [BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6", 45f25377eeSAndrey Ignatov [BPF_CGROUP_SYSCTL] = "sysctl", 46000aa125SDaniel Borkmann [BPF_CGROUP_UDP4_RECVMSG] = "recvmsg4", 47000aa125SDaniel Borkmann [BPF_CGROUP_UDP6_RECVMSG] = "recvmsg6", 485ccda64dSRoman Gushchin [__MAX_BPF_ATTACH_TYPE] = NULL, 495ccda64dSRoman Gushchin }; 505ccda64dSRoman Gushchin 515ccda64dSRoman Gushchin static enum bpf_attach_type parse_attach_type(const char *str) 525ccda64dSRoman Gushchin { 535ccda64dSRoman Gushchin enum bpf_attach_type type; 545ccda64dSRoman Gushchin 555ccda64dSRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 565ccda64dSRoman Gushchin if (attach_type_strings[type] && 575ccda64dSRoman Gushchin is_prefix(str, attach_type_strings[type])) 585ccda64dSRoman Gushchin return type; 595ccda64dSRoman Gushchin } 605ccda64dSRoman Gushchin 615ccda64dSRoman Gushchin return __MAX_BPF_ATTACH_TYPE; 625ccda64dSRoman Gushchin } 635ccda64dSRoman Gushchin 6465b875bcSJakub Kicinski static int show_bpf_prog(int id, const char *attach_type_str, 652058b383SRoman Gushchin const char *attach_flags_str, 662058b383SRoman Gushchin int level) 675ccda64dSRoman Gushchin { 685ccda64dSRoman Gushchin struct bpf_prog_info info = {}; 695ccda64dSRoman Gushchin __u32 info_len = sizeof(info); 705ccda64dSRoman Gushchin int prog_fd; 715ccda64dSRoman Gushchin 725ccda64dSRoman Gushchin prog_fd = bpf_prog_get_fd_by_id(id); 735ccda64dSRoman Gushchin if (prog_fd < 0) 745ccda64dSRoman Gushchin return -1; 755ccda64dSRoman Gushchin 765ccda64dSRoman Gushchin if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { 775ccda64dSRoman Gushchin close(prog_fd); 785ccda64dSRoman Gushchin return -1; 795ccda64dSRoman Gushchin } 805ccda64dSRoman Gushchin 815ccda64dSRoman Gushchin if (json_output) { 825ccda64dSRoman Gushchin jsonw_start_object(json_wtr); 835ccda64dSRoman Gushchin jsonw_uint_field(json_wtr, "id", info.id); 845ccda64dSRoman Gushchin jsonw_string_field(json_wtr, "attach_type", 855ccda64dSRoman Gushchin attach_type_str); 865ccda64dSRoman Gushchin jsonw_string_field(json_wtr, "attach_flags", 875ccda64dSRoman Gushchin attach_flags_str); 885ccda64dSRoman Gushchin jsonw_string_field(json_wtr, "name", info.name); 895ccda64dSRoman Gushchin jsonw_end_object(json_wtr); 905ccda64dSRoman Gushchin } else { 912058b383SRoman Gushchin printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "", 922058b383SRoman Gushchin info.id, 935ccda64dSRoman Gushchin attach_type_str, 945ccda64dSRoman Gushchin attach_flags_str, 955ccda64dSRoman Gushchin info.name); 965ccda64dSRoman Gushchin } 975ccda64dSRoman Gushchin 985ccda64dSRoman Gushchin close(prog_fd); 995ccda64dSRoman Gushchin return 0; 1005ccda64dSRoman Gushchin } 1015ccda64dSRoman Gushchin 1022058b383SRoman Gushchin static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) 1032058b383SRoman Gushchin { 1042058b383SRoman Gushchin __u32 prog_cnt = 0; 1052058b383SRoman Gushchin int ret; 1062058b383SRoman Gushchin 1072058b383SRoman Gushchin ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt); 1082058b383SRoman Gushchin if (ret) 1092058b383SRoman Gushchin return -1; 1102058b383SRoman Gushchin 1112058b383SRoman Gushchin return prog_cnt; 1122058b383SRoman Gushchin } 1132058b383SRoman Gushchin 1142058b383SRoman Gushchin static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, 1152058b383SRoman Gushchin int level) 1165ccda64dSRoman Gushchin { 1175ccda64dSRoman Gushchin __u32 prog_ids[1024] = {0}; 1185ccda64dSRoman Gushchin char *attach_flags_str; 1195ccda64dSRoman Gushchin __u32 prog_cnt, iter; 1205ccda64dSRoman Gushchin __u32 attach_flags; 1215ccda64dSRoman Gushchin char buf[32]; 1225ccda64dSRoman Gushchin int ret; 1235ccda64dSRoman Gushchin 1245ccda64dSRoman Gushchin prog_cnt = ARRAY_SIZE(prog_ids); 1255ccda64dSRoman Gushchin ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids, 1265ccda64dSRoman Gushchin &prog_cnt); 1275ccda64dSRoman Gushchin if (ret) 1285ccda64dSRoman Gushchin return ret; 1295ccda64dSRoman Gushchin 1305ccda64dSRoman Gushchin if (prog_cnt == 0) 1315ccda64dSRoman Gushchin return 0; 1325ccda64dSRoman Gushchin 1335ccda64dSRoman Gushchin switch (attach_flags) { 1345ccda64dSRoman Gushchin case BPF_F_ALLOW_MULTI: 1355ccda64dSRoman Gushchin attach_flags_str = "multi"; 1365ccda64dSRoman Gushchin break; 1375ccda64dSRoman Gushchin case BPF_F_ALLOW_OVERRIDE: 1385ccda64dSRoman Gushchin attach_flags_str = "override"; 1395ccda64dSRoman Gushchin break; 1405ccda64dSRoman Gushchin case 0: 1415ccda64dSRoman Gushchin attach_flags_str = ""; 1425ccda64dSRoman Gushchin break; 1435ccda64dSRoman Gushchin default: 1445ccda64dSRoman Gushchin snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags); 1455ccda64dSRoman Gushchin attach_flags_str = buf; 1465ccda64dSRoman Gushchin } 1475ccda64dSRoman Gushchin 1485ccda64dSRoman Gushchin for (iter = 0; iter < prog_cnt; iter++) 14965b875bcSJakub Kicinski show_bpf_prog(prog_ids[iter], attach_type_strings[type], 1502058b383SRoman Gushchin attach_flags_str, level); 1515ccda64dSRoman Gushchin 1525ccda64dSRoman Gushchin return 0; 1535ccda64dSRoman Gushchin } 1545ccda64dSRoman Gushchin 15565b875bcSJakub Kicinski static int do_show(int argc, char **argv) 1565ccda64dSRoman Gushchin { 1575ccda64dSRoman Gushchin enum bpf_attach_type type; 1585ccda64dSRoman Gushchin int cgroup_fd; 1595ccda64dSRoman Gushchin int ret = -1; 1605ccda64dSRoman Gushchin 1615ccda64dSRoman Gushchin if (argc < 1) { 162b4fac96dSJakub Kicinski p_err("too few parameters for cgroup show"); 1635ccda64dSRoman Gushchin goto exit; 1645ccda64dSRoman Gushchin } else if (argc > 1) { 165b4fac96dSJakub Kicinski p_err("too many parameters for cgroup show"); 1665ccda64dSRoman Gushchin goto exit; 1675ccda64dSRoman Gushchin } 1685ccda64dSRoman Gushchin 1695ccda64dSRoman Gushchin cgroup_fd = open(argv[0], O_RDONLY); 1705ccda64dSRoman Gushchin if (cgroup_fd < 0) { 171b4fac96dSJakub Kicinski p_err("can't open cgroup %s", argv[1]); 1725ccda64dSRoman Gushchin goto exit; 1735ccda64dSRoman Gushchin } 1745ccda64dSRoman Gushchin 1755ccda64dSRoman Gushchin if (json_output) 1765ccda64dSRoman Gushchin jsonw_start_array(json_wtr); 1775ccda64dSRoman Gushchin else 1785ccda64dSRoman Gushchin printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType", 1795ccda64dSRoman Gushchin "AttachFlags", "Name"); 1805ccda64dSRoman Gushchin 1815ccda64dSRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 1825ccda64dSRoman Gushchin /* 1835ccda64dSRoman Gushchin * Not all attach types may be supported, so it's expected, 1845ccda64dSRoman Gushchin * that some requests will fail. 18565b875bcSJakub Kicinski * If we were able to get the show for at least one 1865ccda64dSRoman Gushchin * attach type, let's return 0. 1875ccda64dSRoman Gushchin */ 1882058b383SRoman Gushchin if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0) 1895ccda64dSRoman Gushchin ret = 0; 1905ccda64dSRoman Gushchin } 1915ccda64dSRoman Gushchin 1925ccda64dSRoman Gushchin if (json_output) 1935ccda64dSRoman Gushchin jsonw_end_array(json_wtr); 1945ccda64dSRoman Gushchin 1955ccda64dSRoman Gushchin close(cgroup_fd); 1965ccda64dSRoman Gushchin exit: 1975ccda64dSRoman Gushchin return ret; 1985ccda64dSRoman Gushchin } 1995ccda64dSRoman Gushchin 2002058b383SRoman Gushchin /* 2012058b383SRoman Gushchin * To distinguish nftw() errors and do_show_tree_fn() errors 2022058b383SRoman Gushchin * and avoid duplicating error messages, let's return -2 2032058b383SRoman Gushchin * from do_show_tree_fn() in case of error. 2042058b383SRoman Gushchin */ 2052058b383SRoman Gushchin #define NFTW_ERR -1 2062058b383SRoman Gushchin #define SHOW_TREE_FN_ERR -2 2072058b383SRoman Gushchin static int do_show_tree_fn(const char *fpath, const struct stat *sb, 2082058b383SRoman Gushchin int typeflag, struct FTW *ftw) 2092058b383SRoman Gushchin { 2102058b383SRoman Gushchin enum bpf_attach_type type; 2112058b383SRoman Gushchin bool skip = true; 2122058b383SRoman Gushchin int cgroup_fd; 2132058b383SRoman Gushchin 2142058b383SRoman Gushchin if (typeflag != FTW_D) 2152058b383SRoman Gushchin return 0; 2162058b383SRoman Gushchin 2172058b383SRoman Gushchin cgroup_fd = open(fpath, O_RDONLY); 2182058b383SRoman Gushchin if (cgroup_fd < 0) { 2192058b383SRoman Gushchin p_err("can't open cgroup %s: %s", fpath, strerror(errno)); 2202058b383SRoman Gushchin return SHOW_TREE_FN_ERR; 2212058b383SRoman Gushchin } 2222058b383SRoman Gushchin 2232058b383SRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 2242058b383SRoman Gushchin int count = count_attached_bpf_progs(cgroup_fd, type); 2252058b383SRoman Gushchin 2262058b383SRoman Gushchin if (count < 0 && errno != EINVAL) { 2272058b383SRoman Gushchin p_err("can't query bpf programs attached to %s: %s", 2282058b383SRoman Gushchin fpath, strerror(errno)); 2292058b383SRoman Gushchin close(cgroup_fd); 2302058b383SRoman Gushchin return SHOW_TREE_FN_ERR; 2312058b383SRoman Gushchin } 2322058b383SRoman Gushchin if (count > 0) { 2332058b383SRoman Gushchin skip = false; 2342058b383SRoman Gushchin break; 2352058b383SRoman Gushchin } 2362058b383SRoman Gushchin } 2372058b383SRoman Gushchin 2382058b383SRoman Gushchin if (skip) { 2392058b383SRoman Gushchin close(cgroup_fd); 2402058b383SRoman Gushchin return 0; 2412058b383SRoman Gushchin } 2422058b383SRoman Gushchin 2432058b383SRoman Gushchin if (json_output) { 2442058b383SRoman Gushchin jsonw_start_object(json_wtr); 2452058b383SRoman Gushchin jsonw_string_field(json_wtr, "cgroup", fpath); 2462058b383SRoman Gushchin jsonw_name(json_wtr, "programs"); 2472058b383SRoman Gushchin jsonw_start_array(json_wtr); 2482058b383SRoman Gushchin } else { 2492058b383SRoman Gushchin printf("%s\n", fpath); 2502058b383SRoman Gushchin } 2512058b383SRoman Gushchin 2522058b383SRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) 2532058b383SRoman Gushchin show_attached_bpf_progs(cgroup_fd, type, ftw->level); 2542058b383SRoman Gushchin 25539c9f106SQuentin Monnet if (errno == EINVAL) 25639c9f106SQuentin Monnet /* Last attach type does not support query. 25739c9f106SQuentin Monnet * Do not report an error for this, especially because batch 25839c9f106SQuentin Monnet * mode would stop processing commands. 25939c9f106SQuentin Monnet */ 26039c9f106SQuentin Monnet errno = 0; 26139c9f106SQuentin Monnet 2622058b383SRoman Gushchin if (json_output) { 2632058b383SRoman Gushchin jsonw_end_array(json_wtr); 2642058b383SRoman Gushchin jsonw_end_object(json_wtr); 2652058b383SRoman Gushchin } 2662058b383SRoman Gushchin 2672058b383SRoman Gushchin close(cgroup_fd); 2682058b383SRoman Gushchin 2692058b383SRoman Gushchin return 0; 2702058b383SRoman Gushchin } 2712058b383SRoman Gushchin 2722058b383SRoman Gushchin static char *find_cgroup_root(void) 2732058b383SRoman Gushchin { 2742058b383SRoman Gushchin struct mntent *mnt; 2752058b383SRoman Gushchin FILE *f; 2762058b383SRoman Gushchin 2772058b383SRoman Gushchin f = fopen("/proc/mounts", "r"); 2782058b383SRoman Gushchin if (f == NULL) 2792058b383SRoman Gushchin return NULL; 2802058b383SRoman Gushchin 2812058b383SRoman Gushchin while ((mnt = getmntent(f))) { 2822058b383SRoman Gushchin if (strcmp(mnt->mnt_type, "cgroup2") == 0) { 2832058b383SRoman Gushchin fclose(f); 2842058b383SRoman Gushchin return strdup(mnt->mnt_dir); 2852058b383SRoman Gushchin } 2862058b383SRoman Gushchin } 2872058b383SRoman Gushchin 2882058b383SRoman Gushchin fclose(f); 2892058b383SRoman Gushchin return NULL; 2902058b383SRoman Gushchin } 2912058b383SRoman Gushchin 2922058b383SRoman Gushchin static int do_show_tree(int argc, char **argv) 2932058b383SRoman Gushchin { 2942058b383SRoman Gushchin char *cgroup_root; 2952058b383SRoman Gushchin int ret; 2962058b383SRoman Gushchin 2972058b383SRoman Gushchin switch (argc) { 2982058b383SRoman Gushchin case 0: 2992058b383SRoman Gushchin cgroup_root = find_cgroup_root(); 3002058b383SRoman Gushchin if (!cgroup_root) { 3012058b383SRoman Gushchin p_err("cgroup v2 isn't mounted"); 3022058b383SRoman Gushchin return -1; 3032058b383SRoman Gushchin } 3042058b383SRoman Gushchin break; 3052058b383SRoman Gushchin case 1: 3062058b383SRoman Gushchin cgroup_root = argv[0]; 3072058b383SRoman Gushchin break; 3082058b383SRoman Gushchin default: 3092058b383SRoman Gushchin p_err("too many parameters for cgroup tree"); 3102058b383SRoman Gushchin return -1; 3112058b383SRoman Gushchin } 3122058b383SRoman Gushchin 3132058b383SRoman Gushchin 3142058b383SRoman Gushchin if (json_output) 3152058b383SRoman Gushchin jsonw_start_array(json_wtr); 3162058b383SRoman Gushchin else 3172058b383SRoman Gushchin printf("%s\n" 3182058b383SRoman Gushchin "%-8s %-15s %-15s %-15s\n", 3192058b383SRoman Gushchin "CgroupPath", 3202058b383SRoman Gushchin "ID", "AttachType", "AttachFlags", "Name"); 3212058b383SRoman Gushchin 3222058b383SRoman Gushchin switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) { 3232058b383SRoman Gushchin case NFTW_ERR: 3242058b383SRoman Gushchin p_err("can't iterate over %s: %s", cgroup_root, 3252058b383SRoman Gushchin strerror(errno)); 3262058b383SRoman Gushchin ret = -1; 3272058b383SRoman Gushchin break; 3282058b383SRoman Gushchin case SHOW_TREE_FN_ERR: 3292058b383SRoman Gushchin ret = -1; 3302058b383SRoman Gushchin break; 3312058b383SRoman Gushchin default: 3322058b383SRoman Gushchin ret = 0; 3332058b383SRoman Gushchin } 3342058b383SRoman Gushchin 3352058b383SRoman Gushchin if (json_output) 3362058b383SRoman Gushchin jsonw_end_array(json_wtr); 3372058b383SRoman Gushchin 3382058b383SRoman Gushchin if (argc == 0) 3392058b383SRoman Gushchin free(cgroup_root); 3402058b383SRoman Gushchin 3412058b383SRoman Gushchin return ret; 3422058b383SRoman Gushchin } 3432058b383SRoman Gushchin 3445ccda64dSRoman Gushchin static int do_attach(int argc, char **argv) 3455ccda64dSRoman Gushchin { 3465ccda64dSRoman Gushchin enum bpf_attach_type attach_type; 3475ccda64dSRoman Gushchin int cgroup_fd, prog_fd; 3485ccda64dSRoman Gushchin int attach_flags = 0; 3495ccda64dSRoman Gushchin int ret = -1; 3505ccda64dSRoman Gushchin int i; 3515ccda64dSRoman Gushchin 3525ccda64dSRoman Gushchin if (argc < 4) { 353b4fac96dSJakub Kicinski p_err("too few parameters for cgroup attach"); 3545ccda64dSRoman Gushchin goto exit; 3555ccda64dSRoman Gushchin } 3565ccda64dSRoman Gushchin 3575ccda64dSRoman Gushchin cgroup_fd = open(argv[0], O_RDONLY); 3585ccda64dSRoman Gushchin if (cgroup_fd < 0) { 359b4fac96dSJakub Kicinski p_err("can't open cgroup %s", argv[1]); 3605ccda64dSRoman Gushchin goto exit; 3615ccda64dSRoman Gushchin } 3625ccda64dSRoman Gushchin 3635ccda64dSRoman Gushchin attach_type = parse_attach_type(argv[1]); 3645ccda64dSRoman Gushchin if (attach_type == __MAX_BPF_ATTACH_TYPE) { 365b4fac96dSJakub Kicinski p_err("invalid attach type"); 3665ccda64dSRoman Gushchin goto exit_cgroup; 3675ccda64dSRoman Gushchin } 3685ccda64dSRoman Gushchin 3695ccda64dSRoman Gushchin argc -= 2; 3705ccda64dSRoman Gushchin argv = &argv[2]; 3715ccda64dSRoman Gushchin prog_fd = prog_parse_fd(&argc, &argv); 3725ccda64dSRoman Gushchin if (prog_fd < 0) 3735ccda64dSRoman Gushchin goto exit_cgroup; 3745ccda64dSRoman Gushchin 3755ccda64dSRoman Gushchin for (i = 0; i < argc; i++) { 3765ccda64dSRoman Gushchin if (is_prefix(argv[i], "multi")) { 3775ccda64dSRoman Gushchin attach_flags |= BPF_F_ALLOW_MULTI; 3785ccda64dSRoman Gushchin } else if (is_prefix(argv[i], "override")) { 3795ccda64dSRoman Gushchin attach_flags |= BPF_F_ALLOW_OVERRIDE; 3805ccda64dSRoman Gushchin } else { 381b4fac96dSJakub Kicinski p_err("unknown option: %s", argv[i]); 3825ccda64dSRoman Gushchin goto exit_cgroup; 3835ccda64dSRoman Gushchin } 3845ccda64dSRoman Gushchin } 3855ccda64dSRoman Gushchin 3865ccda64dSRoman Gushchin if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) { 3875ccda64dSRoman Gushchin p_err("failed to attach program"); 3885ccda64dSRoman Gushchin goto exit_prog; 3895ccda64dSRoman Gushchin } 3905ccda64dSRoman Gushchin 3915ccda64dSRoman Gushchin if (json_output) 3925ccda64dSRoman Gushchin jsonw_null(json_wtr); 3935ccda64dSRoman Gushchin 3945ccda64dSRoman Gushchin ret = 0; 3955ccda64dSRoman Gushchin 3965ccda64dSRoman Gushchin exit_prog: 3975ccda64dSRoman Gushchin close(prog_fd); 3985ccda64dSRoman Gushchin exit_cgroup: 3995ccda64dSRoman Gushchin close(cgroup_fd); 4005ccda64dSRoman Gushchin exit: 4015ccda64dSRoman Gushchin return ret; 4025ccda64dSRoman Gushchin } 4035ccda64dSRoman Gushchin 4045ccda64dSRoman Gushchin static int do_detach(int argc, char **argv) 4055ccda64dSRoman Gushchin { 4065ccda64dSRoman Gushchin enum bpf_attach_type attach_type; 4075ccda64dSRoman Gushchin int prog_fd, cgroup_fd; 4085ccda64dSRoman Gushchin int ret = -1; 4095ccda64dSRoman Gushchin 4105ccda64dSRoman Gushchin if (argc < 4) { 411b4fac96dSJakub Kicinski p_err("too few parameters for cgroup detach"); 4125ccda64dSRoman Gushchin goto exit; 4135ccda64dSRoman Gushchin } 4145ccda64dSRoman Gushchin 4155ccda64dSRoman Gushchin cgroup_fd = open(argv[0], O_RDONLY); 4165ccda64dSRoman Gushchin if (cgroup_fd < 0) { 417b4fac96dSJakub Kicinski p_err("can't open cgroup %s", argv[1]); 4185ccda64dSRoman Gushchin goto exit; 4195ccda64dSRoman Gushchin } 4205ccda64dSRoman Gushchin 4215ccda64dSRoman Gushchin attach_type = parse_attach_type(argv[1]); 4225ccda64dSRoman Gushchin if (attach_type == __MAX_BPF_ATTACH_TYPE) { 4235ccda64dSRoman Gushchin p_err("invalid attach type"); 4245ccda64dSRoman Gushchin goto exit_cgroup; 4255ccda64dSRoman Gushchin } 4265ccda64dSRoman Gushchin 4275ccda64dSRoman Gushchin argc -= 2; 4285ccda64dSRoman Gushchin argv = &argv[2]; 4295ccda64dSRoman Gushchin prog_fd = prog_parse_fd(&argc, &argv); 4305ccda64dSRoman Gushchin if (prog_fd < 0) 4315ccda64dSRoman Gushchin goto exit_cgroup; 4325ccda64dSRoman Gushchin 4335ccda64dSRoman Gushchin if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) { 4345ccda64dSRoman Gushchin p_err("failed to detach program"); 4355ccda64dSRoman Gushchin goto exit_prog; 4365ccda64dSRoman Gushchin } 4375ccda64dSRoman Gushchin 4385ccda64dSRoman Gushchin if (json_output) 4395ccda64dSRoman Gushchin jsonw_null(json_wtr); 4405ccda64dSRoman Gushchin 4415ccda64dSRoman Gushchin ret = 0; 4425ccda64dSRoman Gushchin 4435ccda64dSRoman Gushchin exit_prog: 4445ccda64dSRoman Gushchin close(prog_fd); 4455ccda64dSRoman Gushchin exit_cgroup: 4465ccda64dSRoman Gushchin close(cgroup_fd); 4475ccda64dSRoman Gushchin exit: 4485ccda64dSRoman Gushchin return ret; 4495ccda64dSRoman Gushchin } 4505ccda64dSRoman Gushchin 4515ccda64dSRoman Gushchin static int do_help(int argc, char **argv) 4525ccda64dSRoman Gushchin { 4535ccda64dSRoman Gushchin if (json_output) { 4545ccda64dSRoman Gushchin jsonw_null(json_wtr); 4555ccda64dSRoman Gushchin return 0; 4565ccda64dSRoman Gushchin } 4575ccda64dSRoman Gushchin 4585ccda64dSRoman Gushchin fprintf(stderr, 4596ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } CGROUP\n" 4602058b383SRoman Gushchin " %s %s tree [CGROUP_ROOT]\n" 4615ccda64dSRoman Gushchin " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" 4625ccda64dSRoman Gushchin " %s %s detach CGROUP ATTACH_TYPE PROG\n" 4635ccda64dSRoman Gushchin " %s %s help\n" 4645ccda64dSRoman Gushchin "\n" 465393de512SAndrey Ignatov HELP_SPEC_ATTACH_TYPES "\n" 4665ccda64dSRoman Gushchin " " HELP_SPEC_ATTACH_FLAGS "\n" 4675ccda64dSRoman Gushchin " " HELP_SPEC_PROGRAM "\n" 4685ccda64dSRoman Gushchin " " HELP_SPEC_OPTIONS "\n" 4695ccda64dSRoman Gushchin "", 4702058b383SRoman Gushchin bin_name, argv[-2], 4715ccda64dSRoman Gushchin bin_name, argv[-2], bin_name, argv[-2], 4725ccda64dSRoman Gushchin bin_name, argv[-2], bin_name, argv[-2]); 4735ccda64dSRoman Gushchin 4745ccda64dSRoman Gushchin return 0; 4755ccda64dSRoman Gushchin } 4765ccda64dSRoman Gushchin 4775ccda64dSRoman Gushchin static const struct cmd cmds[] = { 4786ebe6dbdSJakub Kicinski { "show", do_show }, 47965b875bcSJakub Kicinski { "list", do_show }, 4802058b383SRoman Gushchin { "tree", do_show_tree }, 4815ccda64dSRoman Gushchin { "attach", do_attach }, 4825ccda64dSRoman Gushchin { "detach", do_detach }, 4835ccda64dSRoman Gushchin { "help", do_help }, 4845ccda64dSRoman Gushchin { 0 } 4855ccda64dSRoman Gushchin }; 4865ccda64dSRoman Gushchin 4875ccda64dSRoman Gushchin int do_cgroup(int argc, char **argv) 4885ccda64dSRoman Gushchin { 4895ccda64dSRoman Gushchin return cmd_select(cmds, argc, argv, do_help); 4905ccda64dSRoman Gushchin } 491