1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2020 Facebook */ 3 4 #include <errno.h> 5 #include <linux/err.h> 6 #include <linux/netfilter.h> 7 #include <linux/netfilter_arp.h> 8 #include <linux/perf_event.h> 9 #include <net/if.h> 10 #include <stdio.h> 11 #include <unistd.h> 12 13 #include <bpf/bpf.h> 14 #include <bpf/hashmap.h> 15 16 #include "json_writer.h" 17 #include "main.h" 18 #include "xlated_dumper.h" 19 20 #define PERF_HW_CACHE_LEN 128 21 22 static struct hashmap *link_table; 23 static struct dump_data dd; 24 25 static const char *perf_type_name[PERF_TYPE_MAX] = { 26 [PERF_TYPE_HARDWARE] = "hardware", 27 [PERF_TYPE_SOFTWARE] = "software", 28 [PERF_TYPE_TRACEPOINT] = "tracepoint", 29 [PERF_TYPE_HW_CACHE] = "hw-cache", 30 [PERF_TYPE_RAW] = "raw", 31 [PERF_TYPE_BREAKPOINT] = "breakpoint", 32 }; 33 34 const char *event_symbols_hw[PERF_COUNT_HW_MAX] = { 35 [PERF_COUNT_HW_CPU_CYCLES] = "cpu-cycles", 36 [PERF_COUNT_HW_INSTRUCTIONS] = "instructions", 37 [PERF_COUNT_HW_CACHE_REFERENCES] = "cache-references", 38 [PERF_COUNT_HW_CACHE_MISSES] = "cache-misses", 39 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "branch-instructions", 40 [PERF_COUNT_HW_BRANCH_MISSES] = "branch-misses", 41 [PERF_COUNT_HW_BUS_CYCLES] = "bus-cycles", 42 [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = "stalled-cycles-frontend", 43 [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = "stalled-cycles-backend", 44 [PERF_COUNT_HW_REF_CPU_CYCLES] = "ref-cycles", 45 }; 46 47 const char *event_symbols_sw[PERF_COUNT_SW_MAX] = { 48 [PERF_COUNT_SW_CPU_CLOCK] = "cpu-clock", 49 [PERF_COUNT_SW_TASK_CLOCK] = "task-clock", 50 [PERF_COUNT_SW_PAGE_FAULTS] = "page-faults", 51 [PERF_COUNT_SW_CONTEXT_SWITCHES] = "context-switches", 52 [PERF_COUNT_SW_CPU_MIGRATIONS] = "cpu-migrations", 53 [PERF_COUNT_SW_PAGE_FAULTS_MIN] = "minor-faults", 54 [PERF_COUNT_SW_PAGE_FAULTS_MAJ] = "major-faults", 55 [PERF_COUNT_SW_ALIGNMENT_FAULTS] = "alignment-faults", 56 [PERF_COUNT_SW_EMULATION_FAULTS] = "emulation-faults", 57 [PERF_COUNT_SW_DUMMY] = "dummy", 58 [PERF_COUNT_SW_BPF_OUTPUT] = "bpf-output", 59 [PERF_COUNT_SW_CGROUP_SWITCHES] = "cgroup-switches", 60 }; 61 62 const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] = { 63 [PERF_COUNT_HW_CACHE_L1D] = "L1-dcache", 64 [PERF_COUNT_HW_CACHE_L1I] = "L1-icache", 65 [PERF_COUNT_HW_CACHE_LL] = "LLC", 66 [PERF_COUNT_HW_CACHE_DTLB] = "dTLB", 67 [PERF_COUNT_HW_CACHE_ITLB] = "iTLB", 68 [PERF_COUNT_HW_CACHE_BPU] = "branch", 69 [PERF_COUNT_HW_CACHE_NODE] = "node", 70 }; 71 72 const char *evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] = { 73 [PERF_COUNT_HW_CACHE_OP_READ] = "load", 74 [PERF_COUNT_HW_CACHE_OP_WRITE] = "store", 75 [PERF_COUNT_HW_CACHE_OP_PREFETCH] = "prefetch", 76 }; 77 78 const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] = { 79 [PERF_COUNT_HW_CACHE_RESULT_ACCESS] = "refs", 80 [PERF_COUNT_HW_CACHE_RESULT_MISS] = "misses", 81 }; 82 83 #define perf_event_name(array, id) ({ \ 84 const char *event_str = NULL; \ 85 \ 86 if ((id) < ARRAY_SIZE(array)) \ 87 event_str = array[id]; \ 88 event_str; \ 89 }) 90 91 static int link_parse_fd(int *argc, char ***argv) 92 { 93 int fd; 94 95 if (is_prefix(**argv, "id")) { 96 unsigned int id; 97 char *endptr; 98 99 NEXT_ARGP(); 100 101 id = strtoul(**argv, &endptr, 0); 102 if (*endptr) { 103 p_err("can't parse %s as ID", **argv); 104 return -1; 105 } 106 NEXT_ARGP(); 107 108 fd = bpf_link_get_fd_by_id(id); 109 if (fd < 0) 110 p_err("failed to get link with ID %d: %s", id, strerror(errno)); 111 return fd; 112 } else if (is_prefix(**argv, "pinned")) { 113 char *path; 114 115 NEXT_ARGP(); 116 117 path = **argv; 118 NEXT_ARGP(); 119 120 return open_obj_pinned_any(path, BPF_OBJ_LINK); 121 } 122 123 p_err("expected 'id' or 'pinned', got: '%s'?", **argv); 124 return -1; 125 } 126 127 static void 128 show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr) 129 { 130 const char *link_type_str; 131 132 jsonw_uint_field(wtr, "id", info->id); 133 link_type_str = libbpf_bpf_link_type_str(info->type); 134 if (link_type_str) 135 jsonw_string_field(wtr, "type", link_type_str); 136 else 137 jsonw_uint_field(wtr, "type", info->type); 138 139 jsonw_uint_field(json_wtr, "prog_id", info->prog_id); 140 } 141 142 static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr) 143 { 144 const char *attach_type_str; 145 146 attach_type_str = libbpf_bpf_attach_type_str(attach_type); 147 if (attach_type_str) 148 jsonw_string_field(wtr, "attach_type", attach_type_str); 149 else 150 jsonw_uint_field(wtr, "attach_type", attach_type); 151 } 152 153 static void show_link_ifindex_json(__u32 ifindex, json_writer_t *wtr) 154 { 155 char devname[IF_NAMESIZE] = "(unknown)"; 156 157 if (ifindex) 158 if_indextoname(ifindex, devname); 159 else 160 snprintf(devname, sizeof(devname), "(detached)"); 161 jsonw_string_field(wtr, "devname", devname); 162 jsonw_uint_field(wtr, "ifindex", ifindex); 163 } 164 165 static bool is_iter_map_target(const char *target_name) 166 { 167 return strcmp(target_name, "bpf_map_elem") == 0 || 168 strcmp(target_name, "bpf_sk_storage_map") == 0; 169 } 170 171 static bool is_iter_cgroup_target(const char *target_name) 172 { 173 return strcmp(target_name, "cgroup") == 0; 174 } 175 176 static const char *cgroup_order_string(__u32 order) 177 { 178 switch (order) { 179 case BPF_CGROUP_ITER_ORDER_UNSPEC: 180 return "order_unspec"; 181 case BPF_CGROUP_ITER_SELF_ONLY: 182 return "self_only"; 183 case BPF_CGROUP_ITER_DESCENDANTS_PRE: 184 return "descendants_pre"; 185 case BPF_CGROUP_ITER_DESCENDANTS_POST: 186 return "descendants_post"; 187 case BPF_CGROUP_ITER_ANCESTORS_UP: 188 return "ancestors_up"; 189 default: /* won't happen */ 190 return "unknown"; 191 } 192 } 193 194 static bool is_iter_task_target(const char *target_name) 195 { 196 return strcmp(target_name, "task") == 0 || 197 strcmp(target_name, "task_file") == 0 || 198 strcmp(target_name, "task_vma") == 0; 199 } 200 201 static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr) 202 { 203 const char *target_name = u64_to_ptr(info->iter.target_name); 204 205 jsonw_string_field(wtr, "target_name", target_name); 206 207 if (is_iter_map_target(target_name)) 208 jsonw_uint_field(wtr, "map_id", info->iter.map.map_id); 209 else if (is_iter_task_target(target_name)) { 210 if (info->iter.task.tid) 211 jsonw_uint_field(wtr, "tid", info->iter.task.tid); 212 else if (info->iter.task.pid) 213 jsonw_uint_field(wtr, "pid", info->iter.task.pid); 214 } 215 216 if (is_iter_cgroup_target(target_name)) { 217 jsonw_lluint_field(wtr, "cgroup_id", info->iter.cgroup.cgroup_id); 218 jsonw_string_field(wtr, "order", 219 cgroup_order_string(info->iter.cgroup.order)); 220 } 221 } 222 223 void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr) 224 { 225 jsonw_uint_field(json_wtr, "pf", 226 info->netfilter.pf); 227 jsonw_uint_field(json_wtr, "hook", 228 info->netfilter.hooknum); 229 jsonw_int_field(json_wtr, "prio", 230 info->netfilter.priority); 231 jsonw_uint_field(json_wtr, "flags", 232 info->netfilter.flags); 233 } 234 235 static int get_prog_info(int prog_id, struct bpf_prog_info *info) 236 { 237 __u32 len = sizeof(*info); 238 int err, prog_fd; 239 240 prog_fd = bpf_prog_get_fd_by_id(prog_id); 241 if (prog_fd < 0) 242 return prog_fd; 243 244 memset(info, 0, sizeof(*info)); 245 err = bpf_prog_get_info_by_fd(prog_fd, info, &len); 246 if (err) 247 p_err("can't get prog info: %s", strerror(errno)); 248 close(prog_fd); 249 return err; 250 } 251 252 static int cmp_u64(const void *A, const void *B) 253 { 254 const __u64 *a = A, *b = B; 255 256 return *a - *b; 257 } 258 259 static void 260 show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) 261 { 262 __u32 i, j = 0; 263 __u64 *addrs; 264 265 jsonw_bool_field(json_wtr, "retprobe", 266 info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN); 267 jsonw_uint_field(json_wtr, "func_cnt", info->kprobe_multi.count); 268 jsonw_uint_field(json_wtr, "missed", info->kprobe_multi.missed); 269 jsonw_name(json_wtr, "funcs"); 270 jsonw_start_array(json_wtr); 271 addrs = u64_to_ptr(info->kprobe_multi.addrs); 272 qsort(addrs, info->kprobe_multi.count, sizeof(addrs[0]), cmp_u64); 273 274 /* Load it once for all. */ 275 if (!dd.sym_count) 276 kernel_syms_load(&dd); 277 for (i = 0; i < dd.sym_count; i++) { 278 if (dd.sym_mapping[i].address != addrs[j]) 279 continue; 280 jsonw_start_object(json_wtr); 281 jsonw_uint_field(json_wtr, "addr", dd.sym_mapping[i].address); 282 jsonw_string_field(json_wtr, "func", dd.sym_mapping[i].name); 283 /* Print null if it is vmlinux */ 284 if (dd.sym_mapping[i].module[0] == '\0') { 285 jsonw_name(json_wtr, "module"); 286 jsonw_null(json_wtr); 287 } else { 288 jsonw_string_field(json_wtr, "module", dd.sym_mapping[i].module); 289 } 290 jsonw_end_object(json_wtr); 291 if (j++ == info->kprobe_multi.count) 292 break; 293 } 294 jsonw_end_array(json_wtr); 295 } 296 297 static void 298 show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 299 { 300 jsonw_bool_field(wtr, "retprobe", info->perf_event.type == BPF_PERF_EVENT_KRETPROBE); 301 jsonw_uint_field(wtr, "addr", info->perf_event.kprobe.addr); 302 jsonw_string_field(wtr, "func", 303 u64_to_ptr(info->perf_event.kprobe.func_name)); 304 jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset); 305 jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed); 306 } 307 308 static void 309 show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 310 { 311 jsonw_bool_field(wtr, "retprobe", info->perf_event.type == BPF_PERF_EVENT_URETPROBE); 312 jsonw_string_field(wtr, "file", 313 u64_to_ptr(info->perf_event.uprobe.file_name)); 314 jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset); 315 } 316 317 static void 318 show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr) 319 { 320 jsonw_string_field(wtr, "tracepoint", 321 u64_to_ptr(info->perf_event.tracepoint.tp_name)); 322 } 323 324 static char *perf_config_hw_cache_str(__u64 config) 325 { 326 const char *hw_cache, *result, *op; 327 char *str = malloc(PERF_HW_CACHE_LEN); 328 329 if (!str) { 330 p_err("mem alloc failed"); 331 return NULL; 332 } 333 334 hw_cache = perf_event_name(evsel__hw_cache, config & 0xff); 335 if (hw_cache) 336 snprintf(str, PERF_HW_CACHE_LEN, "%s-", hw_cache); 337 else 338 snprintf(str, PERF_HW_CACHE_LEN, "%lld-", config & 0xff); 339 340 op = perf_event_name(evsel__hw_cache_op, (config >> 8) & 0xff); 341 if (op) 342 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 343 "%s-", op); 344 else 345 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 346 "%lld-", (config >> 8) & 0xff); 347 348 result = perf_event_name(evsel__hw_cache_result, config >> 16); 349 if (result) 350 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 351 "%s", result); 352 else 353 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 354 "%lld", config >> 16); 355 return str; 356 } 357 358 static const char *perf_config_str(__u32 type, __u64 config) 359 { 360 const char *perf_config; 361 362 switch (type) { 363 case PERF_TYPE_HARDWARE: 364 perf_config = perf_event_name(event_symbols_hw, config); 365 break; 366 case PERF_TYPE_SOFTWARE: 367 perf_config = perf_event_name(event_symbols_sw, config); 368 break; 369 case PERF_TYPE_HW_CACHE: 370 perf_config = perf_config_hw_cache_str(config); 371 break; 372 default: 373 perf_config = NULL; 374 break; 375 } 376 return perf_config; 377 } 378 379 static void 380 show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr) 381 { 382 __u64 config = info->perf_event.event.config; 383 __u32 type = info->perf_event.event.type; 384 const char *perf_type, *perf_config; 385 386 perf_type = perf_event_name(perf_type_name, type); 387 if (perf_type) 388 jsonw_string_field(wtr, "event_type", perf_type); 389 else 390 jsonw_uint_field(wtr, "event_type", type); 391 392 perf_config = perf_config_str(type, config); 393 if (perf_config) 394 jsonw_string_field(wtr, "event_config", perf_config); 395 else 396 jsonw_uint_field(wtr, "event_config", config); 397 398 if (type == PERF_TYPE_HW_CACHE && perf_config) 399 free((void *)perf_config); 400 } 401 402 static int show_link_close_json(int fd, struct bpf_link_info *info) 403 { 404 struct bpf_prog_info prog_info; 405 const char *prog_type_str; 406 int err; 407 408 jsonw_start_object(json_wtr); 409 410 show_link_header_json(info, json_wtr); 411 412 switch (info->type) { 413 case BPF_LINK_TYPE_RAW_TRACEPOINT: 414 jsonw_string_field(json_wtr, "tp_name", 415 u64_to_ptr(info->raw_tracepoint.tp_name)); 416 break; 417 case BPF_LINK_TYPE_TRACING: 418 err = get_prog_info(info->prog_id, &prog_info); 419 if (err) 420 return err; 421 422 prog_type_str = libbpf_bpf_prog_type_str(prog_info.type); 423 /* libbpf will return NULL for variants unknown to it. */ 424 if (prog_type_str) 425 jsonw_string_field(json_wtr, "prog_type", prog_type_str); 426 else 427 jsonw_uint_field(json_wtr, "prog_type", prog_info.type); 428 429 show_link_attach_type_json(info->tracing.attach_type, 430 json_wtr); 431 jsonw_uint_field(json_wtr, "target_obj_id", info->tracing.target_obj_id); 432 jsonw_uint_field(json_wtr, "target_btf_id", info->tracing.target_btf_id); 433 break; 434 case BPF_LINK_TYPE_CGROUP: 435 jsonw_lluint_field(json_wtr, "cgroup_id", 436 info->cgroup.cgroup_id); 437 show_link_attach_type_json(info->cgroup.attach_type, json_wtr); 438 break; 439 case BPF_LINK_TYPE_ITER: 440 show_iter_json(info, json_wtr); 441 break; 442 case BPF_LINK_TYPE_NETNS: 443 jsonw_uint_field(json_wtr, "netns_ino", 444 info->netns.netns_ino); 445 show_link_attach_type_json(info->netns.attach_type, json_wtr); 446 break; 447 case BPF_LINK_TYPE_NETFILTER: 448 netfilter_dump_json(info, json_wtr); 449 break; 450 case BPF_LINK_TYPE_TCX: 451 show_link_ifindex_json(info->tcx.ifindex, json_wtr); 452 show_link_attach_type_json(info->tcx.attach_type, json_wtr); 453 break; 454 case BPF_LINK_TYPE_XDP: 455 show_link_ifindex_json(info->xdp.ifindex, json_wtr); 456 break; 457 case BPF_LINK_TYPE_STRUCT_OPS: 458 jsonw_uint_field(json_wtr, "map_id", 459 info->struct_ops.map_id); 460 break; 461 case BPF_LINK_TYPE_KPROBE_MULTI: 462 show_kprobe_multi_json(info, json_wtr); 463 break; 464 case BPF_LINK_TYPE_PERF_EVENT: 465 switch (info->perf_event.type) { 466 case BPF_PERF_EVENT_EVENT: 467 show_perf_event_event_json(info, json_wtr); 468 break; 469 case BPF_PERF_EVENT_TRACEPOINT: 470 show_perf_event_tracepoint_json(info, json_wtr); 471 break; 472 case BPF_PERF_EVENT_KPROBE: 473 case BPF_PERF_EVENT_KRETPROBE: 474 show_perf_event_kprobe_json(info, json_wtr); 475 break; 476 case BPF_PERF_EVENT_UPROBE: 477 case BPF_PERF_EVENT_URETPROBE: 478 show_perf_event_uprobe_json(info, json_wtr); 479 break; 480 default: 481 break; 482 } 483 break; 484 default: 485 break; 486 } 487 488 if (!hashmap__empty(link_table)) { 489 struct hashmap_entry *entry; 490 491 jsonw_name(json_wtr, "pinned"); 492 jsonw_start_array(json_wtr); 493 hashmap__for_each_key_entry(link_table, entry, info->id) 494 jsonw_string(json_wtr, entry->pvalue); 495 jsonw_end_array(json_wtr); 496 } 497 498 emit_obj_refs_json(refs_table, info->id, json_wtr); 499 500 jsonw_end_object(json_wtr); 501 502 return 0; 503 } 504 505 static void show_link_header_plain(struct bpf_link_info *info) 506 { 507 const char *link_type_str; 508 509 printf("%u: ", info->id); 510 link_type_str = libbpf_bpf_link_type_str(info->type); 511 if (link_type_str) 512 printf("%s ", link_type_str); 513 else 514 printf("type %u ", info->type); 515 516 if (info->type == BPF_LINK_TYPE_STRUCT_OPS) 517 printf("map %u ", info->struct_ops.map_id); 518 else 519 printf("prog %u ", info->prog_id); 520 } 521 522 static void show_link_attach_type_plain(__u32 attach_type) 523 { 524 const char *attach_type_str; 525 526 attach_type_str = libbpf_bpf_attach_type_str(attach_type); 527 if (attach_type_str) 528 printf("attach_type %s ", attach_type_str); 529 else 530 printf("attach_type %u ", attach_type); 531 } 532 533 static void show_link_ifindex_plain(__u32 ifindex) 534 { 535 char devname[IF_NAMESIZE * 2] = "(unknown)"; 536 char tmpname[IF_NAMESIZE]; 537 char *ret = NULL; 538 539 if (ifindex) 540 ret = if_indextoname(ifindex, tmpname); 541 else 542 snprintf(devname, sizeof(devname), "(detached)"); 543 if (ret) 544 snprintf(devname, sizeof(devname), "%s(%d)", 545 tmpname, ifindex); 546 printf("ifindex %s ", devname); 547 } 548 549 static void show_iter_plain(struct bpf_link_info *info) 550 { 551 const char *target_name = u64_to_ptr(info->iter.target_name); 552 553 printf("target_name %s ", target_name); 554 555 if (is_iter_map_target(target_name)) 556 printf("map_id %u ", info->iter.map.map_id); 557 else if (is_iter_task_target(target_name)) { 558 if (info->iter.task.tid) 559 printf("tid %u ", info->iter.task.tid); 560 else if (info->iter.task.pid) 561 printf("pid %u ", info->iter.task.pid); 562 } 563 564 if (is_iter_cgroup_target(target_name)) { 565 printf("cgroup_id %llu ", info->iter.cgroup.cgroup_id); 566 printf("order %s ", 567 cgroup_order_string(info->iter.cgroup.order)); 568 } 569 } 570 571 static const char * const pf2name[] = { 572 [NFPROTO_INET] = "inet", 573 [NFPROTO_IPV4] = "ip", 574 [NFPROTO_ARP] = "arp", 575 [NFPROTO_NETDEV] = "netdev", 576 [NFPROTO_BRIDGE] = "bridge", 577 [NFPROTO_IPV6] = "ip6", 578 }; 579 580 static const char * const inethook2name[] = { 581 [NF_INET_PRE_ROUTING] = "prerouting", 582 [NF_INET_LOCAL_IN] = "input", 583 [NF_INET_FORWARD] = "forward", 584 [NF_INET_LOCAL_OUT] = "output", 585 [NF_INET_POST_ROUTING] = "postrouting", 586 }; 587 588 static const char * const arphook2name[] = { 589 [NF_ARP_IN] = "input", 590 [NF_ARP_OUT] = "output", 591 }; 592 593 void netfilter_dump_plain(const struct bpf_link_info *info) 594 { 595 const char *hookname = NULL, *pfname = NULL; 596 unsigned int hook = info->netfilter.hooknum; 597 unsigned int pf = info->netfilter.pf; 598 599 if (pf < ARRAY_SIZE(pf2name)) 600 pfname = pf2name[pf]; 601 602 switch (pf) { 603 case NFPROTO_BRIDGE: /* bridge shares numbers with enum nf_inet_hooks */ 604 case NFPROTO_IPV4: 605 case NFPROTO_IPV6: 606 case NFPROTO_INET: 607 if (hook < ARRAY_SIZE(inethook2name)) 608 hookname = inethook2name[hook]; 609 break; 610 case NFPROTO_ARP: 611 if (hook < ARRAY_SIZE(arphook2name)) 612 hookname = arphook2name[hook]; 613 default: 614 break; 615 } 616 617 if (pfname) 618 printf("\n\t%s", pfname); 619 else 620 printf("\n\tpf: %d", pf); 621 622 if (hookname) 623 printf(" %s", hookname); 624 else 625 printf(", hook %u,", hook); 626 627 printf(" prio %d", info->netfilter.priority); 628 629 if (info->netfilter.flags) 630 printf(" flags 0x%x", info->netfilter.flags); 631 } 632 633 static void show_kprobe_multi_plain(struct bpf_link_info *info) 634 { 635 __u32 i, j = 0; 636 __u64 *addrs; 637 638 if (!info->kprobe_multi.count) 639 return; 640 641 if (info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN) 642 printf("\n\tkretprobe.multi "); 643 else 644 printf("\n\tkprobe.multi "); 645 printf("func_cnt %u ", info->kprobe_multi.count); 646 if (info->kprobe_multi.missed) 647 printf("missed %llu ", info->kprobe_multi.missed); 648 addrs = (__u64 *)u64_to_ptr(info->kprobe_multi.addrs); 649 qsort(addrs, info->kprobe_multi.count, sizeof(__u64), cmp_u64); 650 651 /* Load it once for all. */ 652 if (!dd.sym_count) 653 kernel_syms_load(&dd); 654 if (!dd.sym_count) 655 return; 656 657 printf("\n\t%-16s %s", "addr", "func [module]"); 658 for (i = 0; i < dd.sym_count; i++) { 659 if (dd.sym_mapping[i].address != addrs[j]) 660 continue; 661 printf("\n\t%016lx %s", 662 dd.sym_mapping[i].address, dd.sym_mapping[i].name); 663 if (dd.sym_mapping[i].module[0] != '\0') 664 printf(" [%s] ", dd.sym_mapping[i].module); 665 else 666 printf(" "); 667 668 if (j++ == info->kprobe_multi.count) 669 break; 670 } 671 } 672 673 static void show_perf_event_kprobe_plain(struct bpf_link_info *info) 674 { 675 const char *buf; 676 677 buf = u64_to_ptr(info->perf_event.kprobe.func_name); 678 if (buf[0] == '\0' && !info->perf_event.kprobe.addr) 679 return; 680 681 if (info->perf_event.type == BPF_PERF_EVENT_KRETPROBE) 682 printf("\n\tkretprobe "); 683 else 684 printf("\n\tkprobe "); 685 if (info->perf_event.kprobe.addr) 686 printf("%llx ", info->perf_event.kprobe.addr); 687 printf("%s", buf); 688 if (info->perf_event.kprobe.offset) 689 printf("+%#x", info->perf_event.kprobe.offset); 690 if (info->perf_event.kprobe.missed) 691 printf(" missed %llu", info->perf_event.kprobe.missed); 692 printf(" "); 693 } 694 695 static void show_perf_event_uprobe_plain(struct bpf_link_info *info) 696 { 697 const char *buf; 698 699 buf = u64_to_ptr(info->perf_event.uprobe.file_name); 700 if (buf[0] == '\0') 701 return; 702 703 if (info->perf_event.type == BPF_PERF_EVENT_URETPROBE) 704 printf("\n\turetprobe "); 705 else 706 printf("\n\tuprobe "); 707 printf("%s+%#x ", buf, info->perf_event.uprobe.offset); 708 } 709 710 static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) 711 { 712 const char *buf; 713 714 buf = u64_to_ptr(info->perf_event.tracepoint.tp_name); 715 if (buf[0] == '\0') 716 return; 717 718 printf("\n\ttracepoint %s ", buf); 719 } 720 721 static void show_perf_event_event_plain(struct bpf_link_info *info) 722 { 723 __u64 config = info->perf_event.event.config; 724 __u32 type = info->perf_event.event.type; 725 const char *perf_type, *perf_config; 726 727 printf("\n\tevent "); 728 perf_type = perf_event_name(perf_type_name, type); 729 if (perf_type) 730 printf("%s:", perf_type); 731 else 732 printf("%u :", type); 733 734 perf_config = perf_config_str(type, config); 735 if (perf_config) 736 printf("%s ", perf_config); 737 else 738 printf("%llu ", config); 739 740 if (type == PERF_TYPE_HW_CACHE && perf_config) 741 free((void *)perf_config); 742 } 743 744 static int show_link_close_plain(int fd, struct bpf_link_info *info) 745 { 746 struct bpf_prog_info prog_info; 747 const char *prog_type_str; 748 int err; 749 750 show_link_header_plain(info); 751 752 switch (info->type) { 753 case BPF_LINK_TYPE_RAW_TRACEPOINT: 754 printf("\n\ttp '%s' ", 755 (const char *)u64_to_ptr(info->raw_tracepoint.tp_name)); 756 break; 757 case BPF_LINK_TYPE_TRACING: 758 err = get_prog_info(info->prog_id, &prog_info); 759 if (err) 760 return err; 761 762 prog_type_str = libbpf_bpf_prog_type_str(prog_info.type); 763 /* libbpf will return NULL for variants unknown to it. */ 764 if (prog_type_str) 765 printf("\n\tprog_type %s ", prog_type_str); 766 else 767 printf("\n\tprog_type %u ", prog_info.type); 768 769 show_link_attach_type_plain(info->tracing.attach_type); 770 if (info->tracing.target_obj_id || info->tracing.target_btf_id) 771 printf("\n\ttarget_obj_id %u target_btf_id %u ", 772 info->tracing.target_obj_id, 773 info->tracing.target_btf_id); 774 break; 775 case BPF_LINK_TYPE_CGROUP: 776 printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id); 777 show_link_attach_type_plain(info->cgroup.attach_type); 778 break; 779 case BPF_LINK_TYPE_ITER: 780 show_iter_plain(info); 781 break; 782 case BPF_LINK_TYPE_NETNS: 783 printf("\n\tnetns_ino %u ", info->netns.netns_ino); 784 show_link_attach_type_plain(info->netns.attach_type); 785 break; 786 case BPF_LINK_TYPE_NETFILTER: 787 netfilter_dump_plain(info); 788 break; 789 case BPF_LINK_TYPE_TCX: 790 printf("\n\t"); 791 show_link_ifindex_plain(info->tcx.ifindex); 792 show_link_attach_type_plain(info->tcx.attach_type); 793 break; 794 case BPF_LINK_TYPE_XDP: 795 printf("\n\t"); 796 show_link_ifindex_plain(info->xdp.ifindex); 797 break; 798 case BPF_LINK_TYPE_KPROBE_MULTI: 799 show_kprobe_multi_plain(info); 800 break; 801 case BPF_LINK_TYPE_PERF_EVENT: 802 switch (info->perf_event.type) { 803 case BPF_PERF_EVENT_EVENT: 804 show_perf_event_event_plain(info); 805 break; 806 case BPF_PERF_EVENT_TRACEPOINT: 807 show_perf_event_tracepoint_plain(info); 808 break; 809 case BPF_PERF_EVENT_KPROBE: 810 case BPF_PERF_EVENT_KRETPROBE: 811 show_perf_event_kprobe_plain(info); 812 break; 813 case BPF_PERF_EVENT_UPROBE: 814 case BPF_PERF_EVENT_URETPROBE: 815 show_perf_event_uprobe_plain(info); 816 break; 817 default: 818 break; 819 } 820 break; 821 default: 822 break; 823 } 824 825 if (!hashmap__empty(link_table)) { 826 struct hashmap_entry *entry; 827 828 hashmap__for_each_key_entry(link_table, entry, info->id) 829 printf("\n\tpinned %s", (char *)entry->pvalue); 830 } 831 emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 832 833 printf("\n"); 834 835 return 0; 836 } 837 838 static int do_show_link(int fd) 839 { 840 struct bpf_link_info info; 841 __u32 len = sizeof(info); 842 __u64 *addrs = NULL; 843 char buf[PATH_MAX]; 844 int count; 845 int err; 846 847 memset(&info, 0, sizeof(info)); 848 buf[0] = '\0'; 849 again: 850 err = bpf_link_get_info_by_fd(fd, &info, &len); 851 if (err) { 852 p_err("can't get link info: %s", 853 strerror(errno)); 854 close(fd); 855 return err; 856 } 857 if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT && 858 !info.raw_tracepoint.tp_name) { 859 info.raw_tracepoint.tp_name = ptr_to_u64(&buf); 860 info.raw_tracepoint.tp_name_len = sizeof(buf); 861 goto again; 862 } 863 if (info.type == BPF_LINK_TYPE_ITER && 864 !info.iter.target_name) { 865 info.iter.target_name = ptr_to_u64(&buf); 866 info.iter.target_name_len = sizeof(buf); 867 goto again; 868 } 869 if (info.type == BPF_LINK_TYPE_KPROBE_MULTI && 870 !info.kprobe_multi.addrs) { 871 count = info.kprobe_multi.count; 872 if (count) { 873 addrs = calloc(count, sizeof(__u64)); 874 if (!addrs) { 875 p_err("mem alloc failed"); 876 close(fd); 877 return -ENOMEM; 878 } 879 info.kprobe_multi.addrs = ptr_to_u64(addrs); 880 goto again; 881 } 882 } 883 if (info.type == BPF_LINK_TYPE_PERF_EVENT) { 884 switch (info.perf_event.type) { 885 case BPF_PERF_EVENT_TRACEPOINT: 886 if (!info.perf_event.tracepoint.tp_name) { 887 info.perf_event.tracepoint.tp_name = ptr_to_u64(&buf); 888 info.perf_event.tracepoint.name_len = sizeof(buf); 889 goto again; 890 } 891 break; 892 case BPF_PERF_EVENT_KPROBE: 893 case BPF_PERF_EVENT_KRETPROBE: 894 if (!info.perf_event.kprobe.func_name) { 895 info.perf_event.kprobe.func_name = ptr_to_u64(&buf); 896 info.perf_event.kprobe.name_len = sizeof(buf); 897 goto again; 898 } 899 break; 900 case BPF_PERF_EVENT_UPROBE: 901 case BPF_PERF_EVENT_URETPROBE: 902 if (!info.perf_event.uprobe.file_name) { 903 info.perf_event.uprobe.file_name = ptr_to_u64(&buf); 904 info.perf_event.uprobe.name_len = sizeof(buf); 905 goto again; 906 } 907 break; 908 default: 909 break; 910 } 911 } 912 913 if (json_output) 914 show_link_close_json(fd, &info); 915 else 916 show_link_close_plain(fd, &info); 917 918 if (addrs) 919 free(addrs); 920 close(fd); 921 return 0; 922 } 923 924 static int do_show(int argc, char **argv) 925 { 926 __u32 id = 0; 927 int err, fd; 928 929 if (show_pinned) { 930 link_table = hashmap__new(hash_fn_for_key_as_id, 931 equal_fn_for_key_as_id, NULL); 932 if (IS_ERR(link_table)) { 933 p_err("failed to create hashmap for pinned paths"); 934 return -1; 935 } 936 build_pinned_obj_table(link_table, BPF_OBJ_LINK); 937 } 938 build_obj_refs_table(&refs_table, BPF_OBJ_LINK); 939 940 if (argc == 2) { 941 fd = link_parse_fd(&argc, &argv); 942 if (fd < 0) 943 return fd; 944 do_show_link(fd); 945 goto out; 946 } 947 948 if (argc) 949 return BAD_ARG(); 950 951 if (json_output) 952 jsonw_start_array(json_wtr); 953 while (true) { 954 err = bpf_link_get_next_id(id, &id); 955 if (err) { 956 if (errno == ENOENT) 957 break; 958 p_err("can't get next link: %s%s", strerror(errno), 959 errno == EINVAL ? " -- kernel too old?" : ""); 960 break; 961 } 962 963 fd = bpf_link_get_fd_by_id(id); 964 if (fd < 0) { 965 if (errno == ENOENT) 966 continue; 967 p_err("can't get link by id (%u): %s", 968 id, strerror(errno)); 969 break; 970 } 971 972 err = do_show_link(fd); 973 if (err) 974 break; 975 } 976 if (json_output) 977 jsonw_end_array(json_wtr); 978 979 delete_obj_refs_table(refs_table); 980 981 if (show_pinned) 982 delete_pinned_obj_table(link_table); 983 984 out: 985 if (dd.sym_count) 986 kernel_syms_destroy(&dd); 987 return errno == ENOENT ? 0 : -1; 988 } 989 990 static int do_pin(int argc, char **argv) 991 { 992 int err; 993 994 err = do_pin_any(argc, argv, link_parse_fd); 995 if (!err && json_output) 996 jsonw_null(json_wtr); 997 return err; 998 } 999 1000 static int do_detach(int argc, char **argv) 1001 { 1002 int err, fd; 1003 1004 if (argc != 2) { 1005 p_err("link specifier is invalid or missing\n"); 1006 return 1; 1007 } 1008 1009 fd = link_parse_fd(&argc, &argv); 1010 if (fd < 0) 1011 return 1; 1012 1013 err = bpf_link_detach(fd); 1014 if (err) 1015 err = -errno; 1016 close(fd); 1017 if (err) { 1018 p_err("failed link detach: %s", strerror(-err)); 1019 return 1; 1020 } 1021 1022 if (json_output) 1023 jsonw_null(json_wtr); 1024 1025 return 0; 1026 } 1027 1028 static int do_help(int argc, char **argv) 1029 { 1030 if (json_output) { 1031 jsonw_null(json_wtr); 1032 return 0; 1033 } 1034 1035 fprintf(stderr, 1036 "Usage: %1$s %2$s { show | list } [LINK]\n" 1037 " %1$s %2$s pin LINK FILE\n" 1038 " %1$s %2$s detach LINK\n" 1039 " %1$s %2$s help\n" 1040 "\n" 1041 " " HELP_SPEC_LINK "\n" 1042 " " HELP_SPEC_OPTIONS " |\n" 1043 " {-f|--bpffs} | {-n|--nomount} }\n" 1044 "", 1045 bin_name, argv[-2]); 1046 1047 return 0; 1048 } 1049 1050 static const struct cmd cmds[] = { 1051 { "show", do_show }, 1052 { "list", do_show }, 1053 { "help", do_help }, 1054 { "pin", do_pin }, 1055 { "detach", do_detach }, 1056 { 0 } 1057 }; 1058 1059 int do_link(int argc, char **argv) 1060 { 1061 return cmd_select(cmds, argc, argv, do_help); 1062 } 1063