| .. | .. |
|---|
| 1 | | -// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
|---|
| 2 | 2 | // Copyright (C) 2017 Facebook |
|---|
| 3 | 3 | // Author: Roman Gushchin <guro@fb.com> |
|---|
| 4 | 4 | |
|---|
| .. | .. |
|---|
| 14 | 14 | #include <sys/types.h> |
|---|
| 15 | 15 | #include <unistd.h> |
|---|
| 16 | 16 | |
|---|
| 17 | | -#include <bpf.h> |
|---|
| 17 | +#include <bpf/bpf.h> |
|---|
| 18 | 18 | |
|---|
| 19 | 19 | #include "main.h" |
|---|
| 20 | 20 | |
|---|
| .. | .. |
|---|
| 25 | 25 | " ATTACH_TYPE := { ingress | egress | sock_create |\n" \ |
|---|
| 26 | 26 | " sock_ops | device | bind4 | bind6 |\n" \ |
|---|
| 27 | 27 | " post_bind4 | post_bind6 | connect4 |\n" \ |
|---|
| 28 | | - " connect6 | sendmsg4 | sendmsg6 }" |
|---|
| 28 | + " connect6 | getpeername4 | getpeername6 |\n" \ |
|---|
| 29 | + " getsockname4 | getsockname6 | sendmsg4 |\n" \ |
|---|
| 30 | + " sendmsg6 | recvmsg4 | recvmsg6 |\n" \ |
|---|
| 31 | + " sysctl | getsockopt | setsockopt |\n" \ |
|---|
| 32 | + " sock_release }" |
|---|
| 29 | 33 | |
|---|
| 30 | | -static const char * const attach_type_strings[] = { |
|---|
| 31 | | - [BPF_CGROUP_INET_INGRESS] = "ingress", |
|---|
| 32 | | - [BPF_CGROUP_INET_EGRESS] = "egress", |
|---|
| 33 | | - [BPF_CGROUP_INET_SOCK_CREATE] = "sock_create", |
|---|
| 34 | | - [BPF_CGROUP_SOCK_OPS] = "sock_ops", |
|---|
| 35 | | - [BPF_CGROUP_DEVICE] = "device", |
|---|
| 36 | | - [BPF_CGROUP_INET4_BIND] = "bind4", |
|---|
| 37 | | - [BPF_CGROUP_INET6_BIND] = "bind6", |
|---|
| 38 | | - [BPF_CGROUP_INET4_CONNECT] = "connect4", |
|---|
| 39 | | - [BPF_CGROUP_INET6_CONNECT] = "connect6", |
|---|
| 40 | | - [BPF_CGROUP_INET4_POST_BIND] = "post_bind4", |
|---|
| 41 | | - [BPF_CGROUP_INET6_POST_BIND] = "post_bind6", |
|---|
| 42 | | - [BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4", |
|---|
| 43 | | - [BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6", |
|---|
| 44 | | - [__MAX_BPF_ATTACH_TYPE] = NULL, |
|---|
| 45 | | -}; |
|---|
| 34 | +static unsigned int query_flags; |
|---|
| 46 | 35 | |
|---|
| 47 | 36 | static enum bpf_attach_type parse_attach_type(const char *str) |
|---|
| 48 | 37 | { |
|---|
| 49 | 38 | enum bpf_attach_type type; |
|---|
| 50 | 39 | |
|---|
| 51 | 40 | for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { |
|---|
| 52 | | - if (attach_type_strings[type] && |
|---|
| 53 | | - is_prefix(str, attach_type_strings[type])) |
|---|
| 41 | + if (attach_type_name[type] && |
|---|
| 42 | + is_prefix(str, attach_type_name[type])) |
|---|
| 54 | 43 | return type; |
|---|
| 55 | 44 | } |
|---|
| 56 | 45 | |
|---|
| 57 | 46 | return __MAX_BPF_ATTACH_TYPE; |
|---|
| 58 | 47 | } |
|---|
| 59 | 48 | |
|---|
| 60 | | -static int show_bpf_prog(int id, const char *attach_type_str, |
|---|
| 49 | +static int show_bpf_prog(int id, enum bpf_attach_type attach_type, |
|---|
| 61 | 50 | const char *attach_flags_str, |
|---|
| 62 | 51 | int level) |
|---|
| 63 | 52 | { |
|---|
| .. | .. |
|---|
| 77 | 66 | if (json_output) { |
|---|
| 78 | 67 | jsonw_start_object(json_wtr); |
|---|
| 79 | 68 | jsonw_uint_field(json_wtr, "id", info.id); |
|---|
| 80 | | - jsonw_string_field(json_wtr, "attach_type", |
|---|
| 81 | | - attach_type_str); |
|---|
| 69 | + if (attach_type < ARRAY_SIZE(attach_type_name)) |
|---|
| 70 | + jsonw_string_field(json_wtr, "attach_type", |
|---|
| 71 | + attach_type_name[attach_type]); |
|---|
| 72 | + else |
|---|
| 73 | + jsonw_uint_field(json_wtr, "attach_type", attach_type); |
|---|
| 82 | 74 | jsonw_string_field(json_wtr, "attach_flags", |
|---|
| 83 | 75 | attach_flags_str); |
|---|
| 84 | 76 | jsonw_string_field(json_wtr, "name", info.name); |
|---|
| 85 | 77 | jsonw_end_object(json_wtr); |
|---|
| 86 | 78 | } else { |
|---|
| 87 | | - printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "", |
|---|
| 88 | | - info.id, |
|---|
| 89 | | - attach_type_str, |
|---|
| 90 | | - attach_flags_str, |
|---|
| 91 | | - info.name); |
|---|
| 79 | + printf("%s%-8u ", level ? " " : "", info.id); |
|---|
| 80 | + if (attach_type < ARRAY_SIZE(attach_type_name)) |
|---|
| 81 | + printf("%-15s", attach_type_name[attach_type]); |
|---|
| 82 | + else |
|---|
| 83 | + printf("type %-10u", attach_type); |
|---|
| 84 | + printf(" %-15s %-15s\n", attach_flags_str, info.name); |
|---|
| 92 | 85 | } |
|---|
| 93 | 86 | |
|---|
| 94 | 87 | close(prog_fd); |
|---|
| .. | .. |
|---|
| 100 | 93 | __u32 prog_cnt = 0; |
|---|
| 101 | 94 | int ret; |
|---|
| 102 | 95 | |
|---|
| 103 | | - ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt); |
|---|
| 96 | + ret = bpf_prog_query(cgroup_fd, type, query_flags, NULL, |
|---|
| 97 | + NULL, &prog_cnt); |
|---|
| 104 | 98 | if (ret) |
|---|
| 105 | 99 | return -1; |
|---|
| 106 | 100 | |
|---|
| 107 | 101 | return prog_cnt; |
|---|
| 108 | 102 | } |
|---|
| 109 | 103 | |
|---|
| 104 | +static int cgroup_has_attached_progs(int cgroup_fd) |
|---|
| 105 | +{ |
|---|
| 106 | + enum bpf_attach_type type; |
|---|
| 107 | + bool no_prog = true; |
|---|
| 108 | + |
|---|
| 109 | + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { |
|---|
| 110 | + int count = count_attached_bpf_progs(cgroup_fd, type); |
|---|
| 111 | + |
|---|
| 112 | + if (count < 0 && errno != EINVAL) |
|---|
| 113 | + return -1; |
|---|
| 114 | + |
|---|
| 115 | + if (count > 0) { |
|---|
| 116 | + no_prog = false; |
|---|
| 117 | + break; |
|---|
| 118 | + } |
|---|
| 119 | + } |
|---|
| 120 | + |
|---|
| 121 | + return no_prog ? 0 : 1; |
|---|
| 122 | +} |
|---|
| 110 | 123 | static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, |
|---|
| 111 | 124 | int level) |
|---|
| 112 | 125 | { |
|---|
| 126 | + const char *attach_flags_str; |
|---|
| 113 | 127 | __u32 prog_ids[1024] = {0}; |
|---|
| 114 | | - char *attach_flags_str; |
|---|
| 115 | 128 | __u32 prog_cnt, iter; |
|---|
| 116 | 129 | __u32 attach_flags; |
|---|
| 117 | 130 | char buf[32]; |
|---|
| 118 | 131 | int ret; |
|---|
| 119 | 132 | |
|---|
| 120 | 133 | prog_cnt = ARRAY_SIZE(prog_ids); |
|---|
| 121 | | - ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids, |
|---|
| 122 | | - &prog_cnt); |
|---|
| 134 | + ret = bpf_prog_query(cgroup_fd, type, query_flags, &attach_flags, |
|---|
| 135 | + prog_ids, &prog_cnt); |
|---|
| 123 | 136 | if (ret) |
|---|
| 124 | 137 | return ret; |
|---|
| 125 | 138 | |
|---|
| .. | .. |
|---|
| 142 | 155 | } |
|---|
| 143 | 156 | |
|---|
| 144 | 157 | for (iter = 0; iter < prog_cnt; iter++) |
|---|
| 145 | | - show_bpf_prog(prog_ids[iter], attach_type_strings[type], |
|---|
| 158 | + show_bpf_prog(prog_ids[iter], type, |
|---|
| 146 | 159 | attach_flags_str, level); |
|---|
| 147 | 160 | |
|---|
| 148 | 161 | return 0; |
|---|
| .. | .. |
|---|
| 151 | 164 | static int do_show(int argc, char **argv) |
|---|
| 152 | 165 | { |
|---|
| 153 | 166 | enum bpf_attach_type type; |
|---|
| 167 | + int has_attached_progs; |
|---|
| 168 | + const char *path; |
|---|
| 154 | 169 | int cgroup_fd; |
|---|
| 155 | 170 | int ret = -1; |
|---|
| 156 | 171 | |
|---|
| 157 | | - if (argc < 1) { |
|---|
| 158 | | - p_err("too few parameters for cgroup show"); |
|---|
| 159 | | - goto exit; |
|---|
| 160 | | - } else if (argc > 1) { |
|---|
| 161 | | - p_err("too many parameters for cgroup show"); |
|---|
| 172 | + query_flags = 0; |
|---|
| 173 | + |
|---|
| 174 | + if (!REQ_ARGS(1)) |
|---|
| 175 | + return -1; |
|---|
| 176 | + path = GET_ARG(); |
|---|
| 177 | + |
|---|
| 178 | + while (argc) { |
|---|
| 179 | + if (is_prefix(*argv, "effective")) { |
|---|
| 180 | + if (query_flags & BPF_F_QUERY_EFFECTIVE) { |
|---|
| 181 | + p_err("duplicated argument: %s", *argv); |
|---|
| 182 | + return -1; |
|---|
| 183 | + } |
|---|
| 184 | + query_flags |= BPF_F_QUERY_EFFECTIVE; |
|---|
| 185 | + NEXT_ARG(); |
|---|
| 186 | + } else { |
|---|
| 187 | + p_err("expected no more arguments, 'effective', got: '%s'?", |
|---|
| 188 | + *argv); |
|---|
| 189 | + return -1; |
|---|
| 190 | + } |
|---|
| 191 | + } |
|---|
| 192 | + |
|---|
| 193 | + cgroup_fd = open(path, O_RDONLY); |
|---|
| 194 | + if (cgroup_fd < 0) { |
|---|
| 195 | + p_err("can't open cgroup %s", path); |
|---|
| 162 | 196 | goto exit; |
|---|
| 163 | 197 | } |
|---|
| 164 | 198 | |
|---|
| 165 | | - cgroup_fd = open(argv[0], O_RDONLY); |
|---|
| 166 | | - if (cgroup_fd < 0) { |
|---|
| 167 | | - p_err("can't open cgroup %s", argv[0]); |
|---|
| 168 | | - goto exit; |
|---|
| 199 | + has_attached_progs = cgroup_has_attached_progs(cgroup_fd); |
|---|
| 200 | + if (has_attached_progs < 0) { |
|---|
| 201 | + p_err("can't query bpf programs attached to %s: %s", |
|---|
| 202 | + path, strerror(errno)); |
|---|
| 203 | + goto exit_cgroup; |
|---|
| 204 | + } else if (!has_attached_progs) { |
|---|
| 205 | + ret = 0; |
|---|
| 206 | + goto exit_cgroup; |
|---|
| 169 | 207 | } |
|---|
| 170 | 208 | |
|---|
| 171 | 209 | if (json_output) |
|---|
| .. | .. |
|---|
| 188 | 226 | if (json_output) |
|---|
| 189 | 227 | jsonw_end_array(json_wtr); |
|---|
| 190 | 228 | |
|---|
| 229 | +exit_cgroup: |
|---|
| 191 | 230 | close(cgroup_fd); |
|---|
| 192 | 231 | exit: |
|---|
| 193 | 232 | return ret; |
|---|
| .. | .. |
|---|
| 204 | 243 | int typeflag, struct FTW *ftw) |
|---|
| 205 | 244 | { |
|---|
| 206 | 245 | enum bpf_attach_type type; |
|---|
| 207 | | - bool skip = true; |
|---|
| 246 | + int has_attached_progs; |
|---|
| 208 | 247 | int cgroup_fd; |
|---|
| 209 | 248 | |
|---|
| 210 | 249 | if (typeflag != FTW_D) |
|---|
| .. | .. |
|---|
| 216 | 255 | return SHOW_TREE_FN_ERR; |
|---|
| 217 | 256 | } |
|---|
| 218 | 257 | |
|---|
| 219 | | - for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { |
|---|
| 220 | | - int count = count_attached_bpf_progs(cgroup_fd, type); |
|---|
| 221 | | - |
|---|
| 222 | | - if (count < 0 && errno != EINVAL) { |
|---|
| 223 | | - p_err("can't query bpf programs attached to %s: %s", |
|---|
| 224 | | - fpath, strerror(errno)); |
|---|
| 225 | | - close(cgroup_fd); |
|---|
| 226 | | - return SHOW_TREE_FN_ERR; |
|---|
| 227 | | - } |
|---|
| 228 | | - if (count > 0) { |
|---|
| 229 | | - skip = false; |
|---|
| 230 | | - break; |
|---|
| 231 | | - } |
|---|
| 232 | | - } |
|---|
| 233 | | - |
|---|
| 234 | | - if (skip) { |
|---|
| 258 | + has_attached_progs = cgroup_has_attached_progs(cgroup_fd); |
|---|
| 259 | + if (has_attached_progs < 0) { |
|---|
| 260 | + p_err("can't query bpf programs attached to %s: %s", |
|---|
| 261 | + fpath, strerror(errno)); |
|---|
| 262 | + close(cgroup_fd); |
|---|
| 263 | + return SHOW_TREE_FN_ERR; |
|---|
| 264 | + } else if (!has_attached_progs) { |
|---|
| 235 | 265 | close(cgroup_fd); |
|---|
| 236 | 266 | return 0; |
|---|
| 237 | 267 | } |
|---|
| .. | .. |
|---|
| 247 | 277 | |
|---|
| 248 | 278 | for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) |
|---|
| 249 | 279 | show_attached_bpf_progs(cgroup_fd, type, ftw->level); |
|---|
| 280 | + |
|---|
| 281 | + if (errno == EINVAL) |
|---|
| 282 | + /* Last attach type does not support query. |
|---|
| 283 | + * Do not report an error for this, especially because batch |
|---|
| 284 | + * mode would stop processing commands. |
|---|
| 285 | + */ |
|---|
| 286 | + errno = 0; |
|---|
| 250 | 287 | |
|---|
| 251 | 288 | if (json_output) { |
|---|
| 252 | 289 | jsonw_end_array(json_wtr); |
|---|
| .. | .. |
|---|
| 280 | 317 | |
|---|
| 281 | 318 | static int do_show_tree(int argc, char **argv) |
|---|
| 282 | 319 | { |
|---|
| 283 | | - char *cgroup_root; |
|---|
| 320 | + char *cgroup_root, *cgroup_alloced = NULL; |
|---|
| 284 | 321 | int ret; |
|---|
| 285 | 322 | |
|---|
| 286 | | - switch (argc) { |
|---|
| 287 | | - case 0: |
|---|
| 288 | | - cgroup_root = find_cgroup_root(); |
|---|
| 289 | | - if (!cgroup_root) { |
|---|
| 323 | + query_flags = 0; |
|---|
| 324 | + |
|---|
| 325 | + if (!argc) { |
|---|
| 326 | + cgroup_alloced = find_cgroup_root(); |
|---|
| 327 | + if (!cgroup_alloced) { |
|---|
| 290 | 328 | p_err("cgroup v2 isn't mounted"); |
|---|
| 291 | 329 | return -1; |
|---|
| 292 | 330 | } |
|---|
| 293 | | - break; |
|---|
| 294 | | - case 1: |
|---|
| 295 | | - cgroup_root = argv[0]; |
|---|
| 296 | | - break; |
|---|
| 297 | | - default: |
|---|
| 298 | | - p_err("too many parameters for cgroup tree"); |
|---|
| 299 | | - return -1; |
|---|
| 300 | | - } |
|---|
| 331 | + cgroup_root = cgroup_alloced; |
|---|
| 332 | + } else { |
|---|
| 333 | + cgroup_root = GET_ARG(); |
|---|
| 301 | 334 | |
|---|
| 335 | + while (argc) { |
|---|
| 336 | + if (is_prefix(*argv, "effective")) { |
|---|
| 337 | + if (query_flags & BPF_F_QUERY_EFFECTIVE) { |
|---|
| 338 | + p_err("duplicated argument: %s", *argv); |
|---|
| 339 | + return -1; |
|---|
| 340 | + } |
|---|
| 341 | + query_flags |= BPF_F_QUERY_EFFECTIVE; |
|---|
| 342 | + NEXT_ARG(); |
|---|
| 343 | + } else { |
|---|
| 344 | + p_err("expected no more arguments, 'effective', got: '%s'?", |
|---|
| 345 | + *argv); |
|---|
| 346 | + return -1; |
|---|
| 347 | + } |
|---|
| 348 | + } |
|---|
| 349 | + } |
|---|
| 302 | 350 | |
|---|
| 303 | 351 | if (json_output) |
|---|
| 304 | 352 | jsonw_start_array(json_wtr); |
|---|
| .. | .. |
|---|
| 324 | 372 | if (json_output) |
|---|
| 325 | 373 | jsonw_end_array(json_wtr); |
|---|
| 326 | 374 | |
|---|
| 327 | | - if (argc == 0) |
|---|
| 328 | | - free(cgroup_root); |
|---|
| 375 | + free(cgroup_alloced); |
|---|
| 329 | 376 | |
|---|
| 330 | 377 | return ret; |
|---|
| 331 | 378 | } |
|---|
| .. | .. |
|---|
| 445 | 492 | } |
|---|
| 446 | 493 | |
|---|
| 447 | 494 | fprintf(stderr, |
|---|
| 448 | | - "Usage: %s %s { show | list } CGROUP\n" |
|---|
| 449 | | - " %s %s tree [CGROUP_ROOT]\n" |
|---|
| 450 | | - " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" |
|---|
| 451 | | - " %s %s detach CGROUP ATTACH_TYPE PROG\n" |
|---|
| 452 | | - " %s %s help\n" |
|---|
| 495 | + "Usage: %1$s %2$s { show | list } CGROUP [**effective**]\n" |
|---|
| 496 | + " %1$s %2$s tree [CGROUP_ROOT] [**effective**]\n" |
|---|
| 497 | + " %1$s %2$s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" |
|---|
| 498 | + " %1$s %2$s detach CGROUP ATTACH_TYPE PROG\n" |
|---|
| 499 | + " %1$s %2$s help\n" |
|---|
| 453 | 500 | "\n" |
|---|
| 454 | 501 | HELP_SPEC_ATTACH_TYPES "\n" |
|---|
| 455 | 502 | " " HELP_SPEC_ATTACH_FLAGS "\n" |
|---|
| 456 | 503 | " " HELP_SPEC_PROGRAM "\n" |
|---|
| 457 | 504 | " " HELP_SPEC_OPTIONS "\n" |
|---|
| 458 | 505 | "", |
|---|
| 459 | | - bin_name, argv[-2], |
|---|
| 460 | | - bin_name, argv[-2], bin_name, argv[-2], |
|---|
| 461 | | - bin_name, argv[-2], bin_name, argv[-2]); |
|---|
| 506 | + bin_name, argv[-2]); |
|---|
| 462 | 507 | |
|---|
| 463 | 508 | return 0; |
|---|
| 464 | 509 | } |
|---|