Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Register struct_ops with a link.

You can include an optional path after specifying the object name for the
'struct_ops register' subcommand.

Since the commit 226bc6ae6405 ("Merge branch 'Transit between BPF TCP
congestion controls.'") has been accepted, it is now possible to create a
link for a struct_ops. This can be done by defining a struct_ops in
SEC(".struct_ops.link") to make libbpf returns a real link. If we don't pin
the links before leaving bpftool, they will disappear. To instruct bpftool
to pin the links in a directory with the names of the maps, we need to
provide the path of that directory.

Signed-off-by: Kui-Feng Lee <kuifeng@meta.com>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/r/20230420002822.345222-1-kuifeng@meta.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kui-Feng Lee and committed by
Alexei Starovoitov
0232b788 833d67ec

+75 -25
+14
tools/bpf/bpftool/common.c
··· 1091 1091 default: return libbpf_bpf_attach_type_str(t); 1092 1092 } 1093 1093 } 1094 + 1095 + int pathname_concat(char *buf, int buf_sz, const char *path, 1096 + const char *name) 1097 + { 1098 + int len; 1099 + 1100 + len = snprintf(buf, buf_sz, "%s/%s", path, name); 1101 + if (len < 0) 1102 + return -EINVAL; 1103 + if (len >= buf_sz) 1104 + return -ENAMETOOLONG; 1105 + 1106 + return 0; 1107 + }
+3
tools/bpf/bpftool/main.h
··· 264 264 return map ? hashmap__size(map) == 0 : true; 265 265 } 266 266 267 + int pathname_concat(char *buf, int buf_sz, const char *path, 268 + const char *name); 269 + 267 270 #endif
-13
tools/bpf/bpftool/prog.c
··· 1476 1476 return err; 1477 1477 } 1478 1478 1479 - static int pathname_concat(char *buf, size_t buf_sz, const char *path, const char *name) 1480 - { 1481 - int len; 1482 - 1483 - len = snprintf(buf, buf_sz, "%s/%s", path, name); 1484 - if (len < 0) 1485 - return -EINVAL; 1486 - if ((size_t)len >= buf_sz) 1487 - return -ENAMETOOLONG; 1488 - 1489 - return 0; 1490 - } 1491 - 1492 1479 static int 1493 1480 auto_attach_programs(struct bpf_object *obj, const char *path) 1494 1481 {
+58 -12
tools/bpf/bpftool/struct_ops.c
··· 475 475 return cmd_retval(&res, true); 476 476 } 477 477 478 + static int pin_link(struct bpf_link *link, const char *pindir, 479 + const char *name) 480 + { 481 + char pinfile[PATH_MAX]; 482 + int err; 483 + 484 + err = pathname_concat(pinfile, sizeof(pinfile), pindir, name); 485 + if (err) 486 + return -1; 487 + 488 + return bpf_link__pin(link, pinfile); 489 + } 490 + 478 491 static int do_register(int argc, char **argv) 479 492 { 480 493 LIBBPF_OPTS(bpf_object_open_opts, open_opts); 494 + __u32 link_info_len = sizeof(struct bpf_link_info); 495 + struct bpf_link_info link_info = {}; 481 496 struct bpf_map_info info = {}; 482 497 __u32 info_len = sizeof(info); 483 498 int nr_errs = 0, nr_maps = 0; 499 + const char *linkdir = NULL; 484 500 struct bpf_object *obj; 485 501 struct bpf_link *link; 486 502 struct bpf_map *map; 487 503 const char *file; 488 504 489 - if (argc != 1) 505 + if (argc != 1 && argc != 2) 490 506 usage(); 491 507 492 508 file = GET_ARG(); 509 + if (argc == 1) 510 + linkdir = GET_ARG(); 511 + 512 + if (linkdir && mount_bpffs_for_pin(linkdir)) { 513 + p_err("can't mount bpffs for pinning"); 514 + return -1; 515 + } 493 516 494 517 if (verifier_logs) 495 518 /* log_level1 + log_level2 + stats, but not stable UAPI */ ··· 542 519 } 543 520 nr_maps++; 544 521 545 - bpf_link__disconnect(link); 546 - bpf_link__destroy(link); 547 - 548 - if (!bpf_map_get_info_by_fd(bpf_map__fd(map), &info, 549 - &info_len)) 550 - p_info("Registered %s %s id %u", 551 - get_kern_struct_ops_name(&info), 552 - bpf_map__name(map), 553 - info.id); 554 - else 522 + if (bpf_map_get_info_by_fd(bpf_map__fd(map), &info, 523 + &info_len)) { 555 524 /* Not p_err. The struct_ops was attached 556 525 * successfully. 557 526 */ 558 527 p_info("Registered %s but can't find id: %s", 559 528 bpf_map__name(map), strerror(errno)); 529 + goto clean_link; 530 + } 531 + if (!(bpf_map__map_flags(map) & BPF_F_LINK)) { 532 + p_info("Registered %s %s id %u", 533 + get_kern_struct_ops_name(&info), 534 + info.name, 535 + info.id); 536 + goto clean_link; 537 + } 538 + if (bpf_link_get_info_by_fd(bpf_link__fd(link), 539 + &link_info, 540 + &link_info_len)) { 541 + p_err("Registered %s but can't find link id: %s", 542 + bpf_map__name(map), strerror(errno)); 543 + nr_errs++; 544 + goto clean_link; 545 + } 546 + if (linkdir && pin_link(link, linkdir, info.name)) { 547 + p_err("can't pin link %u for %s: %s", 548 + link_info.id, info.name, 549 + strerror(errno)); 550 + nr_errs++; 551 + goto clean_link; 552 + } 553 + p_info("Registered %s %s map id %u link id %u", 554 + get_kern_struct_ops_name(&info), 555 + info.name, info.id, link_info.id); 556 + 557 + clean_link: 558 + bpf_link__disconnect(link); 559 + bpf_link__destroy(link); 560 560 } 561 561 562 562 bpf_object__close(obj); ··· 608 562 fprintf(stderr, 609 563 "Usage: %1$s %2$s { show | list } [STRUCT_OPS_MAP]\n" 610 564 " %1$s %2$s dump [STRUCT_OPS_MAP]\n" 611 - " %1$s %2$s register OBJ\n" 565 + " %1$s %2$s register OBJ [LINK_DIR]\n" 612 566 " %1$s %2$s unregister STRUCT_OPS_MAP\n" 613 567 " %1$s %2$s help\n" 614 568 "\n"