.. | .. |
---|
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 | } |
---|