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 17229c3b47SToke Høiland-Jørgensen #include <bpf/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" \ 2805ee19c1SDaniel Borkmann " connect6 | getpeername4 | getpeername6 |\n" \ 2905ee19c1SDaniel Borkmann " getsockname4 | getsockname6 | sendmsg4 |\n" \ 3005ee19c1SDaniel Borkmann " sendmsg6 | recvmsg4 | recvmsg6 |\n" \ 31a8deba85SLiu Jian " sysctl | getsockopt | setsockopt |\n" \ 32a8deba85SLiu Jian " sock_release }" 335ccda64dSRoman Gushchin 34a98bf573SJakub Kicinski static unsigned int query_flags; 35a98bf573SJakub Kicinski 365ccda64dSRoman Gushchin static enum bpf_attach_type parse_attach_type(const char *str) 375ccda64dSRoman Gushchin { 385ccda64dSRoman Gushchin enum bpf_attach_type type; 395ccda64dSRoman Gushchin 405ccda64dSRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 4150325b17SAndrii Nakryiko if (attach_type_name[type] && 4250325b17SAndrii Nakryiko is_prefix(str, attach_type_name[type])) 435ccda64dSRoman Gushchin return type; 445ccda64dSRoman Gushchin } 455ccda64dSRoman Gushchin 465ccda64dSRoman Gushchin return __MAX_BPF_ATTACH_TYPE; 475ccda64dSRoman Gushchin } 485ccda64dSRoman Gushchin 4950325b17SAndrii Nakryiko static int show_bpf_prog(int id, enum bpf_attach_type attach_type, 502058b383SRoman Gushchin const char *attach_flags_str, 512058b383SRoman Gushchin int level) 525ccda64dSRoman Gushchin { 535ccda64dSRoman Gushchin struct bpf_prog_info info = {}; 545ccda64dSRoman Gushchin __u32 info_len = sizeof(info); 555ccda64dSRoman Gushchin int prog_fd; 565ccda64dSRoman Gushchin 575ccda64dSRoman Gushchin prog_fd = bpf_prog_get_fd_by_id(id); 585ccda64dSRoman Gushchin if (prog_fd < 0) 595ccda64dSRoman Gushchin return -1; 605ccda64dSRoman Gushchin 615ccda64dSRoman Gushchin if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { 625ccda64dSRoman Gushchin close(prog_fd); 635ccda64dSRoman Gushchin return -1; 645ccda64dSRoman Gushchin } 655ccda64dSRoman Gushchin 665ccda64dSRoman Gushchin if (json_output) { 675ccda64dSRoman Gushchin jsonw_start_object(json_wtr); 685ccda64dSRoman Gushchin jsonw_uint_field(json_wtr, "id", info.id); 6950325b17SAndrii Nakryiko if (attach_type < ARRAY_SIZE(attach_type_name)) 705ccda64dSRoman Gushchin jsonw_string_field(json_wtr, "attach_type", 7150325b17SAndrii Nakryiko attach_type_name[attach_type]); 7250325b17SAndrii Nakryiko else 7350325b17SAndrii Nakryiko jsonw_uint_field(json_wtr, "attach_type", attach_type); 745ccda64dSRoman Gushchin jsonw_string_field(json_wtr, "attach_flags", 755ccda64dSRoman Gushchin attach_flags_str); 765ccda64dSRoman Gushchin jsonw_string_field(json_wtr, "name", info.name); 775ccda64dSRoman Gushchin jsonw_end_object(json_wtr); 785ccda64dSRoman Gushchin } else { 7950325b17SAndrii Nakryiko printf("%s%-8u ", level ? " " : "", info.id); 8050325b17SAndrii Nakryiko if (attach_type < ARRAY_SIZE(attach_type_name)) 8150325b17SAndrii Nakryiko printf("%-15s", attach_type_name[attach_type]); 8250325b17SAndrii Nakryiko else 8350325b17SAndrii Nakryiko printf("type %-10u", attach_type); 8450325b17SAndrii Nakryiko printf(" %-15s %-15s\n", attach_flags_str, info.name); 855ccda64dSRoman Gushchin } 865ccda64dSRoman Gushchin 875ccda64dSRoman Gushchin close(prog_fd); 885ccda64dSRoman Gushchin return 0; 895ccda64dSRoman Gushchin } 905ccda64dSRoman Gushchin 912058b383SRoman Gushchin static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) 922058b383SRoman Gushchin { 932058b383SRoman Gushchin __u32 prog_cnt = 0; 942058b383SRoman Gushchin int ret; 952058b383SRoman Gushchin 96a98bf573SJakub Kicinski ret = bpf_prog_query(cgroup_fd, type, query_flags, NULL, 97a98bf573SJakub Kicinski NULL, &prog_cnt); 982058b383SRoman Gushchin if (ret) 992058b383SRoman Gushchin return -1; 1002058b383SRoman Gushchin 1012058b383SRoman Gushchin return prog_cnt; 1022058b383SRoman Gushchin } 1032058b383SRoman Gushchin 1041162f844SHechao Li static int cgroup_has_attached_progs(int cgroup_fd) 1051162f844SHechao Li { 1061162f844SHechao Li enum bpf_attach_type type; 1071162f844SHechao Li bool no_prog = true; 1081162f844SHechao Li 1091162f844SHechao Li for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 1101162f844SHechao Li int count = count_attached_bpf_progs(cgroup_fd, type); 1111162f844SHechao Li 1121162f844SHechao Li if (count < 0 && errno != EINVAL) 1131162f844SHechao Li return -1; 1141162f844SHechao Li 1151162f844SHechao Li if (count > 0) { 1161162f844SHechao Li no_prog = false; 1171162f844SHechao Li break; 1181162f844SHechao Li } 1191162f844SHechao Li } 1201162f844SHechao Li 1211162f844SHechao Li return no_prog ? 0 : 1; 1221162f844SHechao Li } 1232058b383SRoman Gushchin static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, 1242058b383SRoman Gushchin int level) 1255ccda64dSRoman Gushchin { 126a9436dcaSQuentin Monnet const char *attach_flags_str; 1275ccda64dSRoman Gushchin __u32 prog_ids[1024] = {0}; 1285ccda64dSRoman Gushchin __u32 prog_cnt, iter; 1295ccda64dSRoman Gushchin __u32 attach_flags; 1305ccda64dSRoman Gushchin char buf[32]; 1315ccda64dSRoman Gushchin int ret; 1325ccda64dSRoman Gushchin 1335ccda64dSRoman Gushchin prog_cnt = ARRAY_SIZE(prog_ids); 134a98bf573SJakub Kicinski ret = bpf_prog_query(cgroup_fd, type, query_flags, &attach_flags, 135a98bf573SJakub Kicinski prog_ids, &prog_cnt); 1365ccda64dSRoman Gushchin if (ret) 1375ccda64dSRoman Gushchin return ret; 1385ccda64dSRoman Gushchin 1395ccda64dSRoman Gushchin if (prog_cnt == 0) 1405ccda64dSRoman Gushchin return 0; 1415ccda64dSRoman Gushchin 1425ccda64dSRoman Gushchin switch (attach_flags) { 1435ccda64dSRoman Gushchin case BPF_F_ALLOW_MULTI: 1445ccda64dSRoman Gushchin attach_flags_str = "multi"; 1455ccda64dSRoman Gushchin break; 1465ccda64dSRoman Gushchin case BPF_F_ALLOW_OVERRIDE: 1475ccda64dSRoman Gushchin attach_flags_str = "override"; 1485ccda64dSRoman Gushchin break; 1495ccda64dSRoman Gushchin case 0: 1505ccda64dSRoman Gushchin attach_flags_str = ""; 1515ccda64dSRoman Gushchin break; 1525ccda64dSRoman Gushchin default: 1535ccda64dSRoman Gushchin snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags); 1545ccda64dSRoman Gushchin attach_flags_str = buf; 1555ccda64dSRoman Gushchin } 1565ccda64dSRoman Gushchin 1575ccda64dSRoman Gushchin for (iter = 0; iter < prog_cnt; iter++) 15850325b17SAndrii Nakryiko show_bpf_prog(prog_ids[iter], type, 1592058b383SRoman Gushchin attach_flags_str, level); 1605ccda64dSRoman Gushchin 1615ccda64dSRoman Gushchin return 0; 1625ccda64dSRoman Gushchin } 1635ccda64dSRoman Gushchin 16465b875bcSJakub Kicinski static int do_show(int argc, char **argv) 1655ccda64dSRoman Gushchin { 1665ccda64dSRoman Gushchin enum bpf_attach_type type; 1671162f844SHechao Li int has_attached_progs; 168a98bf573SJakub Kicinski const char *path; 1695ccda64dSRoman Gushchin int cgroup_fd; 1705ccda64dSRoman Gushchin int ret = -1; 1715ccda64dSRoman Gushchin 172a98bf573SJakub Kicinski query_flags = 0; 173a98bf573SJakub Kicinski 174a98bf573SJakub Kicinski if (!REQ_ARGS(1)) 175a98bf573SJakub Kicinski return -1; 176a98bf573SJakub Kicinski path = GET_ARG(); 177a98bf573SJakub Kicinski 178a98bf573SJakub Kicinski while (argc) { 179a98bf573SJakub Kicinski if (is_prefix(*argv, "effective")) { 180a98bf573SJakub Kicinski if (query_flags & BPF_F_QUERY_EFFECTIVE) { 181a98bf573SJakub Kicinski p_err("duplicated argument: %s", *argv); 182a98bf573SJakub Kicinski return -1; 183a98bf573SJakub Kicinski } 184a98bf573SJakub Kicinski query_flags |= BPF_F_QUERY_EFFECTIVE; 185a98bf573SJakub Kicinski NEXT_ARG(); 186a98bf573SJakub Kicinski } else { 187a98bf573SJakub Kicinski p_err("expected no more arguments, 'effective', got: '%s'?", 188a98bf573SJakub Kicinski *argv); 189a98bf573SJakub Kicinski return -1; 190a98bf573SJakub Kicinski } 1915ccda64dSRoman Gushchin } 1925ccda64dSRoman Gushchin 193a98bf573SJakub Kicinski cgroup_fd = open(path, O_RDONLY); 1945ccda64dSRoman Gushchin if (cgroup_fd < 0) { 195a98bf573SJakub Kicinski p_err("can't open cgroup %s", path); 1965ccda64dSRoman Gushchin goto exit; 1975ccda64dSRoman Gushchin } 1985ccda64dSRoman Gushchin 1991162f844SHechao Li has_attached_progs = cgroup_has_attached_progs(cgroup_fd); 2001162f844SHechao Li if (has_attached_progs < 0) { 2011162f844SHechao Li p_err("can't query bpf programs attached to %s: %s", 2021162f844SHechao Li path, strerror(errno)); 2031162f844SHechao Li goto exit_cgroup; 2041162f844SHechao Li } else if (!has_attached_progs) { 2051162f844SHechao Li ret = 0; 2061162f844SHechao Li goto exit_cgroup; 2071162f844SHechao Li } 2081162f844SHechao Li 2095ccda64dSRoman Gushchin if (json_output) 2105ccda64dSRoman Gushchin jsonw_start_array(json_wtr); 2115ccda64dSRoman Gushchin else 2125ccda64dSRoman Gushchin printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType", 2135ccda64dSRoman Gushchin "AttachFlags", "Name"); 2145ccda64dSRoman Gushchin 2155ccda64dSRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 2165ccda64dSRoman Gushchin /* 2175ccda64dSRoman Gushchin * Not all attach types may be supported, so it's expected, 2185ccda64dSRoman Gushchin * that some requests will fail. 21965b875bcSJakub Kicinski * If we were able to get the show for at least one 2205ccda64dSRoman Gushchin * attach type, let's return 0. 2215ccda64dSRoman Gushchin */ 2222058b383SRoman Gushchin if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0) 2235ccda64dSRoman Gushchin ret = 0; 2245ccda64dSRoman Gushchin } 2255ccda64dSRoman Gushchin 2265ccda64dSRoman Gushchin if (json_output) 2275ccda64dSRoman Gushchin jsonw_end_array(json_wtr); 2285ccda64dSRoman Gushchin 2291162f844SHechao Li exit_cgroup: 2305ccda64dSRoman Gushchin close(cgroup_fd); 2315ccda64dSRoman Gushchin exit: 2325ccda64dSRoman Gushchin return ret; 2335ccda64dSRoman Gushchin } 2345ccda64dSRoman Gushchin 2352058b383SRoman Gushchin /* 2362058b383SRoman Gushchin * To distinguish nftw() errors and do_show_tree_fn() errors 2372058b383SRoman Gushchin * and avoid duplicating error messages, let's return -2 2382058b383SRoman Gushchin * from do_show_tree_fn() in case of error. 2392058b383SRoman Gushchin */ 2402058b383SRoman Gushchin #define NFTW_ERR -1 2412058b383SRoman Gushchin #define SHOW_TREE_FN_ERR -2 2422058b383SRoman Gushchin static int do_show_tree_fn(const char *fpath, const struct stat *sb, 2432058b383SRoman Gushchin int typeflag, struct FTW *ftw) 2442058b383SRoman Gushchin { 2452058b383SRoman Gushchin enum bpf_attach_type type; 2461162f844SHechao Li int has_attached_progs; 2472058b383SRoman Gushchin int cgroup_fd; 2482058b383SRoman Gushchin 2492058b383SRoman Gushchin if (typeflag != FTW_D) 2502058b383SRoman Gushchin return 0; 2512058b383SRoman Gushchin 2522058b383SRoman Gushchin cgroup_fd = open(fpath, O_RDONLY); 2532058b383SRoman Gushchin if (cgroup_fd < 0) { 2542058b383SRoman Gushchin p_err("can't open cgroup %s: %s", fpath, strerror(errno)); 2552058b383SRoman Gushchin return SHOW_TREE_FN_ERR; 2562058b383SRoman Gushchin } 2572058b383SRoman Gushchin 2581162f844SHechao Li has_attached_progs = cgroup_has_attached_progs(cgroup_fd); 2591162f844SHechao Li if (has_attached_progs < 0) { 2602058b383SRoman Gushchin p_err("can't query bpf programs attached to %s: %s", 2612058b383SRoman Gushchin fpath, strerror(errno)); 2622058b383SRoman Gushchin close(cgroup_fd); 2632058b383SRoman Gushchin return SHOW_TREE_FN_ERR; 2641162f844SHechao Li } else if (!has_attached_progs) { 2652058b383SRoman Gushchin close(cgroup_fd); 2662058b383SRoman Gushchin return 0; 2672058b383SRoman Gushchin } 2682058b383SRoman Gushchin 2692058b383SRoman Gushchin if (json_output) { 2702058b383SRoman Gushchin jsonw_start_object(json_wtr); 2712058b383SRoman Gushchin jsonw_string_field(json_wtr, "cgroup", fpath); 2722058b383SRoman Gushchin jsonw_name(json_wtr, "programs"); 2732058b383SRoman Gushchin jsonw_start_array(json_wtr); 2742058b383SRoman Gushchin } else { 2752058b383SRoman Gushchin printf("%s\n", fpath); 2762058b383SRoman Gushchin } 2772058b383SRoman Gushchin 2782058b383SRoman Gushchin for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) 2792058b383SRoman Gushchin show_attached_bpf_progs(cgroup_fd, type, ftw->level); 2802058b383SRoman Gushchin 28139c9f106SQuentin Monnet if (errno == EINVAL) 28239c9f106SQuentin Monnet /* Last attach type does not support query. 28339c9f106SQuentin Monnet * Do not report an error for this, especially because batch 28439c9f106SQuentin Monnet * mode would stop processing commands. 28539c9f106SQuentin Monnet */ 28639c9f106SQuentin Monnet errno = 0; 28739c9f106SQuentin Monnet 2882058b383SRoman Gushchin if (json_output) { 2892058b383SRoman Gushchin jsonw_end_array(json_wtr); 2902058b383SRoman Gushchin jsonw_end_object(json_wtr); 2912058b383SRoman Gushchin } 2922058b383SRoman Gushchin 2932058b383SRoman Gushchin close(cgroup_fd); 2942058b383SRoman Gushchin 2952058b383SRoman Gushchin return 0; 2962058b383SRoman Gushchin } 2972058b383SRoman Gushchin 2982058b383SRoman Gushchin static char *find_cgroup_root(void) 2992058b383SRoman Gushchin { 3002058b383SRoman Gushchin struct mntent *mnt; 3012058b383SRoman Gushchin FILE *f; 3022058b383SRoman Gushchin 3032058b383SRoman Gushchin f = fopen("/proc/mounts", "r"); 3042058b383SRoman Gushchin if (f == NULL) 3052058b383SRoman Gushchin return NULL; 3062058b383SRoman Gushchin 3072058b383SRoman Gushchin while ((mnt = getmntent(f))) { 3082058b383SRoman Gushchin if (strcmp(mnt->mnt_type, "cgroup2") == 0) { 3092058b383SRoman Gushchin fclose(f); 3102058b383SRoman Gushchin return strdup(mnt->mnt_dir); 3112058b383SRoman Gushchin } 3122058b383SRoman Gushchin } 3132058b383SRoman Gushchin 3142058b383SRoman Gushchin fclose(f); 3152058b383SRoman Gushchin return NULL; 3162058b383SRoman Gushchin } 3172058b383SRoman Gushchin 3182058b383SRoman Gushchin static int do_show_tree(int argc, char **argv) 3192058b383SRoman Gushchin { 320a98bf573SJakub Kicinski char *cgroup_root, *cgroup_alloced = NULL; 3212058b383SRoman Gushchin int ret; 3222058b383SRoman Gushchin 323a98bf573SJakub Kicinski query_flags = 0; 324a98bf573SJakub Kicinski 325a98bf573SJakub Kicinski if (!argc) { 326a98bf573SJakub Kicinski cgroup_alloced = find_cgroup_root(); 327a98bf573SJakub Kicinski if (!cgroup_alloced) { 3282058b383SRoman Gushchin p_err("cgroup v2 isn't mounted"); 3292058b383SRoman Gushchin return -1; 3302058b383SRoman Gushchin } 331a98bf573SJakub Kicinski cgroup_root = cgroup_alloced; 332a98bf573SJakub Kicinski } else { 333a98bf573SJakub Kicinski cgroup_root = GET_ARG(); 334a98bf573SJakub Kicinski 335a98bf573SJakub Kicinski while (argc) { 336a98bf573SJakub Kicinski if (is_prefix(*argv, "effective")) { 337a98bf573SJakub Kicinski if (query_flags & BPF_F_QUERY_EFFECTIVE) { 338a98bf573SJakub Kicinski p_err("duplicated argument: %s", *argv); 3392058b383SRoman Gushchin return -1; 3402058b383SRoman Gushchin } 341a98bf573SJakub Kicinski query_flags |= BPF_F_QUERY_EFFECTIVE; 342a98bf573SJakub Kicinski NEXT_ARG(); 343a98bf573SJakub Kicinski } else { 344a98bf573SJakub Kicinski p_err("expected no more arguments, 'effective', got: '%s'?", 345a98bf573SJakub Kicinski *argv); 346a98bf573SJakub Kicinski return -1; 347a98bf573SJakub Kicinski } 348a98bf573SJakub Kicinski } 349a98bf573SJakub Kicinski } 3502058b383SRoman Gushchin 3512058b383SRoman Gushchin if (json_output) 3522058b383SRoman Gushchin jsonw_start_array(json_wtr); 3532058b383SRoman Gushchin else 3542058b383SRoman Gushchin printf("%s\n" 3552058b383SRoman Gushchin "%-8s %-15s %-15s %-15s\n", 3562058b383SRoman Gushchin "CgroupPath", 3572058b383SRoman Gushchin "ID", "AttachType", "AttachFlags", "Name"); 3582058b383SRoman Gushchin 3592058b383SRoman Gushchin switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) { 3602058b383SRoman Gushchin case NFTW_ERR: 3612058b383SRoman Gushchin p_err("can't iterate over %s: %s", cgroup_root, 3622058b383SRoman Gushchin strerror(errno)); 3632058b383SRoman Gushchin ret = -1; 3642058b383SRoman Gushchin break; 3652058b383SRoman Gushchin case SHOW_TREE_FN_ERR: 3662058b383SRoman Gushchin ret = -1; 3672058b383SRoman Gushchin break; 3682058b383SRoman Gushchin default: 3692058b383SRoman Gushchin ret = 0; 3702058b383SRoman Gushchin } 3712058b383SRoman Gushchin 3722058b383SRoman Gushchin if (json_output) 3732058b383SRoman Gushchin jsonw_end_array(json_wtr); 3742058b383SRoman Gushchin 375a98bf573SJakub Kicinski free(cgroup_alloced); 3762058b383SRoman Gushchin 3772058b383SRoman Gushchin return ret; 3782058b383SRoman Gushchin } 3792058b383SRoman Gushchin 3805ccda64dSRoman Gushchin static int do_attach(int argc, char **argv) 3815ccda64dSRoman Gushchin { 3825ccda64dSRoman Gushchin enum bpf_attach_type attach_type; 3835ccda64dSRoman Gushchin int cgroup_fd, prog_fd; 3845ccda64dSRoman Gushchin int attach_flags = 0; 3855ccda64dSRoman Gushchin int ret = -1; 3865ccda64dSRoman Gushchin int i; 3875ccda64dSRoman Gushchin 3885ccda64dSRoman Gushchin if (argc < 4) { 389b4fac96dSJakub Kicinski p_err("too few parameters for cgroup attach"); 3905ccda64dSRoman Gushchin goto exit; 3915ccda64dSRoman Gushchin } 3925ccda64dSRoman Gushchin 3935ccda64dSRoman Gushchin cgroup_fd = open(argv[0], O_RDONLY); 3945ccda64dSRoman Gushchin if (cgroup_fd < 0) { 3956c6874f4SJakub Kicinski p_err("can't open cgroup %s", argv[0]); 3965ccda64dSRoman Gushchin goto exit; 3975ccda64dSRoman Gushchin } 3985ccda64dSRoman Gushchin 3995ccda64dSRoman Gushchin attach_type = parse_attach_type(argv[1]); 4005ccda64dSRoman Gushchin if (attach_type == __MAX_BPF_ATTACH_TYPE) { 401b4fac96dSJakub Kicinski p_err("invalid attach type"); 4025ccda64dSRoman Gushchin goto exit_cgroup; 4035ccda64dSRoman Gushchin } 4045ccda64dSRoman Gushchin 4055ccda64dSRoman Gushchin argc -= 2; 4065ccda64dSRoman Gushchin argv = &argv[2]; 4075ccda64dSRoman Gushchin prog_fd = prog_parse_fd(&argc, &argv); 4085ccda64dSRoman Gushchin if (prog_fd < 0) 4095ccda64dSRoman Gushchin goto exit_cgroup; 4105ccda64dSRoman Gushchin 4115ccda64dSRoman Gushchin for (i = 0; i < argc; i++) { 4125ccda64dSRoman Gushchin if (is_prefix(argv[i], "multi")) { 4135ccda64dSRoman Gushchin attach_flags |= BPF_F_ALLOW_MULTI; 4145ccda64dSRoman Gushchin } else if (is_prefix(argv[i], "override")) { 4155ccda64dSRoman Gushchin attach_flags |= BPF_F_ALLOW_OVERRIDE; 4165ccda64dSRoman Gushchin } else { 417b4fac96dSJakub Kicinski p_err("unknown option: %s", argv[i]); 4185ccda64dSRoman Gushchin goto exit_cgroup; 4195ccda64dSRoman Gushchin } 4205ccda64dSRoman Gushchin } 4215ccda64dSRoman Gushchin 4225ccda64dSRoman Gushchin if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) { 4235ccda64dSRoman Gushchin p_err("failed to attach program"); 4245ccda64dSRoman Gushchin goto exit_prog; 4255ccda64dSRoman Gushchin } 4265ccda64dSRoman Gushchin 4275ccda64dSRoman Gushchin if (json_output) 4285ccda64dSRoman Gushchin jsonw_null(json_wtr); 4295ccda64dSRoman Gushchin 4305ccda64dSRoman Gushchin ret = 0; 4315ccda64dSRoman Gushchin 4325ccda64dSRoman Gushchin exit_prog: 4335ccda64dSRoman Gushchin close(prog_fd); 4345ccda64dSRoman Gushchin exit_cgroup: 4355ccda64dSRoman Gushchin close(cgroup_fd); 4365ccda64dSRoman Gushchin exit: 4375ccda64dSRoman Gushchin return ret; 4385ccda64dSRoman Gushchin } 4395ccda64dSRoman Gushchin 4405ccda64dSRoman Gushchin static int do_detach(int argc, char **argv) 4415ccda64dSRoman Gushchin { 4425ccda64dSRoman Gushchin enum bpf_attach_type attach_type; 4435ccda64dSRoman Gushchin int prog_fd, cgroup_fd; 4445ccda64dSRoman Gushchin int ret = -1; 4455ccda64dSRoman Gushchin 4465ccda64dSRoman Gushchin if (argc < 4) { 447b4fac96dSJakub Kicinski p_err("too few parameters for cgroup detach"); 4485ccda64dSRoman Gushchin goto exit; 4495ccda64dSRoman Gushchin } 4505ccda64dSRoman Gushchin 4515ccda64dSRoman Gushchin cgroup_fd = open(argv[0], O_RDONLY); 4525ccda64dSRoman Gushchin if (cgroup_fd < 0) { 4536c6874f4SJakub Kicinski p_err("can't open cgroup %s", argv[0]); 4545ccda64dSRoman Gushchin goto exit; 4555ccda64dSRoman Gushchin } 4565ccda64dSRoman Gushchin 4575ccda64dSRoman Gushchin attach_type = parse_attach_type(argv[1]); 4585ccda64dSRoman Gushchin if (attach_type == __MAX_BPF_ATTACH_TYPE) { 4595ccda64dSRoman Gushchin p_err("invalid attach type"); 4605ccda64dSRoman Gushchin goto exit_cgroup; 4615ccda64dSRoman Gushchin } 4625ccda64dSRoman Gushchin 4635ccda64dSRoman Gushchin argc -= 2; 4645ccda64dSRoman Gushchin argv = &argv[2]; 4655ccda64dSRoman Gushchin prog_fd = prog_parse_fd(&argc, &argv); 4665ccda64dSRoman Gushchin if (prog_fd < 0) 4675ccda64dSRoman Gushchin goto exit_cgroup; 4685ccda64dSRoman Gushchin 4695ccda64dSRoman Gushchin if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) { 4705ccda64dSRoman Gushchin p_err("failed to detach program"); 4715ccda64dSRoman Gushchin goto exit_prog; 4725ccda64dSRoman Gushchin } 4735ccda64dSRoman Gushchin 4745ccda64dSRoman Gushchin if (json_output) 4755ccda64dSRoman Gushchin jsonw_null(json_wtr); 4765ccda64dSRoman Gushchin 4775ccda64dSRoman Gushchin ret = 0; 4785ccda64dSRoman Gushchin 4795ccda64dSRoman Gushchin exit_prog: 4805ccda64dSRoman Gushchin close(prog_fd); 4815ccda64dSRoman Gushchin exit_cgroup: 4825ccda64dSRoman Gushchin close(cgroup_fd); 4835ccda64dSRoman Gushchin exit: 4845ccda64dSRoman Gushchin return ret; 4855ccda64dSRoman Gushchin } 4865ccda64dSRoman Gushchin 4875ccda64dSRoman Gushchin static int do_help(int argc, char **argv) 4885ccda64dSRoman Gushchin { 4895ccda64dSRoman Gushchin if (json_output) { 4905ccda64dSRoman Gushchin jsonw_null(json_wtr); 4915ccda64dSRoman Gushchin return 0; 4925ccda64dSRoman Gushchin } 4935ccda64dSRoman Gushchin 4945ccda64dSRoman Gushchin fprintf(stderr, 49590040351SQuentin Monnet "Usage: %1$s %2$s { show | list } CGROUP [**effective**]\n" 49690040351SQuentin Monnet " %1$s %2$s tree [CGROUP_ROOT] [**effective**]\n" 49790040351SQuentin Monnet " %1$s %2$s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" 49890040351SQuentin Monnet " %1$s %2$s detach CGROUP ATTACH_TYPE PROG\n" 49990040351SQuentin Monnet " %1$s %2$s help\n" 5005ccda64dSRoman Gushchin "\n" 501393de512SAndrey Ignatov HELP_SPEC_ATTACH_TYPES "\n" 5025ccda64dSRoman Gushchin " " HELP_SPEC_ATTACH_FLAGS "\n" 5035ccda64dSRoman Gushchin " " HELP_SPEC_PROGRAM "\n" 504c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 505*8cc8c635SQuentin Monnet " {-f|--bpffs} }\n" 5065ccda64dSRoman Gushchin "", 50790040351SQuentin Monnet bin_name, argv[-2]); 5085ccda64dSRoman Gushchin 5095ccda64dSRoman Gushchin return 0; 5105ccda64dSRoman Gushchin } 5115ccda64dSRoman Gushchin 5125ccda64dSRoman Gushchin static const struct cmd cmds[] = { 5136ebe6dbdSJakub Kicinski { "show", do_show }, 51465b875bcSJakub Kicinski { "list", do_show }, 5152058b383SRoman Gushchin { "tree", do_show_tree }, 5165ccda64dSRoman Gushchin { "attach", do_attach }, 5175ccda64dSRoman Gushchin { "detach", do_detach }, 5185ccda64dSRoman Gushchin { "help", do_help }, 5195ccda64dSRoman Gushchin { 0 } 5205ccda64dSRoman Gushchin }; 5215ccda64dSRoman Gushchin 5225ccda64dSRoman Gushchin int do_cgroup(int argc, char **argv) 5235ccda64dSRoman Gushchin { 5245ccda64dSRoman Gushchin return cmd_select(cmds, argc, argv, do_help); 5255ccda64dSRoman Gushchin } 526