102ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 202ff58dcSJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 371bb428fSJakub Kicinski 43ff5a4dcSJakub Kicinski #define _GNU_SOURCE 571bb428fSJakub Kicinski #include <errno.h> 671bb428fSJakub Kicinski #include <fcntl.h> 747c09d6aSSong Liu #include <signal.h> 8c9c35995SJakub Kicinski #include <stdarg.h> 971bb428fSJakub Kicinski #include <stdio.h> 1071bb428fSJakub Kicinski #include <stdlib.h> 1171bb428fSJakub Kicinski #include <string.h> 1271bb428fSJakub Kicinski #include <time.h> 1371bb428fSJakub Kicinski #include <unistd.h> 14ba6dd679SJakub Kicinski #include <net/if.h> 1547c09d6aSSong Liu #include <sys/ioctl.h> 1671bb428fSJakub Kicinski #include <sys/types.h> 1771bb428fSJakub Kicinski #include <sys/stat.h> 1847c09d6aSSong Liu #include <sys/syscall.h> 1971bb428fSJakub Kicinski 20c8406848SJakub Kicinski #include <linux/err.h> 2147c09d6aSSong Liu #include <linux/perf_event.h> 22ba95c745SQuentin Monnet #include <linux/sizes.h> 23c8406848SJakub Kicinski 24229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h> 25229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h> 26229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h> 2771bb428fSJakub Kicinski 28b6c1cedbSJiong Wang #include "cfg.h" 2971bb428fSJakub Kicinski #include "main.h" 3073bb5b4fSJiong Wang #include "xlated_dumper.h" 3171bb428fSJakub Kicinski 32ec202509SPaul Chaignon enum dump_mode { 33ec202509SPaul Chaignon DUMP_JITED, 34ec202509SPaul Chaignon DUMP_XLATED, 35ec202509SPaul Chaignon }; 36ec202509SPaul Chaignon 37b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 38b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 39b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 40b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 41092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 42b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 43b7d3826cSJohn Fastabend }; 44b7d3826cSJohn Fastabend 45c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 46b7d3826cSJohn Fastabend { 47b7d3826cSJohn Fastabend enum bpf_attach_type type; 48b7d3826cSJohn Fastabend 49b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 50b7d3826cSJohn Fastabend if (attach_type_strings[type] && 51b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 52b7d3826cSJohn Fastabend return type; 53b7d3826cSJohn Fastabend } 54b7d3826cSJohn Fastabend 55b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 56b7d3826cSJohn Fastabend } 57b7d3826cSJohn Fastabend 5871bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 5971bb428fSJakub Kicinski { 6071bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 6171bb428fSJakub Kicinski time_t wallclock_secs; 6271bb428fSJakub Kicinski struct tm load_tm; 6371bb428fSJakub Kicinski 6471bb428fSJakub Kicinski buf[--size] = '\0'; 6571bb428fSJakub Kicinski 6671bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 6771bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 6871bb428fSJakub Kicinski perror("Can't read clocks"); 6971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 7071bb428fSJakub Kicinski return; 7171bb428fSJakub Kicinski } 7271bb428fSJakub Kicinski 7371bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 7407480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 7507480cbcSJakub Kicinski 1000000000; 7607480cbcSJakub Kicinski 7771bb428fSJakub Kicinski 7871bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 7971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 8071bb428fSJakub Kicinski return; 8171bb428fSJakub Kicinski } 8271bb428fSJakub Kicinski 83a3fe1f6fSQuentin Monnet if (json_output) 84a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 85a3fe1f6fSQuentin Monnet else 86a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 8771bb428fSJakub Kicinski } 8871bb428fSJakub Kicinski 89a7d22ca2SPaul Chaignon static int prog_fd_by_nametag(void *nametag, int **fds, bool tag) 9071bb428fSJakub Kicinski { 9171bb428fSJakub Kicinski unsigned int id = 0; 92ec202509SPaul Chaignon int fd, nb_fds = 0; 93ec202509SPaul Chaignon void *tmp; 9471bb428fSJakub Kicinski int err; 9571bb428fSJakub Kicinski 9671bb428fSJakub Kicinski while (true) { 97752bcf80SJiri Olsa struct bpf_prog_info info = {}; 98752bcf80SJiri Olsa __u32 len = sizeof(info); 99752bcf80SJiri Olsa 10071bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 10171bb428fSJakub Kicinski if (err) { 102ec202509SPaul Chaignon if (errno != ENOENT) { 1039a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 104ec202509SPaul Chaignon goto err_close_fds; 105ec202509SPaul Chaignon } 106ec202509SPaul Chaignon return nb_fds; 10771bb428fSJakub Kicinski } 10871bb428fSJakub Kicinski 10971bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 11071bb428fSJakub Kicinski if (fd < 0) { 1119a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 11271bb428fSJakub Kicinski id, strerror(errno)); 113ec202509SPaul Chaignon goto err_close_fds; 11471bb428fSJakub Kicinski } 11571bb428fSJakub Kicinski 11671bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 11771bb428fSJakub Kicinski if (err) { 1189a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 11971bb428fSJakub Kicinski id, strerror(errno)); 120ec202509SPaul Chaignon goto err_close_fd; 121ec202509SPaul Chaignon } 122ec202509SPaul Chaignon 123a7d22ca2SPaul Chaignon if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) || 124a7d22ca2SPaul Chaignon (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) { 12571bb428fSJakub Kicinski close(fd); 126ec202509SPaul Chaignon continue; 127ec202509SPaul Chaignon } 128ec202509SPaul Chaignon 129ec202509SPaul Chaignon if (nb_fds > 0) { 130ec202509SPaul Chaignon tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); 131ec202509SPaul Chaignon if (!tmp) { 132ec202509SPaul Chaignon p_err("failed to realloc"); 133ec202509SPaul Chaignon goto err_close_fd; 134ec202509SPaul Chaignon } 135ec202509SPaul Chaignon *fds = tmp; 136ec202509SPaul Chaignon } 137ec202509SPaul Chaignon (*fds)[nb_fds++] = fd; 138ec202509SPaul Chaignon } 139ec202509SPaul Chaignon 140ec202509SPaul Chaignon err_close_fd: 141ec202509SPaul Chaignon close(fd); 142ec202509SPaul Chaignon err_close_fds: 143ec202509SPaul Chaignon while (--nb_fds >= 0) 144ec202509SPaul Chaignon close((*fds)[nb_fds]); 14571bb428fSJakub Kicinski return -1; 14671bb428fSJakub Kicinski } 14771bb428fSJakub Kicinski 148ec202509SPaul Chaignon static int prog_parse_fds(int *argc, char ***argv, int **fds) 14971bb428fSJakub Kicinski { 15071bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 15171bb428fSJakub Kicinski unsigned int id; 15271bb428fSJakub Kicinski char *endptr; 15371bb428fSJakub Kicinski 15471bb428fSJakub Kicinski NEXT_ARGP(); 15571bb428fSJakub Kicinski 15671bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 15771bb428fSJakub Kicinski if (*endptr) { 1589a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 15971bb428fSJakub Kicinski return -1; 16071bb428fSJakub Kicinski } 16171bb428fSJakub Kicinski NEXT_ARGP(); 16271bb428fSJakub Kicinski 163ec202509SPaul Chaignon (*fds)[0] = bpf_prog_get_fd_by_id(id); 164ec202509SPaul Chaignon if ((*fds)[0] < 0) { 1659a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 166ec202509SPaul Chaignon return -1; 167ec202509SPaul Chaignon } 168ec202509SPaul Chaignon return 1; 16971bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 17071bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 17171bb428fSJakub Kicinski 17271bb428fSJakub Kicinski NEXT_ARGP(); 17371bb428fSJakub Kicinski 17471bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 17571bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 17671bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1779a5ab8bfSQuentin Monnet p_err("can't parse tag"); 17871bb428fSJakub Kicinski return -1; 17971bb428fSJakub Kicinski } 18071bb428fSJakub Kicinski NEXT_ARGP(); 18171bb428fSJakub Kicinski 182a7d22ca2SPaul Chaignon return prog_fd_by_nametag(tag, fds, true); 183a7d22ca2SPaul Chaignon } else if (is_prefix(**argv, "name")) { 184a7d22ca2SPaul Chaignon char *name; 185a7d22ca2SPaul Chaignon 186a7d22ca2SPaul Chaignon NEXT_ARGP(); 187a7d22ca2SPaul Chaignon 188a7d22ca2SPaul Chaignon name = **argv; 189a7d22ca2SPaul Chaignon if (strlen(name) > BPF_OBJ_NAME_LEN - 1) { 190a7d22ca2SPaul Chaignon p_err("can't parse name"); 191a7d22ca2SPaul Chaignon return -1; 192a7d22ca2SPaul Chaignon } 193a7d22ca2SPaul Chaignon NEXT_ARGP(); 194a7d22ca2SPaul Chaignon 195a7d22ca2SPaul Chaignon return prog_fd_by_nametag(name, fds, false); 19671bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 19771bb428fSJakub Kicinski char *path; 19871bb428fSJakub Kicinski 19971bb428fSJakub Kicinski NEXT_ARGP(); 20071bb428fSJakub Kicinski 20171bb428fSJakub Kicinski path = **argv; 20271bb428fSJakub Kicinski NEXT_ARGP(); 20371bb428fSJakub Kicinski 204ec202509SPaul Chaignon (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG); 205ec202509SPaul Chaignon if ((*fds)[0] < 0) 206ec202509SPaul Chaignon return -1; 207ec202509SPaul Chaignon return 1; 20871bb428fSJakub Kicinski } 20971bb428fSJakub Kicinski 210a7d22ca2SPaul Chaignon p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv); 21171bb428fSJakub Kicinski return -1; 21271bb428fSJakub Kicinski } 21371bb428fSJakub Kicinski 214ec202509SPaul Chaignon int prog_parse_fd(int *argc, char ***argv) 215ec202509SPaul Chaignon { 216ec202509SPaul Chaignon int *fds = NULL; 217ec202509SPaul Chaignon int nb_fds, fd; 218ec202509SPaul Chaignon 219ec202509SPaul Chaignon fds = malloc(sizeof(int)); 220ec202509SPaul Chaignon if (!fds) { 221ec202509SPaul Chaignon p_err("mem alloc failed"); 222ec202509SPaul Chaignon return -1; 223ec202509SPaul Chaignon } 224ec202509SPaul Chaignon nb_fds = prog_parse_fds(argc, argv, &fds); 225ec202509SPaul Chaignon if (nb_fds != 1) { 226ec202509SPaul Chaignon if (nb_fds > 1) { 227ec202509SPaul Chaignon p_err("several programs match this handle"); 228ec202509SPaul Chaignon while (nb_fds--) 229ec202509SPaul Chaignon close(fds[nb_fds]); 230ec202509SPaul Chaignon } 231ec202509SPaul Chaignon fd = -1; 232ec202509SPaul Chaignon goto exit_free; 233ec202509SPaul Chaignon } 234ec202509SPaul Chaignon 235ec202509SPaul Chaignon fd = fds[0]; 236ec202509SPaul Chaignon exit_free: 237ec202509SPaul Chaignon free(fds); 238ec202509SPaul Chaignon return fd; 239ec202509SPaul Chaignon } 240ec202509SPaul Chaignon 24171bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 24271bb428fSJakub Kicinski { 24371bb428fSJakub Kicinski struct bpf_prog_info info = {}; 24471bb428fSJakub Kicinski __u32 len = sizeof(info); 24571bb428fSJakub Kicinski __u32 map_ids[num_maps]; 24671bb428fSJakub Kicinski unsigned int i; 24771bb428fSJakub Kicinski int err; 24871bb428fSJakub Kicinski 24971bb428fSJakub Kicinski info.nr_map_ids = num_maps; 25071bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 25171bb428fSJakub Kicinski 25271bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 25371bb428fSJakub Kicinski if (err || !info.nr_map_ids) 25471bb428fSJakub Kicinski return; 25571bb428fSJakub Kicinski 256743cc665SQuentin Monnet if (json_output) { 257743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 258743cc665SQuentin Monnet jsonw_start_array(json_wtr); 259743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 260743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 261743cc665SQuentin Monnet jsonw_end_array(json_wtr); 262743cc665SQuentin Monnet } else { 26371bb428fSJakub Kicinski printf(" map_ids "); 26471bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 26571bb428fSJakub Kicinski printf("%u%s", map_ids[i], 26671bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 26771bb428fSJakub Kicinski } 26871bb428fSJakub Kicinski } 26971bb428fSJakub Kicinski 270ec202509SPaul Chaignon static void print_prog_header_json(struct bpf_prog_info *info) 271743cc665SQuentin Monnet { 272743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 273743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 274743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 275743cc665SQuentin Monnet prog_type_name[info->type]); 27671bb428fSJakub Kicinski else 277743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 27871bb428fSJakub Kicinski 279743cc665SQuentin Monnet if (*info->name) 280743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 28171bb428fSJakub Kicinski 282743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 283743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 284743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 285743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 28671bb428fSJakub Kicinski 2879b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 28888ad472bSAlexei Starovoitov if (info->run_time_ns) { 28988ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 29088ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 29188ad472bSAlexei Starovoitov } 292ec202509SPaul Chaignon } 2939b984a20SJiri Olsa 294ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 295ec202509SPaul Chaignon { 296ec202509SPaul Chaignon char *memlock; 297ec202509SPaul Chaignon 298ec202509SPaul Chaignon jsonw_start_object(json_wtr); 299ec202509SPaul Chaignon print_prog_header_json(info); 30052262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 30152262210SJakub Kicinski 302743cc665SQuentin Monnet if (info->load_time) { 30371bb428fSJakub Kicinski char buf[32]; 30471bb428fSJakub Kicinski 305743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 30671bb428fSJakub Kicinski 30771bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 308a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 309a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 310743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 31171bb428fSJakub Kicinski } 31271bb428fSJakub Kicinski 313743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 31471bb428fSJakub Kicinski 315743cc665SQuentin Monnet if (info->jited_prog_len) { 316743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 317743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 318743cc665SQuentin Monnet } else { 319743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 320743cc665SQuentin Monnet } 321743cc665SQuentin Monnet 322743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 323743cc665SQuentin Monnet if (memlock) 324743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 325743cc665SQuentin Monnet free(memlock); 326743cc665SQuentin Monnet 327743cc665SQuentin Monnet if (info->nr_map_ids) 328743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 329743cc665SQuentin Monnet 330569b0c77SPrashant Bhole if (info->btf_id) 331569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 332569b0c77SPrashant Bhole 3334990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3344990f1f4SPrashant Bhole struct pinned_obj *obj; 3354990f1f4SPrashant Bhole 3364990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 3374990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 3384990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3394990f1f4SPrashant Bhole if (obj->id == info->id) 3404990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 3414990f1f4SPrashant Bhole } 3424990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 3434990f1f4SPrashant Bhole } 3444990f1f4SPrashant Bhole 345743cc665SQuentin Monnet jsonw_end_object(json_wtr); 346743cc665SQuentin Monnet } 347743cc665SQuentin Monnet 348ec202509SPaul Chaignon static void print_prog_header_plain(struct bpf_prog_info *info) 349743cc665SQuentin Monnet { 350743cc665SQuentin Monnet printf("%u: ", info->id); 351743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 352743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 353743cc665SQuentin Monnet else 354743cc665SQuentin Monnet printf("type %u ", info->type); 355743cc665SQuentin Monnet 356743cc665SQuentin Monnet if (*info->name) 357743cc665SQuentin Monnet printf("name %s ", info->name); 358743cc665SQuentin Monnet 359743cc665SQuentin Monnet printf("tag "); 360743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 36152262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 3629b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 36388ad472bSAlexei Starovoitov if (info->run_time_ns) 36488ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 36588ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 366743cc665SQuentin Monnet printf("\n"); 367ec202509SPaul Chaignon } 368ec202509SPaul Chaignon 369ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 370ec202509SPaul Chaignon { 371ec202509SPaul Chaignon char *memlock; 372ec202509SPaul Chaignon 373ec202509SPaul Chaignon print_prog_header_plain(info); 374743cc665SQuentin Monnet 375743cc665SQuentin Monnet if (info->load_time) { 376743cc665SQuentin Monnet char buf[32]; 377743cc665SQuentin Monnet 378743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 379743cc665SQuentin Monnet 380743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 381743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 382743cc665SQuentin Monnet } 383743cc665SQuentin Monnet 384743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 385743cc665SQuentin Monnet 386743cc665SQuentin Monnet if (info->jited_prog_len) 387743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 38871bb428fSJakub Kicinski else 38971bb428fSJakub Kicinski printf(" not jited"); 39071bb428fSJakub Kicinski 39171bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 39271bb428fSJakub Kicinski if (memlock) 39371bb428fSJakub Kicinski printf(" memlock %sB", memlock); 39471bb428fSJakub Kicinski free(memlock); 39571bb428fSJakub Kicinski 396743cc665SQuentin Monnet if (info->nr_map_ids) 397743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 39871bb428fSJakub Kicinski 3994990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 4004990f1f4SPrashant Bhole struct pinned_obj *obj; 4014990f1f4SPrashant Bhole 4024990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 4034990f1f4SPrashant Bhole if (obj->id == info->id) 404a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 4054990f1f4SPrashant Bhole } 4064990f1f4SPrashant Bhole } 4074990f1f4SPrashant Bhole 408569b0c77SPrashant Bhole if (info->btf_id) 409031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 410569b0c77SPrashant Bhole 41171bb428fSJakub Kicinski printf("\n"); 412743cc665SQuentin Monnet } 413743cc665SQuentin Monnet 414743cc665SQuentin Monnet static int show_prog(int fd) 415743cc665SQuentin Monnet { 416743cc665SQuentin Monnet struct bpf_prog_info info = {}; 417743cc665SQuentin Monnet __u32 len = sizeof(info); 418743cc665SQuentin Monnet int err; 419743cc665SQuentin Monnet 420743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 421743cc665SQuentin Monnet if (err) { 4229a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 423743cc665SQuentin Monnet return -1; 424743cc665SQuentin Monnet } 425743cc665SQuentin Monnet 426743cc665SQuentin Monnet if (json_output) 427743cc665SQuentin Monnet print_prog_json(&info, fd); 428743cc665SQuentin Monnet else 429743cc665SQuentin Monnet print_prog_plain(&info, fd); 43071bb428fSJakub Kicinski 43171bb428fSJakub Kicinski return 0; 43271bb428fSJakub Kicinski } 43371bb428fSJakub Kicinski 434ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 435ec202509SPaul Chaignon { 436ec202509SPaul Chaignon int *fds = NULL; 437ec202509SPaul Chaignon int nb_fds, i; 438ec202509SPaul Chaignon int err = -1; 439ec202509SPaul Chaignon 440ec202509SPaul Chaignon fds = malloc(sizeof(int)); 441ec202509SPaul Chaignon if (!fds) { 442ec202509SPaul Chaignon p_err("mem alloc failed"); 443ec202509SPaul Chaignon return -1; 444ec202509SPaul Chaignon } 445ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 446ec202509SPaul Chaignon if (nb_fds < 1) 447ec202509SPaul Chaignon goto exit_free; 448ec202509SPaul Chaignon 449ec202509SPaul Chaignon if (json_output && nb_fds > 1) 450ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 451ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 452ec202509SPaul Chaignon err = show_prog(fds[i]); 453ec202509SPaul Chaignon if (err) { 454ec202509SPaul Chaignon for (; i < nb_fds; i++) 455ec202509SPaul Chaignon close(fds[i]); 456ec202509SPaul Chaignon break; 457ec202509SPaul Chaignon } 458ec202509SPaul Chaignon close(fds[i]); 459ec202509SPaul Chaignon } 460ec202509SPaul Chaignon if (json_output && nb_fds > 1) 461ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 462ec202509SPaul Chaignon 463ec202509SPaul Chaignon exit_free: 464ec202509SPaul Chaignon free(fds); 465ec202509SPaul Chaignon return err; 466ec202509SPaul Chaignon } 467ec202509SPaul Chaignon 46871bb428fSJakub Kicinski static int do_show(int argc, char **argv) 469743cc665SQuentin Monnet { 470743cc665SQuentin Monnet __u32 id = 0; 47171bb428fSJakub Kicinski int err; 47271bb428fSJakub Kicinski int fd; 47371bb428fSJakub Kicinski 474c541b734SPrashant Bhole if (show_pinned) 4754990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 4764990f1f4SPrashant Bhole 477ec202509SPaul Chaignon if (argc == 2) 478ec202509SPaul Chaignon return do_show_subset(argc, argv); 47971bb428fSJakub Kicinski 48071bb428fSJakub Kicinski if (argc) 48171bb428fSJakub Kicinski return BAD_ARG(); 48271bb428fSJakub Kicinski 483743cc665SQuentin Monnet if (json_output) 484743cc665SQuentin Monnet jsonw_start_array(json_wtr); 48571bb428fSJakub Kicinski while (true) { 48671bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 48771bb428fSJakub Kicinski if (err) { 4881739c26dSQuentin Monnet if (errno == ENOENT) { 4891739c26dSQuentin Monnet err = 0; 49071bb428fSJakub Kicinski break; 4911739c26dSQuentin Monnet } 4929a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 4939a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 494743cc665SQuentin Monnet err = -1; 495743cc665SQuentin Monnet break; 49671bb428fSJakub Kicinski } 49771bb428fSJakub Kicinski 49871bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 49971bb428fSJakub Kicinski if (fd < 0) { 5008207c6ddSJakub Kicinski if (errno == ENOENT) 5018207c6ddSJakub Kicinski continue; 5029a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 50371bb428fSJakub Kicinski id, strerror(errno)); 504743cc665SQuentin Monnet err = -1; 505743cc665SQuentin Monnet break; 50671bb428fSJakub Kicinski } 50771bb428fSJakub Kicinski 50871bb428fSJakub Kicinski err = show_prog(fd); 50971bb428fSJakub Kicinski close(fd); 51071bb428fSJakub Kicinski if (err) 511743cc665SQuentin Monnet break; 51271bb428fSJakub Kicinski } 51371bb428fSJakub Kicinski 514743cc665SQuentin Monnet if (json_output) 515743cc665SQuentin Monnet jsonw_end_array(json_wtr); 516743cc665SQuentin Monnet 517743cc665SQuentin Monnet return err; 51871bb428fSJakub Kicinski } 51971bb428fSJakub Kicinski 520ec202509SPaul Chaignon static int 521ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 522ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 52371bb428fSJakub Kicinski { 524b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 5253ddeac67SJakub Kicinski const char *disasm_opt = NULL; 5267105e828SDaniel Borkmann struct dump_data dd = {}; 527cae73f23SSong Liu void *func_info = NULL; 528254471e5SYonghong Song struct btf *btf = NULL; 529254471e5SYonghong Song char func_sig[1024]; 53071bb428fSJakub Kicinski unsigned char *buf; 531cae73f23SSong Liu __u32 member_len; 53271bb428fSJakub Kicinski ssize_t n; 53371bb428fSJakub Kicinski int fd; 53471bb428fSJakub Kicinski 535cae73f23SSong Liu if (mode == DUMP_JITED) { 5365b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 5379a5ab8bfSQuentin Monnet p_info("no instructions returned"); 538ec202509SPaul Chaignon return -1; 539f84192eeSSandipan Das } 540cae73f23SSong Liu buf = (unsigned char *)(info->jited_prog_insns); 541cae73f23SSong Liu member_len = info->jited_prog_len; 542cae73f23SSong Liu } else { /* DUMP_XLATED */ 543d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 5447105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 545ec202509SPaul Chaignon return -1; 5467105e828SDaniel Borkmann } 547cae73f23SSong Liu buf = (unsigned char *)info->xlated_prog_insns; 548cae73f23SSong Liu member_len = info->xlated_prog_len; 549cae73f23SSong Liu } 5507105e828SDaniel Borkmann 551cae73f23SSong Liu if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 552254471e5SYonghong Song p_err("failed to get btf"); 553ec202509SPaul Chaignon return -1; 554254471e5SYonghong Song } 555254471e5SYonghong Song 556cae73f23SSong Liu func_info = (void *)info->func_info; 557cae73f23SSong Liu 558cae73f23SSong Liu if (info->nr_line_info) { 559cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 560b053b439SMartin KaFai Lau if (!prog_linfo) 56110a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 562b053b439SMartin KaFai Lau } 563b053b439SMartin KaFai Lau 56471bb428fSJakub Kicinski if (filepath) { 56571bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 56671bb428fSJakub Kicinski if (fd < 0) { 5679a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 56871bb428fSJakub Kicinski strerror(errno)); 569ec202509SPaul Chaignon return -1; 57071bb428fSJakub Kicinski } 57171bb428fSJakub Kicinski 572cae73f23SSong Liu n = write(fd, buf, member_len); 57371bb428fSJakub Kicinski close(fd); 574cae73f23SSong Liu if (n != member_len) { 5759a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 57671bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 577ec202509SPaul Chaignon return -1; 57871bb428fSJakub Kicinski } 57952c84d36SQuentin Monnet 58052c84d36SQuentin Monnet if (json_output) 58152c84d36SQuentin Monnet jsonw_null(json_wtr); 582cae73f23SSong Liu } else if (mode == DUMP_JITED) { 583e6593596SJiong Wang const char *name = NULL; 584e6593596SJiong Wang 585cae73f23SSong Liu if (info->ifindex) { 586cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 587cae73f23SSong Liu info->netns_dev, 588cae73f23SSong Liu info->netns_ino, 5893ddeac67SJakub Kicinski &disasm_opt); 590e6593596SJiong Wang if (!name) 591ec202509SPaul Chaignon return -1; 592e6593596SJiong Wang } 593e6593596SJiong Wang 594cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 595f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 596254471e5SYonghong Song struct bpf_func_info *record; 597f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 598f7f62c71SSandipan Das unsigned char *img = buf; 599f7f62c71SSandipan Das __u64 *ksyms = NULL; 600f7f62c71SSandipan Das __u32 *lens; 601f7f62c71SSandipan Das __u32 i; 602cae73f23SSong Liu if (info->nr_jited_ksyms) { 603f7f62c71SSandipan Das kernel_syms_load(&dd); 604cae73f23SSong Liu ksyms = (__u64 *) info->jited_ksyms; 605f7f62c71SSandipan Das } 606f7f62c71SSandipan Das 607f7f62c71SSandipan Das if (json_output) 608f7f62c71SSandipan Das jsonw_start_array(json_wtr); 609f7f62c71SSandipan Das 610cae73f23SSong Liu lens = (__u32 *) info->jited_func_lens; 611cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 612f7f62c71SSandipan Das if (ksyms) { 613f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 614f7f62c71SSandipan Das if (sym) 615f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 616f7f62c71SSandipan Das else 617f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 618f7f62c71SSandipan Das } else { 619f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 620f7f62c71SSandipan Das } 621f7f62c71SSandipan Das 622254471e5SYonghong Song if (func_info) { 623cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 624254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 625254471e5SYonghong Song func_sig, 626254471e5SYonghong Song sizeof(func_sig)); 627254471e5SYonghong Song } 628254471e5SYonghong Song 629f7f62c71SSandipan Das if (json_output) { 630f7f62c71SSandipan Das jsonw_start_object(json_wtr); 631254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 632254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 633254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 634254471e5SYonghong Song } 635f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 636f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 637f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 638f7f62c71SSandipan Das } else { 639254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 640254471e5SYonghong Song printf("%s:\n", func_sig); 641f7f62c71SSandipan Das printf("%s:\n", sym_name); 642f7f62c71SSandipan Das } 643f7f62c71SSandipan Das 644b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 645b053b439SMartin KaFai Lau name, disasm_opt, btf, 646b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 647b053b439SMartin KaFai Lau linum); 648b053b439SMartin KaFai Lau 649f7f62c71SSandipan Das img += lens[i]; 650f7f62c71SSandipan Das 651f7f62c71SSandipan Das if (json_output) 652f7f62c71SSandipan Das jsonw_end_object(json_wtr); 653f7f62c71SSandipan Das else 654f7f62c71SSandipan Das printf("\n"); 655f7f62c71SSandipan Das } 656f7f62c71SSandipan Das 657f7f62c71SSandipan Das if (json_output) 658f7f62c71SSandipan Das jsonw_end_array(json_wtr); 659f7f62c71SSandipan Das } else { 660cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 661b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 662f7f62c71SSandipan Das } 663b6c1cedbSJiong Wang } else if (visual) { 664b6c1cedbSJiong Wang if (json_output) 665b6c1cedbSJiong Wang jsonw_null(json_wtr); 666b6c1cedbSJiong Wang else 667cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 6687105e828SDaniel Borkmann } else { 6697105e828SDaniel Borkmann kernel_syms_load(&dd); 670cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 671cae73f23SSong Liu dd.jited_ksyms = (__u64 *) info->jited_ksyms; 672254471e5SYonghong Song dd.btf = btf; 673254471e5SYonghong Song dd.func_info = func_info; 674cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 675b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 676f84192eeSSandipan Das 677f05e2c32SQuentin Monnet if (json_output) 678cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 679b053b439SMartin KaFai Lau linum); 680f05e2c32SQuentin Monnet else 681cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 682b053b439SMartin KaFai Lau linum); 6837105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6847105e828SDaniel Borkmann } 68571bb428fSJakub Kicinski 68671bb428fSJakub Kicinski return 0; 687ec202509SPaul Chaignon } 68871bb428fSJakub Kicinski 689ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 690ec202509SPaul Chaignon { 691ec202509SPaul Chaignon struct bpf_prog_info_linear *info_linear; 692ec202509SPaul Chaignon char *filepath = NULL; 693ec202509SPaul Chaignon bool opcodes = false; 694ec202509SPaul Chaignon bool visual = false; 695ec202509SPaul Chaignon enum dump_mode mode; 696ec202509SPaul Chaignon bool linum = false; 697ec202509SPaul Chaignon int *fds = NULL; 698ec202509SPaul Chaignon int nb_fds, i = 0; 699ec202509SPaul Chaignon int err = -1; 700ec202509SPaul Chaignon __u64 arrays; 701ec202509SPaul Chaignon 702ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 703ec202509SPaul Chaignon if (disasm_init()) 70471bb428fSJakub Kicinski return -1; 705ec202509SPaul Chaignon mode = DUMP_JITED; 706ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 707ec202509SPaul Chaignon mode = DUMP_XLATED; 708ec202509SPaul Chaignon } else { 709ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 710ec202509SPaul Chaignon return -1; 711ec202509SPaul Chaignon } 712ec202509SPaul Chaignon NEXT_ARG(); 713ec202509SPaul Chaignon 714ec202509SPaul Chaignon if (argc < 2) 715ec202509SPaul Chaignon usage(); 716ec202509SPaul Chaignon 717ec202509SPaul Chaignon fds = malloc(sizeof(int)); 718ec202509SPaul Chaignon if (!fds) { 719ec202509SPaul Chaignon p_err("mem alloc failed"); 720ec202509SPaul Chaignon return -1; 721ec202509SPaul Chaignon } 722ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 723ec202509SPaul Chaignon if (nb_fds < 1) 724ec202509SPaul Chaignon goto exit_free; 725ec202509SPaul Chaignon 726ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 727ec202509SPaul Chaignon NEXT_ARG(); 728ec202509SPaul Chaignon if (!argc) { 729ec202509SPaul Chaignon p_err("expected file path"); 730ec202509SPaul Chaignon goto exit_close; 731ec202509SPaul Chaignon } 732ec202509SPaul Chaignon if (nb_fds > 1) { 733ec202509SPaul Chaignon p_err("several programs matched"); 734ec202509SPaul Chaignon goto exit_close; 735ec202509SPaul Chaignon } 736ec202509SPaul Chaignon 737ec202509SPaul Chaignon filepath = *argv; 738ec202509SPaul Chaignon NEXT_ARG(); 739ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 740ec202509SPaul Chaignon opcodes = true; 741ec202509SPaul Chaignon NEXT_ARG(); 742ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 743ec202509SPaul Chaignon if (nb_fds > 1) { 744ec202509SPaul Chaignon p_err("several programs matched"); 745ec202509SPaul Chaignon goto exit_close; 746ec202509SPaul Chaignon } 747ec202509SPaul Chaignon 748ec202509SPaul Chaignon visual = true; 749ec202509SPaul Chaignon NEXT_ARG(); 750ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 751ec202509SPaul Chaignon linum = true; 752ec202509SPaul Chaignon NEXT_ARG(); 753ec202509SPaul Chaignon } 754ec202509SPaul Chaignon 755ec202509SPaul Chaignon if (argc) { 756ec202509SPaul Chaignon usage(); 757ec202509SPaul Chaignon goto exit_close; 758ec202509SPaul Chaignon } 759ec202509SPaul Chaignon 760ec202509SPaul Chaignon if (mode == DUMP_JITED) 761ec202509SPaul Chaignon arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 762ec202509SPaul Chaignon else 763ec202509SPaul Chaignon arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 764ec202509SPaul Chaignon 765ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 766ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 767ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 768ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 769ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 770ec202509SPaul Chaignon 771ec202509SPaul Chaignon if (json_output && nb_fds > 1) 772ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 773ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 774ec202509SPaul Chaignon info_linear = bpf_program__get_prog_info_linear(fds[i], arrays); 775ec202509SPaul Chaignon if (IS_ERR_OR_NULL(info_linear)) { 776ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 777ec202509SPaul Chaignon break; 778ec202509SPaul Chaignon } 779ec202509SPaul Chaignon 780ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 781ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 782ec202509SPaul Chaignon print_prog_header_json(&info_linear->info); 783ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 784ec202509SPaul Chaignon } else if (nb_fds > 1) { 785ec202509SPaul Chaignon print_prog_header_plain(&info_linear->info); 786ec202509SPaul Chaignon } 787ec202509SPaul Chaignon 788ec202509SPaul Chaignon err = prog_dump(&info_linear->info, mode, filepath, opcodes, 789ec202509SPaul Chaignon visual, linum); 790ec202509SPaul Chaignon 791ec202509SPaul Chaignon if (json_output && nb_fds > 1) 792ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 793ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 794ec202509SPaul Chaignon printf("\n"); 795ec202509SPaul Chaignon 796ec202509SPaul Chaignon free(info_linear); 797ec202509SPaul Chaignon if (err) 798ec202509SPaul Chaignon break; 799ec202509SPaul Chaignon close(fds[i]); 800ec202509SPaul Chaignon } 801ec202509SPaul Chaignon if (json_output && nb_fds > 1) 802ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 803ec202509SPaul Chaignon 804ec202509SPaul Chaignon exit_close: 805ec202509SPaul Chaignon for (; i < nb_fds; i++) 806ec202509SPaul Chaignon close(fds[i]); 807ec202509SPaul Chaignon exit_free: 808ec202509SPaul Chaignon free(fds); 809ec202509SPaul Chaignon return err; 81071bb428fSJakub Kicinski } 81171bb428fSJakub Kicinski 81271bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 81371bb428fSJakub Kicinski { 814004b45c0SQuentin Monnet int err; 815004b45c0SQuentin Monnet 81675a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 817004b45c0SQuentin Monnet if (!err && json_output) 818004b45c0SQuentin Monnet jsonw_null(json_wtr); 819004b45c0SQuentin Monnet return err; 82071bb428fSJakub Kicinski } 82171bb428fSJakub Kicinski 8223ff5a4dcSJakub Kicinski struct map_replace { 8233ff5a4dcSJakub Kicinski int idx; 8243ff5a4dcSJakub Kicinski int fd; 8253ff5a4dcSJakub Kicinski char *name; 8263ff5a4dcSJakub Kicinski }; 8273ff5a4dcSJakub Kicinski 828c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 8293ff5a4dcSJakub Kicinski { 8303ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 8313ff5a4dcSJakub Kicinski 8323ff5a4dcSJakub Kicinski return a->idx - b->idx; 8333ff5a4dcSJakub Kicinski } 8343ff5a4dcSJakub Kicinski 835092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 836092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 837092f0892SStanislav Fomichev int *mapfd) 838092f0892SStanislav Fomichev { 839092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 840092f0892SStanislav Fomichev return -EINVAL; 841092f0892SStanislav Fomichev 842092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 843092f0892SStanislav Fomichev if (*progfd < 0) 844092f0892SStanislav Fomichev return *progfd; 845092f0892SStanislav Fomichev 846092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 847092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 848092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 849092f0892SStanislav Fomichev return -EINVAL; 850092f0892SStanislav Fomichev } 851092f0892SStanislav Fomichev 852092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 853092f0892SStanislav Fomichev *mapfd = -1; 854092f0892SStanislav Fomichev return 0; 855092f0892SStanislav Fomichev } 856092f0892SStanislav Fomichev 857092f0892SStanislav Fomichev NEXT_ARG(); 858092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 859092f0892SStanislav Fomichev return -EINVAL; 860092f0892SStanislav Fomichev 861092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 862092f0892SStanislav Fomichev if (*mapfd < 0) 863092f0892SStanislav Fomichev return *mapfd; 864092f0892SStanislav Fomichev 865092f0892SStanislav Fomichev return 0; 866092f0892SStanislav Fomichev } 867092f0892SStanislav Fomichev 868b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 869b7d3826cSJohn Fastabend { 870b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 871092f0892SStanislav Fomichev int err, progfd; 872092f0892SStanislav Fomichev int mapfd; 873b7d3826cSJohn Fastabend 874092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 875092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 876092f0892SStanislav Fomichev if (err) 877092f0892SStanislav Fomichev return err; 878b7d3826cSJohn Fastabend 879b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 880b7d3826cSJohn Fastabend if (err) { 881b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 882b7d3826cSJohn Fastabend return -EINVAL; 883b7d3826cSJohn Fastabend } 884b7d3826cSJohn Fastabend 885b7d3826cSJohn Fastabend if (json_output) 886b7d3826cSJohn Fastabend jsonw_null(json_wtr); 887b7d3826cSJohn Fastabend return 0; 888b7d3826cSJohn Fastabend } 889b7d3826cSJohn Fastabend 890b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 891b7d3826cSJohn Fastabend { 892b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 893092f0892SStanislav Fomichev int err, progfd; 894092f0892SStanislav Fomichev int mapfd; 895b7d3826cSJohn Fastabend 896092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 897092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 898092f0892SStanislav Fomichev if (err) 899092f0892SStanislav Fomichev return err; 900b7d3826cSJohn Fastabend 901b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 902b7d3826cSJohn Fastabend if (err) { 903b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 904b7d3826cSJohn Fastabend return -EINVAL; 905b7d3826cSJohn Fastabend } 906b7d3826cSJohn Fastabend 907b7d3826cSJohn Fastabend if (json_output) 908b7d3826cSJohn Fastabend jsonw_null(json_wtr); 909b7d3826cSJohn Fastabend return 0; 910b7d3826cSJohn Fastabend } 91177380998SStanislav Fomichev 912ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 913ba95c745SQuentin Monnet { 914ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 915ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 916ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 917ba95c745SQuentin Monnet return -1; 918ba95c745SQuentin Monnet } 919ba95c745SQuentin Monnet 920ba95c745SQuentin Monnet return 0; 921ba95c745SQuentin Monnet } 922ba95c745SQuentin Monnet 923ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 924ba95c745SQuentin Monnet { 925ba95c745SQuentin Monnet size_t block_size = 256; 926ba95c745SQuentin Monnet size_t buf_size = block_size; 927ba95c745SQuentin Monnet size_t nb_read = 0; 928ba95c745SQuentin Monnet void *tmp; 929ba95c745SQuentin Monnet FILE *f; 930ba95c745SQuentin Monnet 931ba95c745SQuentin Monnet if (!fname) { 932ba95c745SQuentin Monnet *data_ptr = NULL; 933ba95c745SQuentin Monnet *size = 0; 934ba95c745SQuentin Monnet return 0; 935ba95c745SQuentin Monnet } 936ba95c745SQuentin Monnet 937ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 938ba95c745SQuentin Monnet f = stdin; 939ba95c745SQuentin Monnet else 940ba95c745SQuentin Monnet f = fopen(fname, "r"); 941ba95c745SQuentin Monnet if (!f) { 942ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 943ba95c745SQuentin Monnet return -1; 944ba95c745SQuentin Monnet } 945ba95c745SQuentin Monnet 946ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 947ba95c745SQuentin Monnet if (!*data_ptr) { 948ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 949ba95c745SQuentin Monnet strerror(errno)); 950ba95c745SQuentin Monnet goto err_fclose; 951ba95c745SQuentin Monnet } 952ba95c745SQuentin Monnet 953ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 954ba95c745SQuentin Monnet if (feof(f)) 955ba95c745SQuentin Monnet break; 956ba95c745SQuentin Monnet if (ferror(f)) { 957ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 958ba95c745SQuentin Monnet fname, strerror(errno)); 959ba95c745SQuentin Monnet goto err_free; 960ba95c745SQuentin Monnet } 961ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 962ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 963ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 964ba95c745SQuentin Monnet UINT32_MAX); 965ba95c745SQuentin Monnet goto err_free; 966ba95c745SQuentin Monnet } 967ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 968ba95c745SQuentin Monnet buf_size *= 2; 969ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 970ba95c745SQuentin Monnet if (!tmp) { 971ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 972ba95c745SQuentin Monnet strerror(errno)); 973ba95c745SQuentin Monnet goto err_free; 974ba95c745SQuentin Monnet } 975ba95c745SQuentin Monnet *data_ptr = tmp; 976ba95c745SQuentin Monnet } 977ba95c745SQuentin Monnet } 978ba95c745SQuentin Monnet if (f != stdin) 979ba95c745SQuentin Monnet fclose(f); 980ba95c745SQuentin Monnet 981ba95c745SQuentin Monnet *size = nb_read; 982ba95c745SQuentin Monnet return 0; 983ba95c745SQuentin Monnet 984ba95c745SQuentin Monnet err_free: 985ba95c745SQuentin Monnet free(*data_ptr); 986ba95c745SQuentin Monnet *data_ptr = NULL; 987ba95c745SQuentin Monnet err_fclose: 988ba95c745SQuentin Monnet if (f != stdin) 989ba95c745SQuentin Monnet fclose(f); 990ba95c745SQuentin Monnet return -1; 991ba95c745SQuentin Monnet } 992ba95c745SQuentin Monnet 993ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 994ba95c745SQuentin Monnet { 995ba95c745SQuentin Monnet size_t i, j; 996ba95c745SQuentin Monnet char c; 997ba95c745SQuentin Monnet 998ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 999ba95c745SQuentin Monnet /* Row offset */ 1000ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1001ba95c745SQuentin Monnet 1002ba95c745SQuentin Monnet /* Hexadecimal values */ 1003ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1004ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1005ba95c745SQuentin Monnet j % 2 ? " " : ""); 1006ba95c745SQuentin Monnet for (; j < i + 16; j++) 1007ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1008ba95c745SQuentin Monnet 1009ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1010ba95c745SQuentin Monnet fprintf(f, "| "); 1011ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1012ba95c745SQuentin Monnet c = *(char *)(data + j); 1013ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1014ba95c745SQuentin Monnet c = '.'; 1015ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1016ba95c745SQuentin Monnet } 1017ba95c745SQuentin Monnet 1018ba95c745SQuentin Monnet fprintf(f, "\n"); 1019ba95c745SQuentin Monnet } 1020ba95c745SQuentin Monnet } 1021ba95c745SQuentin Monnet 1022ba95c745SQuentin Monnet static int 1023ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1024ba95c745SQuentin Monnet const char *json_key) 1025ba95c745SQuentin Monnet { 1026ba95c745SQuentin Monnet size_t nb_written; 1027ba95c745SQuentin Monnet FILE *f; 1028ba95c745SQuentin Monnet 1029ba95c745SQuentin Monnet if (!fname) 1030ba95c745SQuentin Monnet return 0; 1031ba95c745SQuentin Monnet 1032ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1033ba95c745SQuentin Monnet f = stdout; 1034ba95c745SQuentin Monnet if (json_output) { 1035ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1036ba95c745SQuentin Monnet print_data_json(data, size); 1037ba95c745SQuentin Monnet } else { 1038ba95c745SQuentin Monnet hex_print(data, size, f); 1039ba95c745SQuentin Monnet } 1040ba95c745SQuentin Monnet return 0; 1041ba95c745SQuentin Monnet } 1042ba95c745SQuentin Monnet 1043ba95c745SQuentin Monnet f = fopen(fname, "w"); 1044ba95c745SQuentin Monnet if (!f) { 1045ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1046ba95c745SQuentin Monnet return -1; 1047ba95c745SQuentin Monnet } 1048ba95c745SQuentin Monnet 1049ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1050ba95c745SQuentin Monnet fclose(f); 1051ba95c745SQuentin Monnet if (nb_written != size) { 1052ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1053ba95c745SQuentin Monnet return -1; 1054ba95c745SQuentin Monnet } 1055ba95c745SQuentin Monnet 1056ba95c745SQuentin Monnet return 0; 1057ba95c745SQuentin Monnet } 1058ba95c745SQuentin Monnet 1059ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1060ba95c745SQuentin Monnet { 1061ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1062ba95c745SQuentin Monnet if (!*data_ptr) { 1063ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1064ba95c745SQuentin Monnet strerror(errno)); 1065ba95c745SQuentin Monnet return -1; 1066ba95c745SQuentin Monnet } 1067ba95c745SQuentin Monnet 1068ba95c745SQuentin Monnet return 0; 1069ba95c745SQuentin Monnet } 1070ba95c745SQuentin Monnet 1071ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1072ba95c745SQuentin Monnet { 1073ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1074ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1075ba95c745SQuentin Monnet struct bpf_prog_test_run_attr test_attr = {0}; 1076ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1077ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1078ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1079ba95c745SQuentin Monnet unsigned int repeat = 1; 1080ba95c745SQuentin Monnet int fd, err; 1081ba95c745SQuentin Monnet 1082ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1083ba95c745SQuentin Monnet return -1; 1084ba95c745SQuentin Monnet 1085ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1086ba95c745SQuentin Monnet if (fd < 0) 1087ba95c745SQuentin Monnet return -1; 1088ba95c745SQuentin Monnet 1089ba95c745SQuentin Monnet while (argc) { 1090ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1091ba95c745SQuentin Monnet "data_size_out", NULL)) 1092ba95c745SQuentin Monnet return -1; 1093ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1094ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1095ba95c745SQuentin Monnet return -1; 1096ba95c745SQuentin Monnet 1097ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1098ba95c745SQuentin Monnet NEXT_ARG(); 1099ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1100ba95c745SQuentin Monnet return -1; 1101ba95c745SQuentin Monnet 1102ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1103ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1104ba95c745SQuentin Monnet return -1; 1105ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1106ba95c745SQuentin Monnet NEXT_ARG(); 1107ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1108ba95c745SQuentin Monnet return -1; 1109ba95c745SQuentin Monnet 1110ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1111ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1112ba95c745SQuentin Monnet char *endptr; 1113ba95c745SQuentin Monnet 1114ba95c745SQuentin Monnet NEXT_ARG(); 1115ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1116ba95c745SQuentin Monnet return -1; 1117ba95c745SQuentin Monnet 1118ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1119ba95c745SQuentin Monnet if (*endptr) { 1120ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1121ba95c745SQuentin Monnet *argv); 1122ba95c745SQuentin Monnet return -1; 1123ba95c745SQuentin Monnet } 1124ba95c745SQuentin Monnet NEXT_ARG(); 1125ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1126ba95c745SQuentin Monnet NEXT_ARG(); 1127ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1128ba95c745SQuentin Monnet return -1; 1129ba95c745SQuentin Monnet 1130ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1131ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1132ba95c745SQuentin Monnet return -1; 1133ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1134ba95c745SQuentin Monnet NEXT_ARG(); 1135ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1136ba95c745SQuentin Monnet return -1; 1137ba95c745SQuentin Monnet 1138ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1139ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1140ba95c745SQuentin Monnet char *endptr; 1141ba95c745SQuentin Monnet 1142ba95c745SQuentin Monnet NEXT_ARG(); 1143ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1144ba95c745SQuentin Monnet return -1; 1145ba95c745SQuentin Monnet 1146ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1147ba95c745SQuentin Monnet if (*endptr) { 1148ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1149ba95c745SQuentin Monnet *argv); 1150ba95c745SQuentin Monnet return -1; 1151ba95c745SQuentin Monnet } 1152ba95c745SQuentin Monnet NEXT_ARG(); 1153ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1154ba95c745SQuentin Monnet char *endptr; 1155ba95c745SQuentin Monnet 1156ba95c745SQuentin Monnet NEXT_ARG(); 1157ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1158ba95c745SQuentin Monnet return -1; 1159ba95c745SQuentin Monnet 1160ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1161ba95c745SQuentin Monnet if (*endptr) { 1162ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1163ba95c745SQuentin Monnet *argv); 1164ba95c745SQuentin Monnet return -1; 1165ba95c745SQuentin Monnet } 1166ba95c745SQuentin Monnet NEXT_ARG(); 1167ba95c745SQuentin Monnet } else { 1168ba95c745SQuentin Monnet p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1169ba95c745SQuentin Monnet *argv); 1170ba95c745SQuentin Monnet return -1; 1171ba95c745SQuentin Monnet } 1172ba95c745SQuentin Monnet } 1173ba95c745SQuentin Monnet 1174ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1175ba95c745SQuentin Monnet if (err) 1176ba95c745SQuentin Monnet return -1; 1177ba95c745SQuentin Monnet 1178ba95c745SQuentin Monnet if (data_in) { 1179ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1180ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1181ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1182ba95c745SQuentin Monnet if (err) 1183ba95c745SQuentin Monnet goto free_data_in; 1184ba95c745SQuentin Monnet } 1185ba95c745SQuentin Monnet 1186ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1187ba95c745SQuentin Monnet if (err) 1188ba95c745SQuentin Monnet goto free_data_out; 1189ba95c745SQuentin Monnet 1190ba95c745SQuentin Monnet if (ctx_in) { 1191ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1192ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1193ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1194ba95c745SQuentin Monnet if (err) 1195ba95c745SQuentin Monnet goto free_ctx_in; 1196ba95c745SQuentin Monnet } 1197ba95c745SQuentin Monnet 1198ba95c745SQuentin Monnet test_attr.prog_fd = fd; 1199ba95c745SQuentin Monnet test_attr.repeat = repeat; 1200ba95c745SQuentin Monnet test_attr.data_in = data_in; 1201ba95c745SQuentin Monnet test_attr.data_out = data_out; 1202ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1203ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1204ba95c745SQuentin Monnet 1205ba95c745SQuentin Monnet err = bpf_prog_test_run_xattr(&test_attr); 1206ba95c745SQuentin Monnet if (err) { 1207ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1208ba95c745SQuentin Monnet goto free_ctx_out; 1209ba95c745SQuentin Monnet } 1210ba95c745SQuentin Monnet 1211ba95c745SQuentin Monnet err = 0; 1212ba95c745SQuentin Monnet 1213ba95c745SQuentin Monnet if (json_output) 1214ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1215ba95c745SQuentin Monnet 1216ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1217ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1218ba95c745SQuentin Monnet */ 1219ba95c745SQuentin Monnet if (test_attr.data_size_out) 1220ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1221ba95c745SQuentin Monnet test_attr.data_size_out, 1222ba95c745SQuentin Monnet data_fname_out, "data_out"); 1223ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1224ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1225ba95c745SQuentin Monnet test_attr.ctx_size_out, 1226ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1227ba95c745SQuentin Monnet 1228ba95c745SQuentin Monnet if (json_output) { 1229ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1230ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1231ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1232ba95c745SQuentin Monnet } else { 1233ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1234ba95c745SQuentin Monnet test_attr.retval, 1235ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1236ba95c745SQuentin Monnet } 1237ba95c745SQuentin Monnet 1238ba95c745SQuentin Monnet free_ctx_out: 1239ba95c745SQuentin Monnet free(ctx_out); 1240ba95c745SQuentin Monnet free_ctx_in: 1241ba95c745SQuentin Monnet free(ctx_in); 1242ba95c745SQuentin Monnet free_data_out: 1243ba95c745SQuentin Monnet free(data_out); 1244ba95c745SQuentin Monnet free_data_in: 1245ba95c745SQuentin Monnet free(data_in); 1246ba95c745SQuentin Monnet 1247ba95c745SQuentin Monnet return err; 1248ba95c745SQuentin Monnet } 1249ba95c745SQuentin Monnet 1250*6ae32b29SQuentin Monnet static int 1251*6ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 1252*6ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 1253*6ae32b29SQuentin Monnet { 1254*6ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 1255*6ae32b29SQuentin Monnet int ret; 1256*6ae32b29SQuentin Monnet 1257*6ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 1258*6ae32b29SQuentin Monnet if (!ret) 1259*6ae32b29SQuentin Monnet return ret; 1260*6ae32b29SQuentin Monnet 1261*6ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 1262*6ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 1263*6ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 1264*6ae32b29SQuentin Monnet libbpf_set_print(print_backup); 1265*6ae32b29SQuentin Monnet 1266*6ae32b29SQuentin Monnet return ret; 1267*6ae32b29SQuentin Monnet } 1268*6ae32b29SQuentin Monnet 126977380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 127049a086c2SRoman Gushchin { 127132e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1272e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1273e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1274e00aca65SAndrii Nakryiko ); 1275e00aca65SAndrii Nakryiko struct bpf_object_load_attr load_attr = { 0 }; 127655d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 12773ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 127877380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 12793ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 12803767a94bSStanislav Fomichev const char *pinmaps = NULL; 128149a086c2SRoman Gushchin struct bpf_object *obj; 1282c8406848SJakub Kicinski struct bpf_map *map; 1283c8406848SJakub Kicinski const char *pinfile; 12843ff5a4dcSJakub Kicinski unsigned int i, j; 1285c8406848SJakub Kicinski __u32 ifindex = 0; 128632e3e58eSAndrii Nakryiko const char *file; 12873ff5a4dcSJakub Kicinski int idx, err; 128849a086c2SRoman Gushchin 128932e3e58eSAndrii Nakryiko 12908d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 12918d1fc3deSJakub Kicinski return -1; 129232e3e58eSAndrii Nakryiko file = GET_ARG(); 12938d1fc3deSJakub Kicinski pinfile = GET_ARG(); 129449a086c2SRoman Gushchin 1295ba6dd679SJakub Kicinski while (argc) { 129649f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 129749f2cba3SJakub Kicinski char *type; 129849f2cba3SJakub Kicinski 129949f2cba3SJakub Kicinski NEXT_ARG(); 130049f2cba3SJakub Kicinski 130132e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 130249f2cba3SJakub Kicinski p_err("program type already specified"); 13033ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 130449f2cba3SJakub Kicinski } 130549f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 13063ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 130749f2cba3SJakub Kicinski 130849f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 130949f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 131049f2cba3SJakub Kicinski if (!type) { 131149f2cba3SJakub Kicinski p_err("mem alloc failed"); 13123ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 131349f2cba3SJakub Kicinski } 131449f2cba3SJakub Kicinski *type = 0; 131549f2cba3SJakub Kicinski strcat(type, *argv); 131649f2cba3SJakub Kicinski strcat(type, "/"); 131749f2cba3SJakub Kicinski 1318*6ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1319c8406848SJakub Kicinski &expected_attach_type); 132049f2cba3SJakub Kicinski free(type); 1321c76e4c22STaeung Song if (err < 0) 13223ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1323c76e4c22STaeung Song 132449f2cba3SJakub Kicinski NEXT_ARG(); 13253ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1326dde7011aSJakub Kicinski void *new_map_replace; 13273ff5a4dcSJakub Kicinski char *endptr, *name; 13283ff5a4dcSJakub Kicinski int fd; 13293ff5a4dcSJakub Kicinski 13303ff5a4dcSJakub Kicinski NEXT_ARG(); 13313ff5a4dcSJakub Kicinski 13323ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 13333ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13343ff5a4dcSJakub Kicinski 13353ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 13363ff5a4dcSJakub Kicinski NEXT_ARG(); 13373ff5a4dcSJakub Kicinski 13383ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 13393ff5a4dcSJakub Kicinski if (*endptr) { 13403ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 13413ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13423ff5a4dcSJakub Kicinski } 13433ff5a4dcSJakub Kicinski name = NULL; 13443ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 13453ff5a4dcSJakub Kicinski NEXT_ARG(); 13463ff5a4dcSJakub Kicinski 13473ff5a4dcSJakub Kicinski name = *argv; 13483ff5a4dcSJakub Kicinski idx = -1; 13493ff5a4dcSJakub Kicinski } else { 13503ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 13513ff5a4dcSJakub Kicinski *argv); 13523ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13533ff5a4dcSJakub Kicinski } 13543ff5a4dcSJakub Kicinski NEXT_ARG(); 13553ff5a4dcSJakub Kicinski 13563ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 13573ff5a4dcSJakub Kicinski if (fd < 0) 13583ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13593ff5a4dcSJakub Kicinski 1360dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 1361dde7011aSJakub Kicinski old_map_fds + 1, 13623ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1363dde7011aSJakub Kicinski if (!new_map_replace) { 13643ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 13653ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13663ff5a4dcSJakub Kicinski } 1367dde7011aSJakub Kicinski map_replace = new_map_replace; 1368dde7011aSJakub Kicinski 13693ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 13703ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 13713ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 13723ff5a4dcSJakub Kicinski old_map_fds++; 137349f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1374ba6dd679SJakub Kicinski NEXT_ARG(); 1375ba6dd679SJakub Kicinski 1376c8406848SJakub Kicinski if (ifindex) { 1377ba6dd679SJakub Kicinski p_err("offload device already specified"); 13783ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1379ba6dd679SJakub Kicinski } 1380ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 13813ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1382ba6dd679SJakub Kicinski 1383c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1384c8406848SJakub Kicinski if (!ifindex) { 1385ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1386ba6dd679SJakub Kicinski *argv, strerror(errno)); 13873ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1388ba6dd679SJakub Kicinski } 1389ba6dd679SJakub Kicinski NEXT_ARG(); 13903767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 13913767a94bSStanislav Fomichev NEXT_ARG(); 13923767a94bSStanislav Fomichev 13933767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 13943767a94bSStanislav Fomichev goto err_free_reuse_maps; 13953767a94bSStanislav Fomichev 13963767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1397ba6dd679SJakub Kicinski } else { 13983ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1399ba6dd679SJakub Kicinski *argv); 14003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1401ba6dd679SJakub Kicinski } 1402ba6dd679SJakub Kicinski } 1403ba6dd679SJakub Kicinski 1404ac4e0e05SYonghong Song set_max_rlimit(); 1405ac4e0e05SYonghong Song 140632e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1407c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 1408c8406848SJakub Kicinski p_err("failed to open object file"); 14093ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 141049a086c2SRoman Gushchin } 141149a086c2SRoman Gushchin 141277380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 141332e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1414c8406848SJakub Kicinski 141532e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 141677380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1417c8406848SJakub Kicinski 1418*6ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1419c8406848SJakub Kicinski &expected_attach_type); 1420c76e4c22STaeung Song if (err < 0) 1421c8406848SJakub Kicinski goto err_close_obj; 1422c8406848SJakub Kicinski } 142377380998SStanislav Fomichev 142477380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 142577380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 142677380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 142777380998SStanislav Fomichev } 1428c8406848SJakub Kicinski 14293ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 14303ff5a4dcSJakub Kicinski map_replace_compar); 14313ff5a4dcSJakub Kicinski 14323ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 14333ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 14343ff5a4dcSJakub Kicinski */ 14353ff5a4dcSJakub Kicinski j = 0; 14363ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 14373ff5a4dcSJakub Kicinski i = 0; 1438f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 14393ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 14403ff5a4dcSJakub Kicinski map_replace[j].idx = i; 14413ff5a4dcSJakub Kicinski break; 14423ff5a4dcSJakub Kicinski } 14433ff5a4dcSJakub Kicinski i++; 14443ff5a4dcSJakub Kicinski } 14453ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 14463ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 14473ff5a4dcSJakub Kicinski goto err_close_obj; 14483ff5a4dcSJakub Kicinski } 14493ff5a4dcSJakub Kicinski j++; 14503ff5a4dcSJakub Kicinski } 14513ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 14523ff5a4dcSJakub Kicinski if (j) 14533ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 14543ff5a4dcSJakub Kicinski map_replace_compar); 14553ff5a4dcSJakub Kicinski 14563ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 14573ff5a4dcSJakub Kicinski j = 0; 14583ff5a4dcSJakub Kicinski idx = 0; 1459f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 1460c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1461c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1462c8406848SJakub Kicinski 14633ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 14643ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 14653ff5a4dcSJakub Kicinski if (err) { 14663ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 14673ff5a4dcSJakub Kicinski goto err_close_obj; 14683ff5a4dcSJakub Kicinski } 14693ff5a4dcSJakub Kicinski 14703ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 14713ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 14723ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 14733ff5a4dcSJakub Kicinski idx); 14743ff5a4dcSJakub Kicinski goto err_close_obj; 14753ff5a4dcSJakub Kicinski } 14763ff5a4dcSJakub Kicinski } 14773ff5a4dcSJakub Kicinski 14783ff5a4dcSJakub Kicinski idx++; 14793ff5a4dcSJakub Kicinski } 14803ff5a4dcSJakub Kicinski if (j < old_map_fds) { 14813ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 14823ff5a4dcSJakub Kicinski goto err_close_obj; 14833ff5a4dcSJakub Kicinski } 14843ff5a4dcSJakub Kicinski 148555d77807SQuentin Monnet load_attr.obj = obj; 148655d77807SQuentin Monnet if (verifier_logs) 148755d77807SQuentin Monnet /* log_level1 + log_level2 + stats, but not stable UAPI */ 148855d77807SQuentin Monnet load_attr.log_level = 1 + 2 + 4; 148955d77807SQuentin Monnet 149055d77807SQuentin Monnet err = bpf_object__load_xattr(&load_attr); 1491c8406848SJakub Kicinski if (err) { 1492c8406848SJakub Kicinski p_err("failed to load object file"); 1493c8406848SJakub Kicinski goto err_close_obj; 1494c8406848SJakub Kicinski } 1495c8406848SJakub Kicinski 149677380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 149777380998SStanislav Fomichev if (err) 1498bfee71fbSJakub Kicinski goto err_close_obj; 149949a086c2SRoman Gushchin 150077380998SStanislav Fomichev if (first_prog_only) { 150177380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 150277380998SStanislav Fomichev if (!prog) { 150377380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 150477380998SStanislav Fomichev goto err_close_obj; 150577380998SStanislav Fomichev } 150677380998SStanislav Fomichev 150777380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 150877380998SStanislav Fomichev if (err) { 150977380998SStanislav Fomichev p_err("failed to pin program %s", 151077380998SStanislav Fomichev bpf_program__title(prog, false)); 151177380998SStanislav Fomichev goto err_close_obj; 151277380998SStanislav Fomichev } 151377380998SStanislav Fomichev } else { 151477380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 151577380998SStanislav Fomichev if (err) { 151677380998SStanislav Fomichev p_err("failed to pin all programs"); 151777380998SStanislav Fomichev goto err_close_obj; 151877380998SStanislav Fomichev } 151977380998SStanislav Fomichev } 152077380998SStanislav Fomichev 15213767a94bSStanislav Fomichev if (pinmaps) { 15223767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 15233767a94bSStanislav Fomichev if (err) { 15243767a94bSStanislav Fomichev p_err("failed to pin all maps"); 15253767a94bSStanislav Fomichev goto err_unpin; 15263767a94bSStanislav Fomichev } 15273767a94bSStanislav Fomichev } 15283767a94bSStanislav Fomichev 152949a086c2SRoman Gushchin if (json_output) 153049a086c2SRoman Gushchin jsonw_null(json_wtr); 153149a086c2SRoman Gushchin 1532bfee71fbSJakub Kicinski bpf_object__close(obj); 15333ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 15343ff5a4dcSJakub Kicinski close(map_replace[i].fd); 15353ff5a4dcSJakub Kicinski free(map_replace); 1536bfee71fbSJakub Kicinski 153749a086c2SRoman Gushchin return 0; 1538bfee71fbSJakub Kicinski 15393767a94bSStanislav Fomichev err_unpin: 15403767a94bSStanislav Fomichev if (first_prog_only) 15413767a94bSStanislav Fomichev unlink(pinfile); 15423767a94bSStanislav Fomichev else 15433767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1544bfee71fbSJakub Kicinski err_close_obj: 1545bfee71fbSJakub Kicinski bpf_object__close(obj); 15463ff5a4dcSJakub Kicinski err_free_reuse_maps: 15473ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 15483ff5a4dcSJakub Kicinski close(map_replace[i].fd); 15493ff5a4dcSJakub Kicinski free(map_replace); 1550bfee71fbSJakub Kicinski return -1; 155149a086c2SRoman Gushchin } 155249a086c2SRoman Gushchin 155377380998SStanislav Fomichev static int do_load(int argc, char **argv) 155477380998SStanislav Fomichev { 155577380998SStanislav Fomichev return load_with_options(argc, argv, true); 155677380998SStanislav Fomichev } 155777380998SStanislav Fomichev 155877380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 155977380998SStanislav Fomichev { 156077380998SStanislav Fomichev return load_with_options(argc, argv, false); 156177380998SStanislav Fomichev } 156277380998SStanislav Fomichev 156347c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 156447c09d6aSSong Liu 156547c09d6aSSong Liu static int do_profile(int argc, char **argv) 156647c09d6aSSong Liu { 156714e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 156847c09d6aSSong Liu return 0; 156947c09d6aSSong Liu } 157047c09d6aSSong Liu 157147c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 157247c09d6aSSong Liu 157347c09d6aSSong Liu #include "profiler.skel.h" 157447c09d6aSSong Liu 157547c09d6aSSong Liu struct profile_metric { 157647c09d6aSSong Liu const char *name; 157747c09d6aSSong Liu struct bpf_perf_event_value val; 157847c09d6aSSong Liu struct perf_event_attr attr; 157947c09d6aSSong Liu bool selected; 158047c09d6aSSong Liu 158147c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 158247c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 158347c09d6aSSong Liu const char *ratio_desc; 158447c09d6aSSong Liu const float ratio_mul; 158547c09d6aSSong Liu } metrics[] = { 158647c09d6aSSong Liu { 158747c09d6aSSong Liu .name = "cycles", 158847c09d6aSSong Liu .attr = { 158947c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 159047c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 159147c09d6aSSong Liu .exclude_user = 1, 159247c09d6aSSong Liu }, 159347c09d6aSSong Liu }, 159447c09d6aSSong Liu { 159547c09d6aSSong Liu .name = "instructions", 159647c09d6aSSong Liu .attr = { 159747c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 159847c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 159947c09d6aSSong Liu .exclude_user = 1, 160047c09d6aSSong Liu }, 160147c09d6aSSong Liu .ratio_metric = 1, 160247c09d6aSSong Liu .ratio_desc = "insns per cycle", 160347c09d6aSSong Liu .ratio_mul = 1.0, 160447c09d6aSSong Liu }, 160547c09d6aSSong Liu { 160647c09d6aSSong Liu .name = "l1d_loads", 160747c09d6aSSong Liu .attr = { 160847c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 160947c09d6aSSong Liu .config = 161047c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 161147c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 161247c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 161347c09d6aSSong Liu .exclude_user = 1, 161447c09d6aSSong Liu }, 161547c09d6aSSong Liu }, 161647c09d6aSSong Liu { 161747c09d6aSSong Liu .name = "llc_misses", 161847c09d6aSSong Liu .attr = { 161947c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 162047c09d6aSSong Liu .config = 162147c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 162247c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 162347c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 162447c09d6aSSong Liu .exclude_user = 1 162547c09d6aSSong Liu }, 162647c09d6aSSong Liu .ratio_metric = 2, 162747c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 162847c09d6aSSong Liu .ratio_mul = 1e6, 162947c09d6aSSong Liu }, 163047c09d6aSSong Liu }; 163147c09d6aSSong Liu 163247c09d6aSSong Liu static __u64 profile_total_count; 163347c09d6aSSong Liu 163447c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 163547c09d6aSSong Liu 163647c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 163747c09d6aSSong Liu { 163847c09d6aSSong Liu unsigned int metric_cnt; 163947c09d6aSSong Liu int selected_cnt = 0; 164047c09d6aSSong Liu unsigned int i; 164147c09d6aSSong Liu 164247c09d6aSSong Liu metric_cnt = sizeof(metrics) / sizeof(struct profile_metric); 164347c09d6aSSong Liu 164447c09d6aSSong Liu while (argc > 0) { 164547c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 164647c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 164747c09d6aSSong Liu if (!metrics[i].selected) 164847c09d6aSSong Liu selected_cnt++; 164947c09d6aSSong Liu metrics[i].selected = true; 165047c09d6aSSong Liu break; 165147c09d6aSSong Liu } 165247c09d6aSSong Liu } 165347c09d6aSSong Liu if (i == metric_cnt) { 165447c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 165547c09d6aSSong Liu return -1; 165647c09d6aSSong Liu } 165747c09d6aSSong Liu NEXT_ARG(); 165847c09d6aSSong Liu } 165947c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 166047c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 166147c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 166247c09d6aSSong Liu return -1; 166347c09d6aSSong Liu } 166447c09d6aSSong Liu return selected_cnt; 166547c09d6aSSong Liu } 166647c09d6aSSong Liu 166747c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 166847c09d6aSSong Liu { 166947c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 167047c09d6aSSong Liu int reading_map_fd, count_map_fd; 167147c09d6aSSong Liu __u64 counts[num_cpu]; 167247c09d6aSSong Liu __u32 key = 0; 167347c09d6aSSong Liu int err; 167447c09d6aSSong Liu 167547c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 167647c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 167747c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 167847c09d6aSSong Liu p_err("failed to get fd for map"); 167947c09d6aSSong Liu return; 168047c09d6aSSong Liu } 168147c09d6aSSong Liu 168247c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 168347c09d6aSSong Liu if (err) { 168447c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 168547c09d6aSSong Liu return; 168647c09d6aSSong Liu } 168747c09d6aSSong Liu 168847c09d6aSSong Liu profile_total_count = 0; 168947c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 169047c09d6aSSong Liu profile_total_count += counts[cpu]; 169147c09d6aSSong Liu 169247c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 169347c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 169447c09d6aSSong Liu 169547c09d6aSSong Liu if (!metrics[m].selected) 169647c09d6aSSong Liu continue; 169747c09d6aSSong Liu 169847c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 169947c09d6aSSong Liu if (err) { 170047c09d6aSSong Liu p_err("failed to read reading_map: %s", 170147c09d6aSSong Liu strerror(errno)); 170247c09d6aSSong Liu return; 170347c09d6aSSong Liu } 170447c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 170547c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 170647c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 170747c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 170847c09d6aSSong Liu } 170947c09d6aSSong Liu key++; 171047c09d6aSSong Liu } 171147c09d6aSSong Liu } 171247c09d6aSSong Liu 171347c09d6aSSong Liu static void profile_print_readings_json(void) 171447c09d6aSSong Liu { 171547c09d6aSSong Liu __u32 m; 171647c09d6aSSong Liu 171747c09d6aSSong Liu jsonw_start_array(json_wtr); 171847c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 171947c09d6aSSong Liu if (!metrics[m].selected) 172047c09d6aSSong Liu continue; 172147c09d6aSSong Liu jsonw_start_object(json_wtr); 172247c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 172347c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 172447c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 172547c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 172647c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 172747c09d6aSSong Liu 172847c09d6aSSong Liu jsonw_end_object(json_wtr); 172947c09d6aSSong Liu } 173047c09d6aSSong Liu jsonw_end_array(json_wtr); 173147c09d6aSSong Liu } 173247c09d6aSSong Liu 173347c09d6aSSong Liu static void profile_print_readings_plain(void) 173447c09d6aSSong Liu { 173547c09d6aSSong Liu __u32 m; 173647c09d6aSSong Liu 173747c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 173847c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 173947c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 174047c09d6aSSong Liu int r; 174147c09d6aSSong Liu 174247c09d6aSSong Liu if (!metrics[m].selected) 174347c09d6aSSong Liu continue; 174447c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 174547c09d6aSSong Liu 174647c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 174747c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 174847c09d6aSSong Liu metrics[r].val.counter > 0) { 174947c09d6aSSong Liu printf("# %8.2f %-30s", 175047c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 175147c09d6aSSong Liu metrics[r].val.counter, 175247c09d6aSSong Liu metrics[m].ratio_desc); 175347c09d6aSSong Liu } else { 175447c09d6aSSong Liu printf("%-41s", ""); 175547c09d6aSSong Liu } 175647c09d6aSSong Liu 175747c09d6aSSong Liu if (val->enabled > val->running) 175847c09d6aSSong Liu printf("(%4.2f%%)", 175947c09d6aSSong Liu val->running * 100.0 / val->enabled); 176047c09d6aSSong Liu printf("\n"); 176147c09d6aSSong Liu } 176247c09d6aSSong Liu } 176347c09d6aSSong Liu 176447c09d6aSSong Liu static void profile_print_readings(void) 176547c09d6aSSong Liu { 176647c09d6aSSong Liu if (json_output) 176747c09d6aSSong Liu profile_print_readings_json(); 176847c09d6aSSong Liu else 176947c09d6aSSong Liu profile_print_readings_plain(); 177047c09d6aSSong Liu } 177147c09d6aSSong Liu 177247c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 177347c09d6aSSong Liu { 177447c09d6aSSong Liu struct bpf_prog_info_linear *info_linear; 177547c09d6aSSong Liu struct bpf_func_info *func_info; 177647c09d6aSSong Liu const struct btf_type *t; 177747c09d6aSSong Liu char *name = NULL; 177847c09d6aSSong Liu struct btf *btf; 177947c09d6aSSong Liu 178047c09d6aSSong Liu info_linear = bpf_program__get_prog_info_linear( 178147c09d6aSSong Liu tgt_fd, 1UL << BPF_PROG_INFO_FUNC_INFO); 178247c09d6aSSong Liu if (IS_ERR_OR_NULL(info_linear)) { 178347c09d6aSSong Liu p_err("failed to get info_linear for prog FD %d", tgt_fd); 178447c09d6aSSong Liu return NULL; 178547c09d6aSSong Liu } 178647c09d6aSSong Liu 178747c09d6aSSong Liu if (info_linear->info.btf_id == 0 || 178847c09d6aSSong Liu btf__get_from_id(info_linear->info.btf_id, &btf)) { 178947c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 179047c09d6aSSong Liu goto out; 179147c09d6aSSong Liu } 179247c09d6aSSong Liu 179347c09d6aSSong Liu func_info = (struct bpf_func_info *)(info_linear->info.func_info); 179447c09d6aSSong Liu t = btf__type_by_id(btf, func_info[0].type_id); 179547c09d6aSSong Liu if (!t) { 179647c09d6aSSong Liu p_err("btf %d doesn't have type %d", 179747c09d6aSSong Liu info_linear->info.btf_id, func_info[0].type_id); 179847c09d6aSSong Liu goto out; 179947c09d6aSSong Liu } 180047c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 180147c09d6aSSong Liu out: 180247c09d6aSSong Liu free(info_linear); 180347c09d6aSSong Liu return name; 180447c09d6aSSong Liu } 180547c09d6aSSong Liu 180647c09d6aSSong Liu static struct profiler_bpf *profile_obj; 180747c09d6aSSong Liu static int profile_tgt_fd = -1; 180847c09d6aSSong Liu static char *profile_tgt_name; 180947c09d6aSSong Liu static int *profile_perf_events; 181047c09d6aSSong Liu static int profile_perf_event_cnt; 181147c09d6aSSong Liu 181247c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 181347c09d6aSSong Liu { 181447c09d6aSSong Liu int i; 181547c09d6aSSong Liu 181647c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 181747c09d6aSSong Liu close(profile_perf_events[i]); 181847c09d6aSSong Liu 181947c09d6aSSong Liu free(profile_perf_events); 182047c09d6aSSong Liu profile_perf_event_cnt = 0; 182147c09d6aSSong Liu } 182247c09d6aSSong Liu 182347c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 182447c09d6aSSong Liu { 182547c09d6aSSong Liu unsigned int cpu, m; 182647c09d6aSSong Liu int map_fd, pmu_fd; 182747c09d6aSSong Liu 182847c09d6aSSong Liu profile_perf_events = calloc( 182947c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 183047c09d6aSSong Liu if (!profile_perf_events) { 183147c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 183247c09d6aSSong Liu strerror(errno)); 183347c09d6aSSong Liu return -1; 183447c09d6aSSong Liu } 183547c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 183647c09d6aSSong Liu if (map_fd < 0) { 183747c09d6aSSong Liu p_err("failed to get fd for events map"); 183847c09d6aSSong Liu return -1; 183947c09d6aSSong Liu } 184047c09d6aSSong Liu 184147c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 184247c09d6aSSong Liu if (!metrics[m].selected) 184347c09d6aSSong Liu continue; 184447c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 184547c09d6aSSong Liu pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 184647c09d6aSSong Liu -1/*pid*/, cpu, -1/*group_fd*/, 0); 184747c09d6aSSong Liu if (pmu_fd < 0 || 184847c09d6aSSong Liu bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 184947c09d6aSSong Liu &pmu_fd, BPF_ANY) || 185047c09d6aSSong Liu ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 185147c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 185247c09d6aSSong Liu metrics[m].name, cpu); 185347c09d6aSSong Liu return -1; 185447c09d6aSSong Liu } 185547c09d6aSSong Liu profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 185647c09d6aSSong Liu } 185747c09d6aSSong Liu } 185847c09d6aSSong Liu return 0; 185947c09d6aSSong Liu } 186047c09d6aSSong Liu 186147c09d6aSSong Liu static void profile_print_and_cleanup(void) 186247c09d6aSSong Liu { 186347c09d6aSSong Liu profile_close_perf_events(profile_obj); 186447c09d6aSSong Liu profile_read_values(profile_obj); 186547c09d6aSSong Liu profile_print_readings(); 186647c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 186747c09d6aSSong Liu 186847c09d6aSSong Liu close(profile_tgt_fd); 186947c09d6aSSong Liu free(profile_tgt_name); 187047c09d6aSSong Liu } 187147c09d6aSSong Liu 187247c09d6aSSong Liu static void int_exit(int signo) 187347c09d6aSSong Liu { 187447c09d6aSSong Liu profile_print_and_cleanup(); 187547c09d6aSSong Liu exit(0); 187647c09d6aSSong Liu } 187747c09d6aSSong Liu 187847c09d6aSSong Liu static int do_profile(int argc, char **argv) 187947c09d6aSSong Liu { 188047c09d6aSSong Liu int num_metric, num_cpu, err = -1; 188147c09d6aSSong Liu struct bpf_program *prog; 188247c09d6aSSong Liu unsigned long duration; 188347c09d6aSSong Liu char *endptr; 188447c09d6aSSong Liu 188547c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 188647c09d6aSSong Liu if (!REQ_ARGS(3)) 188747c09d6aSSong Liu return -EINVAL; 188847c09d6aSSong Liu 188947c09d6aSSong Liu /* parse target fd */ 189047c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 189147c09d6aSSong Liu if (profile_tgt_fd < 0) { 189247c09d6aSSong Liu p_err("failed to parse fd"); 189347c09d6aSSong Liu return -1; 189447c09d6aSSong Liu } 189547c09d6aSSong Liu 189647c09d6aSSong Liu /* parse profiling optional duration */ 189747c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 189847c09d6aSSong Liu NEXT_ARG(); 189947c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 190047c09d6aSSong Liu if (*endptr) 190147c09d6aSSong Liu usage(); 190247c09d6aSSong Liu NEXT_ARG(); 190347c09d6aSSong Liu } else { 190447c09d6aSSong Liu duration = UINT_MAX; 190547c09d6aSSong Liu } 190647c09d6aSSong Liu 190747c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 190847c09d6aSSong Liu if (num_metric <= 0) 190947c09d6aSSong Liu goto out; 191047c09d6aSSong Liu 191147c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 191247c09d6aSSong Liu if (num_cpu <= 0) { 191347c09d6aSSong Liu p_err("failed to identify number of CPUs"); 191447c09d6aSSong Liu goto out; 191547c09d6aSSong Liu } 191647c09d6aSSong Liu 191747c09d6aSSong Liu profile_obj = profiler_bpf__open(); 191847c09d6aSSong Liu if (!profile_obj) { 191947c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 192047c09d6aSSong Liu goto out; 192147c09d6aSSong Liu } 192247c09d6aSSong Liu 192347c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 192447c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 192547c09d6aSSong Liu 192647c09d6aSSong Liu /* adjust map sizes */ 192747c09d6aSSong Liu bpf_map__resize(profile_obj->maps.events, num_metric * num_cpu); 192847c09d6aSSong Liu bpf_map__resize(profile_obj->maps.fentry_readings, num_metric); 192947c09d6aSSong Liu bpf_map__resize(profile_obj->maps.accum_readings, num_metric); 193047c09d6aSSong Liu bpf_map__resize(profile_obj->maps.counts, 1); 193147c09d6aSSong Liu 193247c09d6aSSong Liu /* change target name */ 193347c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 193447c09d6aSSong Liu if (!profile_tgt_name) 193547c09d6aSSong Liu goto out; 193647c09d6aSSong Liu 193747c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 193847c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 193947c09d6aSSong Liu profile_tgt_name); 194047c09d6aSSong Liu if (err) { 194147c09d6aSSong Liu p_err("failed to set attach target\n"); 194247c09d6aSSong Liu goto out; 194347c09d6aSSong Liu } 194447c09d6aSSong Liu } 194547c09d6aSSong Liu 194647c09d6aSSong Liu set_max_rlimit(); 194747c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 194847c09d6aSSong Liu if (err) { 194947c09d6aSSong Liu p_err("failed to load profile_obj"); 195047c09d6aSSong Liu goto out; 195147c09d6aSSong Liu } 195247c09d6aSSong Liu 195347c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 195447c09d6aSSong Liu if (err) 195547c09d6aSSong Liu goto out; 195647c09d6aSSong Liu 195747c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 195847c09d6aSSong Liu if (err) { 195947c09d6aSSong Liu p_err("failed to attach profile_obj"); 196047c09d6aSSong Liu goto out; 196147c09d6aSSong Liu } 196247c09d6aSSong Liu signal(SIGINT, int_exit); 196347c09d6aSSong Liu 196447c09d6aSSong Liu sleep(duration); 196547c09d6aSSong Liu profile_print_and_cleanup(); 196647c09d6aSSong Liu return 0; 196747c09d6aSSong Liu 196847c09d6aSSong Liu out: 196947c09d6aSSong Liu profile_close_perf_events(profile_obj); 197047c09d6aSSong Liu if (profile_obj) 197147c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 197247c09d6aSSong Liu close(profile_tgt_fd); 197347c09d6aSSong Liu free(profile_tgt_name); 197447c09d6aSSong Liu return err; 197547c09d6aSSong Liu } 197647c09d6aSSong Liu 197747c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 197847c09d6aSSong Liu 197971bb428fSJakub Kicinski static int do_help(int argc, char **argv) 198071bb428fSJakub Kicinski { 1981004b45c0SQuentin Monnet if (json_output) { 1982004b45c0SQuentin Monnet jsonw_null(json_wtr); 1983004b45c0SQuentin Monnet return 0; 1984004b45c0SQuentin Monnet } 1985004b45c0SQuentin Monnet 198671bb428fSJakub Kicinski fprintf(stderr, 19876ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1988b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1989b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 199071bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 199177380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 199277380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 19933767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 19943767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1995092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1996092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1997ba95c745SQuentin Monnet " %s %s run PROG \\\n" 1998ba95c745SQuentin Monnet " data_in FILE \\\n" 1999ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2000ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2001ba95c745SQuentin Monnet " [repeat N]\n" 200247c09d6aSSong Liu " %s %s profile PROG [duration DURATION] METRICs\n" 200330da46b5SQuentin Monnet " %s %s tracelog\n" 200471bb428fSJakub Kicinski " %s %s help\n" 200571bb428fSJakub Kicinski "\n" 20063ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 200771bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 200849f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 200949f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 201049f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 201149f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2012f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 201349f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 201449f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 2015000aa125SDaniel Borkmann " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 20163494bec0SAndrey Ignatov " cgroup/recvmsg6 | cgroup/getsockopt | cgroup/setsockopt |\n" 20173494bec0SAndrey Ignatov " struct_ops | fentry | fexit | freplace }\n" 2018a5d9265eSAlban Crequy " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 2019092f0892SStanislav Fomichev " flow_dissector }\n" 202047c09d6aSSong Liu " METRIC := { cycles | instructions | l1d_loads | llc_misses }\n" 20210641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 202271bb428fSJakub Kicinski "", 202371bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 2024b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 2025ba95c745SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 202647c09d6aSSong Liu bin_name, argv[-2], bin_name, argv[-2]); 202771bb428fSJakub Kicinski 202871bb428fSJakub Kicinski return 0; 202971bb428fSJakub Kicinski } 203071bb428fSJakub Kicinski 203171bb428fSJakub Kicinski static const struct cmd cmds[] = { 203271bb428fSJakub Kicinski { "show", do_show }, 20336ebe6dbdSJakub Kicinski { "list", do_show }, 20349f606179SQuentin Monnet { "help", do_help }, 203571bb428fSJakub Kicinski { "dump", do_dump }, 203671bb428fSJakub Kicinski { "pin", do_pin }, 203749a086c2SRoman Gushchin { "load", do_load }, 203877380998SStanislav Fomichev { "loadall", do_loadall }, 2039b7d3826cSJohn Fastabend { "attach", do_attach }, 2040b7d3826cSJohn Fastabend { "detach", do_detach }, 204130da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2042ba95c745SQuentin Monnet { "run", do_run }, 204347c09d6aSSong Liu { "profile", do_profile }, 204471bb428fSJakub Kicinski { 0 } 204571bb428fSJakub Kicinski }; 204671bb428fSJakub Kicinski 204771bb428fSJakub Kicinski int do_prog(int argc, char **argv) 204871bb428fSJakub Kicinski { 204971bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 205071bb428fSJakub Kicinski } 2051