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