1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright (C) 2017 Facebook 3 // Author: Roman Gushchin <guro@fb.com> 4 5 #include <fcntl.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 #include <unistd.h> 11 12 #include <bpf.h> 13 14 #include "main.h" 15 16 #define HELP_SPEC_ATTACH_FLAGS \ 17 "ATTACH_FLAGS := { multi | override }" 18 19 #define HELP_SPEC_ATTACH_TYPES \ 20 "ATTACH_TYPE := { ingress | egress | sock_create | sock_ops | device }" 21 22 static const char * const attach_type_strings[] = { 23 [BPF_CGROUP_INET_INGRESS] = "ingress", 24 [BPF_CGROUP_INET_EGRESS] = "egress", 25 [BPF_CGROUP_INET_SOCK_CREATE] = "sock_create", 26 [BPF_CGROUP_SOCK_OPS] = "sock_ops", 27 [BPF_CGROUP_DEVICE] = "device", 28 [__MAX_BPF_ATTACH_TYPE] = NULL, 29 }; 30 31 static enum bpf_attach_type parse_attach_type(const char *str) 32 { 33 enum bpf_attach_type type; 34 35 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 36 if (attach_type_strings[type] && 37 is_prefix(str, attach_type_strings[type])) 38 return type; 39 } 40 41 return __MAX_BPF_ATTACH_TYPE; 42 } 43 44 static int show_bpf_prog(int id, const char *attach_type_str, 45 const char *attach_flags_str) 46 { 47 struct bpf_prog_info info = {}; 48 __u32 info_len = sizeof(info); 49 int prog_fd; 50 51 prog_fd = bpf_prog_get_fd_by_id(id); 52 if (prog_fd < 0) 53 return -1; 54 55 if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { 56 close(prog_fd); 57 return -1; 58 } 59 60 if (json_output) { 61 jsonw_start_object(json_wtr); 62 jsonw_uint_field(json_wtr, "id", info.id); 63 jsonw_string_field(json_wtr, "attach_type", 64 attach_type_str); 65 jsonw_string_field(json_wtr, "attach_flags", 66 attach_flags_str); 67 jsonw_string_field(json_wtr, "name", info.name); 68 jsonw_end_object(json_wtr); 69 } else { 70 printf("%-8u %-15s %-15s %-15s\n", info.id, 71 attach_type_str, 72 attach_flags_str, 73 info.name); 74 } 75 76 close(prog_fd); 77 return 0; 78 } 79 80 static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) 81 { 82 __u32 prog_ids[1024] = {0}; 83 char *attach_flags_str; 84 __u32 prog_cnt, iter; 85 __u32 attach_flags; 86 char buf[32]; 87 int ret; 88 89 prog_cnt = ARRAY_SIZE(prog_ids); 90 ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids, 91 &prog_cnt); 92 if (ret) 93 return ret; 94 95 if (prog_cnt == 0) 96 return 0; 97 98 switch (attach_flags) { 99 case BPF_F_ALLOW_MULTI: 100 attach_flags_str = "multi"; 101 break; 102 case BPF_F_ALLOW_OVERRIDE: 103 attach_flags_str = "override"; 104 break; 105 case 0: 106 attach_flags_str = ""; 107 break; 108 default: 109 snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags); 110 attach_flags_str = buf; 111 } 112 113 for (iter = 0; iter < prog_cnt; iter++) 114 show_bpf_prog(prog_ids[iter], attach_type_strings[type], 115 attach_flags_str); 116 117 return 0; 118 } 119 120 static int do_show(int argc, char **argv) 121 { 122 enum bpf_attach_type type; 123 int cgroup_fd; 124 int ret = -1; 125 126 if (argc < 1) { 127 p_err("too few parameters for cgroup show"); 128 goto exit; 129 } else if (argc > 1) { 130 p_err("too many parameters for cgroup show"); 131 goto exit; 132 } 133 134 cgroup_fd = open(argv[0], O_RDONLY); 135 if (cgroup_fd < 0) { 136 p_err("can't open cgroup %s", argv[1]); 137 goto exit; 138 } 139 140 if (json_output) 141 jsonw_start_array(json_wtr); 142 else 143 printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType", 144 "AttachFlags", "Name"); 145 146 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 147 /* 148 * Not all attach types may be supported, so it's expected, 149 * that some requests will fail. 150 * If we were able to get the show for at least one 151 * attach type, let's return 0. 152 */ 153 if (show_attached_bpf_progs(cgroup_fd, type) == 0) 154 ret = 0; 155 } 156 157 if (json_output) 158 jsonw_end_array(json_wtr); 159 160 close(cgroup_fd); 161 exit: 162 return ret; 163 } 164 165 static int do_attach(int argc, char **argv) 166 { 167 enum bpf_attach_type attach_type; 168 int cgroup_fd, prog_fd; 169 int attach_flags = 0; 170 int ret = -1; 171 int i; 172 173 if (argc < 4) { 174 p_err("too few parameters for cgroup attach"); 175 goto exit; 176 } 177 178 cgroup_fd = open(argv[0], O_RDONLY); 179 if (cgroup_fd < 0) { 180 p_err("can't open cgroup %s", argv[1]); 181 goto exit; 182 } 183 184 attach_type = parse_attach_type(argv[1]); 185 if (attach_type == __MAX_BPF_ATTACH_TYPE) { 186 p_err("invalid attach type"); 187 goto exit_cgroup; 188 } 189 190 argc -= 2; 191 argv = &argv[2]; 192 prog_fd = prog_parse_fd(&argc, &argv); 193 if (prog_fd < 0) 194 goto exit_cgroup; 195 196 for (i = 0; i < argc; i++) { 197 if (is_prefix(argv[i], "multi")) { 198 attach_flags |= BPF_F_ALLOW_MULTI; 199 } else if (is_prefix(argv[i], "override")) { 200 attach_flags |= BPF_F_ALLOW_OVERRIDE; 201 } else { 202 p_err("unknown option: %s", argv[i]); 203 goto exit_cgroup; 204 } 205 } 206 207 if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) { 208 p_err("failed to attach program"); 209 goto exit_prog; 210 } 211 212 if (json_output) 213 jsonw_null(json_wtr); 214 215 ret = 0; 216 217 exit_prog: 218 close(prog_fd); 219 exit_cgroup: 220 close(cgroup_fd); 221 exit: 222 return ret; 223 } 224 225 static int do_detach(int argc, char **argv) 226 { 227 enum bpf_attach_type attach_type; 228 int prog_fd, cgroup_fd; 229 int ret = -1; 230 231 if (argc < 4) { 232 p_err("too few parameters for cgroup detach"); 233 goto exit; 234 } 235 236 cgroup_fd = open(argv[0], O_RDONLY); 237 if (cgroup_fd < 0) { 238 p_err("can't open cgroup %s", argv[1]); 239 goto exit; 240 } 241 242 attach_type = parse_attach_type(argv[1]); 243 if (attach_type == __MAX_BPF_ATTACH_TYPE) { 244 p_err("invalid attach type"); 245 goto exit_cgroup; 246 } 247 248 argc -= 2; 249 argv = &argv[2]; 250 prog_fd = prog_parse_fd(&argc, &argv); 251 if (prog_fd < 0) 252 goto exit_cgroup; 253 254 if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) { 255 p_err("failed to detach program"); 256 goto exit_prog; 257 } 258 259 if (json_output) 260 jsonw_null(json_wtr); 261 262 ret = 0; 263 264 exit_prog: 265 close(prog_fd); 266 exit_cgroup: 267 close(cgroup_fd); 268 exit: 269 return ret; 270 } 271 272 static int do_help(int argc, char **argv) 273 { 274 if (json_output) { 275 jsonw_null(json_wtr); 276 return 0; 277 } 278 279 fprintf(stderr, 280 "Usage: %s %s { show | list } CGROUP\n" 281 " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" 282 " %s %s detach CGROUP ATTACH_TYPE PROG\n" 283 " %s %s help\n" 284 "\n" 285 " " HELP_SPEC_ATTACH_TYPES "\n" 286 " " HELP_SPEC_ATTACH_FLAGS "\n" 287 " " HELP_SPEC_PROGRAM "\n" 288 " " HELP_SPEC_OPTIONS "\n" 289 "", 290 bin_name, argv[-2], bin_name, argv[-2], 291 bin_name, argv[-2], bin_name, argv[-2]); 292 293 return 0; 294 } 295 296 static const struct cmd cmds[] = { 297 { "show", do_show }, 298 { "list", do_show }, 299 { "attach", do_attach }, 300 { "detach", do_detach }, 301 { "help", do_help }, 302 { 0 } 303 }; 304 305 int do_cgroup(int argc, char **argv) 306 { 307 return cmd_select(cmds, argc, argv, do_help); 308 } 309