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> 7c9c35995SJakub Kicinski #include <stdarg.h> 871bb428fSJakub Kicinski #include <stdio.h> 971bb428fSJakub Kicinski #include <stdlib.h> 1071bb428fSJakub Kicinski #include <string.h> 1171bb428fSJakub Kicinski #include <time.h> 1271bb428fSJakub Kicinski #include <unistd.h> 13ba6dd679SJakub Kicinski #include <net/if.h> 1471bb428fSJakub Kicinski #include <sys/types.h> 1571bb428fSJakub Kicinski #include <sys/stat.h> 1671bb428fSJakub Kicinski 17c8406848SJakub Kicinski #include <linux/err.h> 18ba95c745SQuentin Monnet #include <linux/sizes.h> 19c8406848SJakub Kicinski 20*229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h> 21*229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h> 22*229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h> 2371bb428fSJakub Kicinski 24b6c1cedbSJiong Wang #include "cfg.h" 2571bb428fSJakub Kicinski #include "main.h" 2673bb5b4fSJiong Wang #include "xlated_dumper.h" 2771bb428fSJakub Kicinski 28ec202509SPaul Chaignon enum dump_mode { 29ec202509SPaul Chaignon DUMP_JITED, 30ec202509SPaul Chaignon DUMP_XLATED, 31ec202509SPaul Chaignon }; 32ec202509SPaul Chaignon 33b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 34b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 35b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 36b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 37092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 38b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 39b7d3826cSJohn Fastabend }; 40b7d3826cSJohn Fastabend 41c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 42b7d3826cSJohn Fastabend { 43b7d3826cSJohn Fastabend enum bpf_attach_type type; 44b7d3826cSJohn Fastabend 45b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 46b7d3826cSJohn Fastabend if (attach_type_strings[type] && 47b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 48b7d3826cSJohn Fastabend return type; 49b7d3826cSJohn Fastabend } 50b7d3826cSJohn Fastabend 51b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 52b7d3826cSJohn Fastabend } 53b7d3826cSJohn Fastabend 5471bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 5571bb428fSJakub Kicinski { 5671bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 5771bb428fSJakub Kicinski time_t wallclock_secs; 5871bb428fSJakub Kicinski struct tm load_tm; 5971bb428fSJakub Kicinski 6071bb428fSJakub Kicinski buf[--size] = '\0'; 6171bb428fSJakub Kicinski 6271bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 6371bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 6471bb428fSJakub Kicinski perror("Can't read clocks"); 6571bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 6671bb428fSJakub Kicinski return; 6771bb428fSJakub Kicinski } 6871bb428fSJakub Kicinski 6971bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 7007480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 7107480cbcSJakub Kicinski 1000000000; 7207480cbcSJakub Kicinski 7371bb428fSJakub Kicinski 7471bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 7571bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 7671bb428fSJakub Kicinski return; 7771bb428fSJakub Kicinski } 7871bb428fSJakub Kicinski 79a3fe1f6fSQuentin Monnet if (json_output) 80a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 81a3fe1f6fSQuentin Monnet else 82a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 8371bb428fSJakub Kicinski } 8471bb428fSJakub Kicinski 85a7d22ca2SPaul Chaignon static int prog_fd_by_nametag(void *nametag, int **fds, bool tag) 8671bb428fSJakub Kicinski { 8771bb428fSJakub Kicinski unsigned int id = 0; 88ec202509SPaul Chaignon int fd, nb_fds = 0; 89ec202509SPaul Chaignon void *tmp; 9071bb428fSJakub Kicinski int err; 9171bb428fSJakub Kicinski 9271bb428fSJakub Kicinski while (true) { 93752bcf80SJiri Olsa struct bpf_prog_info info = {}; 94752bcf80SJiri Olsa __u32 len = sizeof(info); 95752bcf80SJiri Olsa 9671bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 9771bb428fSJakub Kicinski if (err) { 98ec202509SPaul Chaignon if (errno != ENOENT) { 999a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 100ec202509SPaul Chaignon goto err_close_fds; 101ec202509SPaul Chaignon } 102ec202509SPaul Chaignon return nb_fds; 10371bb428fSJakub Kicinski } 10471bb428fSJakub Kicinski 10571bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 10671bb428fSJakub Kicinski if (fd < 0) { 1079a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 10871bb428fSJakub Kicinski id, strerror(errno)); 109ec202509SPaul Chaignon goto err_close_fds; 11071bb428fSJakub Kicinski } 11171bb428fSJakub Kicinski 11271bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 11371bb428fSJakub Kicinski if (err) { 1149a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 11571bb428fSJakub Kicinski id, strerror(errno)); 116ec202509SPaul Chaignon goto err_close_fd; 117ec202509SPaul Chaignon } 118ec202509SPaul Chaignon 119a7d22ca2SPaul Chaignon if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) || 120a7d22ca2SPaul Chaignon (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) { 12171bb428fSJakub Kicinski close(fd); 122ec202509SPaul Chaignon continue; 123ec202509SPaul Chaignon } 124ec202509SPaul Chaignon 125ec202509SPaul Chaignon if (nb_fds > 0) { 126ec202509SPaul Chaignon tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); 127ec202509SPaul Chaignon if (!tmp) { 128ec202509SPaul Chaignon p_err("failed to realloc"); 129ec202509SPaul Chaignon goto err_close_fd; 130ec202509SPaul Chaignon } 131ec202509SPaul Chaignon *fds = tmp; 132ec202509SPaul Chaignon } 133ec202509SPaul Chaignon (*fds)[nb_fds++] = fd; 134ec202509SPaul Chaignon } 135ec202509SPaul Chaignon 136ec202509SPaul Chaignon err_close_fd: 137ec202509SPaul Chaignon close(fd); 138ec202509SPaul Chaignon err_close_fds: 139ec202509SPaul Chaignon while (--nb_fds >= 0) 140ec202509SPaul Chaignon close((*fds)[nb_fds]); 14171bb428fSJakub Kicinski return -1; 14271bb428fSJakub Kicinski } 14371bb428fSJakub Kicinski 144ec202509SPaul Chaignon static int prog_parse_fds(int *argc, char ***argv, int **fds) 14571bb428fSJakub Kicinski { 14671bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 14771bb428fSJakub Kicinski unsigned int id; 14871bb428fSJakub Kicinski char *endptr; 14971bb428fSJakub Kicinski 15071bb428fSJakub Kicinski NEXT_ARGP(); 15171bb428fSJakub Kicinski 15271bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 15371bb428fSJakub Kicinski if (*endptr) { 1549a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 15571bb428fSJakub Kicinski return -1; 15671bb428fSJakub Kicinski } 15771bb428fSJakub Kicinski NEXT_ARGP(); 15871bb428fSJakub Kicinski 159ec202509SPaul Chaignon (*fds)[0] = bpf_prog_get_fd_by_id(id); 160ec202509SPaul Chaignon if ((*fds)[0] < 0) { 1619a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 162ec202509SPaul Chaignon return -1; 163ec202509SPaul Chaignon } 164ec202509SPaul Chaignon return 1; 16571bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 16671bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 16771bb428fSJakub Kicinski 16871bb428fSJakub Kicinski NEXT_ARGP(); 16971bb428fSJakub Kicinski 17071bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 17171bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 17271bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1739a5ab8bfSQuentin Monnet p_err("can't parse tag"); 17471bb428fSJakub Kicinski return -1; 17571bb428fSJakub Kicinski } 17671bb428fSJakub Kicinski NEXT_ARGP(); 17771bb428fSJakub Kicinski 178a7d22ca2SPaul Chaignon return prog_fd_by_nametag(tag, fds, true); 179a7d22ca2SPaul Chaignon } else if (is_prefix(**argv, "name")) { 180a7d22ca2SPaul Chaignon char *name; 181a7d22ca2SPaul Chaignon 182a7d22ca2SPaul Chaignon NEXT_ARGP(); 183a7d22ca2SPaul Chaignon 184a7d22ca2SPaul Chaignon name = **argv; 185a7d22ca2SPaul Chaignon if (strlen(name) > BPF_OBJ_NAME_LEN - 1) { 186a7d22ca2SPaul Chaignon p_err("can't parse name"); 187a7d22ca2SPaul Chaignon return -1; 188a7d22ca2SPaul Chaignon } 189a7d22ca2SPaul Chaignon NEXT_ARGP(); 190a7d22ca2SPaul Chaignon 191a7d22ca2SPaul Chaignon return prog_fd_by_nametag(name, fds, false); 19271bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 19371bb428fSJakub Kicinski char *path; 19471bb428fSJakub Kicinski 19571bb428fSJakub Kicinski NEXT_ARGP(); 19671bb428fSJakub Kicinski 19771bb428fSJakub Kicinski path = **argv; 19871bb428fSJakub Kicinski NEXT_ARGP(); 19971bb428fSJakub Kicinski 200ec202509SPaul Chaignon (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG); 201ec202509SPaul Chaignon if ((*fds)[0] < 0) 202ec202509SPaul Chaignon return -1; 203ec202509SPaul Chaignon return 1; 20471bb428fSJakub Kicinski } 20571bb428fSJakub Kicinski 206a7d22ca2SPaul Chaignon p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv); 20771bb428fSJakub Kicinski return -1; 20871bb428fSJakub Kicinski } 20971bb428fSJakub Kicinski 210ec202509SPaul Chaignon int prog_parse_fd(int *argc, char ***argv) 211ec202509SPaul Chaignon { 212ec202509SPaul Chaignon int *fds = NULL; 213ec202509SPaul Chaignon int nb_fds, fd; 214ec202509SPaul Chaignon 215ec202509SPaul Chaignon fds = malloc(sizeof(int)); 216ec202509SPaul Chaignon if (!fds) { 217ec202509SPaul Chaignon p_err("mem alloc failed"); 218ec202509SPaul Chaignon return -1; 219ec202509SPaul Chaignon } 220ec202509SPaul Chaignon nb_fds = prog_parse_fds(argc, argv, &fds); 221ec202509SPaul Chaignon if (nb_fds != 1) { 222ec202509SPaul Chaignon if (nb_fds > 1) { 223ec202509SPaul Chaignon p_err("several programs match this handle"); 224ec202509SPaul Chaignon while (nb_fds--) 225ec202509SPaul Chaignon close(fds[nb_fds]); 226ec202509SPaul Chaignon } 227ec202509SPaul Chaignon fd = -1; 228ec202509SPaul Chaignon goto exit_free; 229ec202509SPaul Chaignon } 230ec202509SPaul Chaignon 231ec202509SPaul Chaignon fd = fds[0]; 232ec202509SPaul Chaignon exit_free: 233ec202509SPaul Chaignon free(fds); 234ec202509SPaul Chaignon return fd; 235ec202509SPaul Chaignon } 236ec202509SPaul Chaignon 23771bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 23871bb428fSJakub Kicinski { 23971bb428fSJakub Kicinski struct bpf_prog_info info = {}; 24071bb428fSJakub Kicinski __u32 len = sizeof(info); 24171bb428fSJakub Kicinski __u32 map_ids[num_maps]; 24271bb428fSJakub Kicinski unsigned int i; 24371bb428fSJakub Kicinski int err; 24471bb428fSJakub Kicinski 24571bb428fSJakub Kicinski info.nr_map_ids = num_maps; 24671bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 24771bb428fSJakub Kicinski 24871bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 24971bb428fSJakub Kicinski if (err || !info.nr_map_ids) 25071bb428fSJakub Kicinski return; 25171bb428fSJakub Kicinski 252743cc665SQuentin Monnet if (json_output) { 253743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 254743cc665SQuentin Monnet jsonw_start_array(json_wtr); 255743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 256743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 257743cc665SQuentin Monnet jsonw_end_array(json_wtr); 258743cc665SQuentin Monnet } else { 25971bb428fSJakub Kicinski printf(" map_ids "); 26071bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 26171bb428fSJakub Kicinski printf("%u%s", map_ids[i], 26271bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 26371bb428fSJakub Kicinski } 26471bb428fSJakub Kicinski } 26571bb428fSJakub Kicinski 266ec202509SPaul Chaignon static void print_prog_header_json(struct bpf_prog_info *info) 267743cc665SQuentin Monnet { 268743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 269743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 270743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 271743cc665SQuentin Monnet prog_type_name[info->type]); 27271bb428fSJakub Kicinski else 273743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 27471bb428fSJakub Kicinski 275743cc665SQuentin Monnet if (*info->name) 276743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 27771bb428fSJakub Kicinski 278743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 279743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 280743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 281743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 28271bb428fSJakub Kicinski 2839b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 28488ad472bSAlexei Starovoitov if (info->run_time_ns) { 28588ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 28688ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 28788ad472bSAlexei Starovoitov } 288ec202509SPaul Chaignon } 2899b984a20SJiri Olsa 290ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 291ec202509SPaul Chaignon { 292ec202509SPaul Chaignon char *memlock; 293ec202509SPaul Chaignon 294ec202509SPaul Chaignon jsonw_start_object(json_wtr); 295ec202509SPaul Chaignon print_prog_header_json(info); 29652262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 29752262210SJakub Kicinski 298743cc665SQuentin Monnet if (info->load_time) { 29971bb428fSJakub Kicinski char buf[32]; 30071bb428fSJakub Kicinski 301743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 30271bb428fSJakub Kicinski 30371bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 304a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 305a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 306743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 30771bb428fSJakub Kicinski } 30871bb428fSJakub Kicinski 309743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 31071bb428fSJakub Kicinski 311743cc665SQuentin Monnet if (info->jited_prog_len) { 312743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 313743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 314743cc665SQuentin Monnet } else { 315743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 316743cc665SQuentin Monnet } 317743cc665SQuentin Monnet 318743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 319743cc665SQuentin Monnet if (memlock) 320743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 321743cc665SQuentin Monnet free(memlock); 322743cc665SQuentin Monnet 323743cc665SQuentin Monnet if (info->nr_map_ids) 324743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 325743cc665SQuentin Monnet 326569b0c77SPrashant Bhole if (info->btf_id) 327569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 328569b0c77SPrashant Bhole 3294990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3304990f1f4SPrashant Bhole struct pinned_obj *obj; 3314990f1f4SPrashant Bhole 3324990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 3334990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 3344990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3354990f1f4SPrashant Bhole if (obj->id == info->id) 3364990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 3374990f1f4SPrashant Bhole } 3384990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 3394990f1f4SPrashant Bhole } 3404990f1f4SPrashant Bhole 341743cc665SQuentin Monnet jsonw_end_object(json_wtr); 342743cc665SQuentin Monnet } 343743cc665SQuentin Monnet 344ec202509SPaul Chaignon static void print_prog_header_plain(struct bpf_prog_info *info) 345743cc665SQuentin Monnet { 346743cc665SQuentin Monnet printf("%u: ", info->id); 347743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 348743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 349743cc665SQuentin Monnet else 350743cc665SQuentin Monnet printf("type %u ", info->type); 351743cc665SQuentin Monnet 352743cc665SQuentin Monnet if (*info->name) 353743cc665SQuentin Monnet printf("name %s ", info->name); 354743cc665SQuentin Monnet 355743cc665SQuentin Monnet printf("tag "); 356743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 35752262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 3589b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 35988ad472bSAlexei Starovoitov if (info->run_time_ns) 36088ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 36188ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 362743cc665SQuentin Monnet printf("\n"); 363ec202509SPaul Chaignon } 364ec202509SPaul Chaignon 365ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 366ec202509SPaul Chaignon { 367ec202509SPaul Chaignon char *memlock; 368ec202509SPaul Chaignon 369ec202509SPaul Chaignon print_prog_header_plain(info); 370743cc665SQuentin Monnet 371743cc665SQuentin Monnet if (info->load_time) { 372743cc665SQuentin Monnet char buf[32]; 373743cc665SQuentin Monnet 374743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 375743cc665SQuentin Monnet 376743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 377743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 378743cc665SQuentin Monnet } 379743cc665SQuentin Monnet 380743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 381743cc665SQuentin Monnet 382743cc665SQuentin Monnet if (info->jited_prog_len) 383743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 38471bb428fSJakub Kicinski else 38571bb428fSJakub Kicinski printf(" not jited"); 38671bb428fSJakub Kicinski 38771bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 38871bb428fSJakub Kicinski if (memlock) 38971bb428fSJakub Kicinski printf(" memlock %sB", memlock); 39071bb428fSJakub Kicinski free(memlock); 39171bb428fSJakub Kicinski 392743cc665SQuentin Monnet if (info->nr_map_ids) 393743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 39471bb428fSJakub Kicinski 3954990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3964990f1f4SPrashant Bhole struct pinned_obj *obj; 3974990f1f4SPrashant Bhole 3984990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3994990f1f4SPrashant Bhole if (obj->id == info->id) 400a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 4014990f1f4SPrashant Bhole } 4024990f1f4SPrashant Bhole } 4034990f1f4SPrashant Bhole 404569b0c77SPrashant Bhole if (info->btf_id) 405031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 406569b0c77SPrashant Bhole 40771bb428fSJakub Kicinski printf("\n"); 408743cc665SQuentin Monnet } 409743cc665SQuentin Monnet 410743cc665SQuentin Monnet static int show_prog(int fd) 411743cc665SQuentin Monnet { 412743cc665SQuentin Monnet struct bpf_prog_info info = {}; 413743cc665SQuentin Monnet __u32 len = sizeof(info); 414743cc665SQuentin Monnet int err; 415743cc665SQuentin Monnet 416743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 417743cc665SQuentin Monnet if (err) { 4189a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 419743cc665SQuentin Monnet return -1; 420743cc665SQuentin Monnet } 421743cc665SQuentin Monnet 422743cc665SQuentin Monnet if (json_output) 423743cc665SQuentin Monnet print_prog_json(&info, fd); 424743cc665SQuentin Monnet else 425743cc665SQuentin Monnet print_prog_plain(&info, fd); 42671bb428fSJakub Kicinski 42771bb428fSJakub Kicinski return 0; 42871bb428fSJakub Kicinski } 42971bb428fSJakub Kicinski 430ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 431ec202509SPaul Chaignon { 432ec202509SPaul Chaignon int *fds = NULL; 433ec202509SPaul Chaignon int nb_fds, i; 434ec202509SPaul Chaignon int err = -1; 435ec202509SPaul Chaignon 436ec202509SPaul Chaignon fds = malloc(sizeof(int)); 437ec202509SPaul Chaignon if (!fds) { 438ec202509SPaul Chaignon p_err("mem alloc failed"); 439ec202509SPaul Chaignon return -1; 440ec202509SPaul Chaignon } 441ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 442ec202509SPaul Chaignon if (nb_fds < 1) 443ec202509SPaul Chaignon goto exit_free; 444ec202509SPaul Chaignon 445ec202509SPaul Chaignon if (json_output && nb_fds > 1) 446ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 447ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 448ec202509SPaul Chaignon err = show_prog(fds[i]); 449ec202509SPaul Chaignon if (err) { 450ec202509SPaul Chaignon for (; i < nb_fds; i++) 451ec202509SPaul Chaignon close(fds[i]); 452ec202509SPaul Chaignon break; 453ec202509SPaul Chaignon } 454ec202509SPaul Chaignon close(fds[i]); 455ec202509SPaul Chaignon } 456ec202509SPaul Chaignon if (json_output && nb_fds > 1) 457ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 458ec202509SPaul Chaignon 459ec202509SPaul Chaignon exit_free: 460ec202509SPaul Chaignon free(fds); 461ec202509SPaul Chaignon return err; 462ec202509SPaul Chaignon } 463ec202509SPaul Chaignon 46471bb428fSJakub Kicinski static int do_show(int argc, char **argv) 465743cc665SQuentin Monnet { 466743cc665SQuentin Monnet __u32 id = 0; 46771bb428fSJakub Kicinski int err; 46871bb428fSJakub Kicinski int fd; 46971bb428fSJakub Kicinski 470c541b734SPrashant Bhole if (show_pinned) 4714990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 4724990f1f4SPrashant Bhole 473ec202509SPaul Chaignon if (argc == 2) 474ec202509SPaul Chaignon return do_show_subset(argc, argv); 47571bb428fSJakub Kicinski 47671bb428fSJakub Kicinski if (argc) 47771bb428fSJakub Kicinski return BAD_ARG(); 47871bb428fSJakub Kicinski 479743cc665SQuentin Monnet if (json_output) 480743cc665SQuentin Monnet jsonw_start_array(json_wtr); 48171bb428fSJakub Kicinski while (true) { 48271bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 48371bb428fSJakub Kicinski if (err) { 4841739c26dSQuentin Monnet if (errno == ENOENT) { 4851739c26dSQuentin Monnet err = 0; 48671bb428fSJakub Kicinski break; 4871739c26dSQuentin Monnet } 4889a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 4899a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 490743cc665SQuentin Monnet err = -1; 491743cc665SQuentin Monnet break; 49271bb428fSJakub Kicinski } 49371bb428fSJakub Kicinski 49471bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 49571bb428fSJakub Kicinski if (fd < 0) { 4968207c6ddSJakub Kicinski if (errno == ENOENT) 4978207c6ddSJakub Kicinski continue; 4989a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 49971bb428fSJakub Kicinski id, strerror(errno)); 500743cc665SQuentin Monnet err = -1; 501743cc665SQuentin Monnet break; 50271bb428fSJakub Kicinski } 50371bb428fSJakub Kicinski 50471bb428fSJakub Kicinski err = show_prog(fd); 50571bb428fSJakub Kicinski close(fd); 50671bb428fSJakub Kicinski if (err) 507743cc665SQuentin Monnet break; 50871bb428fSJakub Kicinski } 50971bb428fSJakub Kicinski 510743cc665SQuentin Monnet if (json_output) 511743cc665SQuentin Monnet jsonw_end_array(json_wtr); 512743cc665SQuentin Monnet 513743cc665SQuentin Monnet return err; 51471bb428fSJakub Kicinski } 51571bb428fSJakub Kicinski 516ec202509SPaul Chaignon static int 517ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 518ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 51971bb428fSJakub Kicinski { 520b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 5213ddeac67SJakub Kicinski const char *disasm_opt = NULL; 5227105e828SDaniel Borkmann struct dump_data dd = {}; 523cae73f23SSong Liu void *func_info = NULL; 524254471e5SYonghong Song struct btf *btf = NULL; 525254471e5SYonghong Song char func_sig[1024]; 52671bb428fSJakub Kicinski unsigned char *buf; 527cae73f23SSong Liu __u32 member_len; 52871bb428fSJakub Kicinski ssize_t n; 52971bb428fSJakub Kicinski int fd; 53071bb428fSJakub Kicinski 531cae73f23SSong Liu if (mode == DUMP_JITED) { 5325b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 5339a5ab8bfSQuentin Monnet p_info("no instructions returned"); 534ec202509SPaul Chaignon return -1; 535f84192eeSSandipan Das } 536cae73f23SSong Liu buf = (unsigned char *)(info->jited_prog_insns); 537cae73f23SSong Liu member_len = info->jited_prog_len; 538cae73f23SSong Liu } else { /* DUMP_XLATED */ 539cae73f23SSong Liu if (info->xlated_prog_len == 0) { 5407105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 541ec202509SPaul Chaignon return -1; 5427105e828SDaniel Borkmann } 543cae73f23SSong Liu buf = (unsigned char *)info->xlated_prog_insns; 544cae73f23SSong Liu member_len = info->xlated_prog_len; 545cae73f23SSong Liu } 5467105e828SDaniel Borkmann 547cae73f23SSong Liu if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 548254471e5SYonghong Song p_err("failed to get btf"); 549ec202509SPaul Chaignon return -1; 550254471e5SYonghong Song } 551254471e5SYonghong Song 552cae73f23SSong Liu func_info = (void *)info->func_info; 553cae73f23SSong Liu 554cae73f23SSong Liu if (info->nr_line_info) { 555cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 556b053b439SMartin KaFai Lau if (!prog_linfo) 55710a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 558b053b439SMartin KaFai Lau } 559b053b439SMartin KaFai Lau 56071bb428fSJakub Kicinski if (filepath) { 56171bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 56271bb428fSJakub Kicinski if (fd < 0) { 5639a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 56471bb428fSJakub Kicinski strerror(errno)); 565ec202509SPaul Chaignon return -1; 56671bb428fSJakub Kicinski } 56771bb428fSJakub Kicinski 568cae73f23SSong Liu n = write(fd, buf, member_len); 56971bb428fSJakub Kicinski close(fd); 570cae73f23SSong Liu if (n != member_len) { 5719a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 57271bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 573ec202509SPaul Chaignon return -1; 57471bb428fSJakub Kicinski } 57552c84d36SQuentin Monnet 57652c84d36SQuentin Monnet if (json_output) 57752c84d36SQuentin Monnet jsonw_null(json_wtr); 578cae73f23SSong Liu } else if (mode == DUMP_JITED) { 579e6593596SJiong Wang const char *name = NULL; 580e6593596SJiong Wang 581cae73f23SSong Liu if (info->ifindex) { 582cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 583cae73f23SSong Liu info->netns_dev, 584cae73f23SSong Liu info->netns_ino, 5853ddeac67SJakub Kicinski &disasm_opt); 586e6593596SJiong Wang if (!name) 587ec202509SPaul Chaignon return -1; 588e6593596SJiong Wang } 589e6593596SJiong Wang 590cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 591f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 592254471e5SYonghong Song struct bpf_func_info *record; 593f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 594f7f62c71SSandipan Das unsigned char *img = buf; 595f7f62c71SSandipan Das __u64 *ksyms = NULL; 596f7f62c71SSandipan Das __u32 *lens; 597f7f62c71SSandipan Das __u32 i; 598cae73f23SSong Liu if (info->nr_jited_ksyms) { 599f7f62c71SSandipan Das kernel_syms_load(&dd); 600cae73f23SSong Liu ksyms = (__u64 *) info->jited_ksyms; 601f7f62c71SSandipan Das } 602f7f62c71SSandipan Das 603f7f62c71SSandipan Das if (json_output) 604f7f62c71SSandipan Das jsonw_start_array(json_wtr); 605f7f62c71SSandipan Das 606cae73f23SSong Liu lens = (__u32 *) info->jited_func_lens; 607cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 608f7f62c71SSandipan Das if (ksyms) { 609f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 610f7f62c71SSandipan Das if (sym) 611f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 612f7f62c71SSandipan Das else 613f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 614f7f62c71SSandipan Das } else { 615f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 616f7f62c71SSandipan Das } 617f7f62c71SSandipan Das 618254471e5SYonghong Song if (func_info) { 619cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 620254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 621254471e5SYonghong Song func_sig, 622254471e5SYonghong Song sizeof(func_sig)); 623254471e5SYonghong Song } 624254471e5SYonghong Song 625f7f62c71SSandipan Das if (json_output) { 626f7f62c71SSandipan Das jsonw_start_object(json_wtr); 627254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 628254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 629254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 630254471e5SYonghong Song } 631f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 632f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 633f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 634f7f62c71SSandipan Das } else { 635254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 636254471e5SYonghong Song printf("%s:\n", func_sig); 637f7f62c71SSandipan Das printf("%s:\n", sym_name); 638f7f62c71SSandipan Das } 639f7f62c71SSandipan Das 640b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 641b053b439SMartin KaFai Lau name, disasm_opt, btf, 642b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 643b053b439SMartin KaFai Lau linum); 644b053b439SMartin KaFai Lau 645f7f62c71SSandipan Das img += lens[i]; 646f7f62c71SSandipan Das 647f7f62c71SSandipan Das if (json_output) 648f7f62c71SSandipan Das jsonw_end_object(json_wtr); 649f7f62c71SSandipan Das else 650f7f62c71SSandipan Das printf("\n"); 651f7f62c71SSandipan Das } 652f7f62c71SSandipan Das 653f7f62c71SSandipan Das if (json_output) 654f7f62c71SSandipan Das jsonw_end_array(json_wtr); 655f7f62c71SSandipan Das } else { 656cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 657b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 658f7f62c71SSandipan Das } 659b6c1cedbSJiong Wang } else if (visual) { 660b6c1cedbSJiong Wang if (json_output) 661b6c1cedbSJiong Wang jsonw_null(json_wtr); 662b6c1cedbSJiong Wang else 663cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 6647105e828SDaniel Borkmann } else { 6657105e828SDaniel Borkmann kernel_syms_load(&dd); 666cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 667cae73f23SSong Liu dd.jited_ksyms = (__u64 *) info->jited_ksyms; 668254471e5SYonghong Song dd.btf = btf; 669254471e5SYonghong Song dd.func_info = func_info; 670cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 671b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 672f84192eeSSandipan Das 673f05e2c32SQuentin Monnet if (json_output) 674cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 675b053b439SMartin KaFai Lau linum); 676f05e2c32SQuentin Monnet else 677cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 678b053b439SMartin KaFai Lau linum); 6797105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6807105e828SDaniel Borkmann } 68171bb428fSJakub Kicinski 68271bb428fSJakub Kicinski return 0; 683ec202509SPaul Chaignon } 68471bb428fSJakub Kicinski 685ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 686ec202509SPaul Chaignon { 687ec202509SPaul Chaignon struct bpf_prog_info_linear *info_linear; 688ec202509SPaul Chaignon char *filepath = NULL; 689ec202509SPaul Chaignon bool opcodes = false; 690ec202509SPaul Chaignon bool visual = false; 691ec202509SPaul Chaignon enum dump_mode mode; 692ec202509SPaul Chaignon bool linum = false; 693ec202509SPaul Chaignon int *fds = NULL; 694ec202509SPaul Chaignon int nb_fds, i = 0; 695ec202509SPaul Chaignon int err = -1; 696ec202509SPaul Chaignon __u64 arrays; 697ec202509SPaul Chaignon 698ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 699ec202509SPaul Chaignon if (disasm_init()) 70071bb428fSJakub Kicinski return -1; 701ec202509SPaul Chaignon mode = DUMP_JITED; 702ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 703ec202509SPaul Chaignon mode = DUMP_XLATED; 704ec202509SPaul Chaignon } else { 705ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 706ec202509SPaul Chaignon return -1; 707ec202509SPaul Chaignon } 708ec202509SPaul Chaignon NEXT_ARG(); 709ec202509SPaul Chaignon 710ec202509SPaul Chaignon if (argc < 2) 711ec202509SPaul Chaignon usage(); 712ec202509SPaul Chaignon 713ec202509SPaul Chaignon fds = malloc(sizeof(int)); 714ec202509SPaul Chaignon if (!fds) { 715ec202509SPaul Chaignon p_err("mem alloc failed"); 716ec202509SPaul Chaignon return -1; 717ec202509SPaul Chaignon } 718ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 719ec202509SPaul Chaignon if (nb_fds < 1) 720ec202509SPaul Chaignon goto exit_free; 721ec202509SPaul Chaignon 722ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 723ec202509SPaul Chaignon NEXT_ARG(); 724ec202509SPaul Chaignon if (!argc) { 725ec202509SPaul Chaignon p_err("expected file path"); 726ec202509SPaul Chaignon goto exit_close; 727ec202509SPaul Chaignon } 728ec202509SPaul Chaignon if (nb_fds > 1) { 729ec202509SPaul Chaignon p_err("several programs matched"); 730ec202509SPaul Chaignon goto exit_close; 731ec202509SPaul Chaignon } 732ec202509SPaul Chaignon 733ec202509SPaul Chaignon filepath = *argv; 734ec202509SPaul Chaignon NEXT_ARG(); 735ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 736ec202509SPaul Chaignon opcodes = true; 737ec202509SPaul Chaignon NEXT_ARG(); 738ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 739ec202509SPaul Chaignon if (nb_fds > 1) { 740ec202509SPaul Chaignon p_err("several programs matched"); 741ec202509SPaul Chaignon goto exit_close; 742ec202509SPaul Chaignon } 743ec202509SPaul Chaignon 744ec202509SPaul Chaignon visual = true; 745ec202509SPaul Chaignon NEXT_ARG(); 746ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 747ec202509SPaul Chaignon linum = true; 748ec202509SPaul Chaignon NEXT_ARG(); 749ec202509SPaul Chaignon } 750ec202509SPaul Chaignon 751ec202509SPaul Chaignon if (argc) { 752ec202509SPaul Chaignon usage(); 753ec202509SPaul Chaignon goto exit_close; 754ec202509SPaul Chaignon } 755ec202509SPaul Chaignon 756ec202509SPaul Chaignon if (mode == DUMP_JITED) 757ec202509SPaul Chaignon arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 758ec202509SPaul Chaignon else 759ec202509SPaul Chaignon arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 760ec202509SPaul Chaignon 761ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 762ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 763ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 764ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 765ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 766ec202509SPaul Chaignon 767ec202509SPaul Chaignon if (json_output && nb_fds > 1) 768ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 769ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 770ec202509SPaul Chaignon info_linear = bpf_program__get_prog_info_linear(fds[i], arrays); 771ec202509SPaul Chaignon if (IS_ERR_OR_NULL(info_linear)) { 772ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 773ec202509SPaul Chaignon break; 774ec202509SPaul Chaignon } 775ec202509SPaul Chaignon 776ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 777ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 778ec202509SPaul Chaignon print_prog_header_json(&info_linear->info); 779ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 780ec202509SPaul Chaignon } else if (nb_fds > 1) { 781ec202509SPaul Chaignon print_prog_header_plain(&info_linear->info); 782ec202509SPaul Chaignon } 783ec202509SPaul Chaignon 784ec202509SPaul Chaignon err = prog_dump(&info_linear->info, mode, filepath, opcodes, 785ec202509SPaul Chaignon visual, linum); 786ec202509SPaul Chaignon 787ec202509SPaul Chaignon if (json_output && nb_fds > 1) 788ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 789ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 790ec202509SPaul Chaignon printf("\n"); 791ec202509SPaul Chaignon 792ec202509SPaul Chaignon free(info_linear); 793ec202509SPaul Chaignon if (err) 794ec202509SPaul Chaignon break; 795ec202509SPaul Chaignon close(fds[i]); 796ec202509SPaul Chaignon } 797ec202509SPaul Chaignon if (json_output && nb_fds > 1) 798ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 799ec202509SPaul Chaignon 800ec202509SPaul Chaignon exit_close: 801ec202509SPaul Chaignon for (; i < nb_fds; i++) 802ec202509SPaul Chaignon close(fds[i]); 803ec202509SPaul Chaignon exit_free: 804ec202509SPaul Chaignon free(fds); 805ec202509SPaul Chaignon return err; 80671bb428fSJakub Kicinski } 80771bb428fSJakub Kicinski 80871bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 80971bb428fSJakub Kicinski { 810004b45c0SQuentin Monnet int err; 811004b45c0SQuentin Monnet 812004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 813004b45c0SQuentin Monnet if (!err && json_output) 814004b45c0SQuentin Monnet jsonw_null(json_wtr); 815004b45c0SQuentin Monnet return err; 81671bb428fSJakub Kicinski } 81771bb428fSJakub Kicinski 8183ff5a4dcSJakub Kicinski struct map_replace { 8193ff5a4dcSJakub Kicinski int idx; 8203ff5a4dcSJakub Kicinski int fd; 8213ff5a4dcSJakub Kicinski char *name; 8223ff5a4dcSJakub Kicinski }; 8233ff5a4dcSJakub Kicinski 824c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 8253ff5a4dcSJakub Kicinski { 8263ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 8273ff5a4dcSJakub Kicinski 8283ff5a4dcSJakub Kicinski return a->idx - b->idx; 8293ff5a4dcSJakub Kicinski } 8303ff5a4dcSJakub Kicinski 831092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 832092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 833092f0892SStanislav Fomichev int *mapfd) 834092f0892SStanislav Fomichev { 835092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 836092f0892SStanislav Fomichev return -EINVAL; 837092f0892SStanislav Fomichev 838092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 839092f0892SStanislav Fomichev if (*progfd < 0) 840092f0892SStanislav Fomichev return *progfd; 841092f0892SStanislav Fomichev 842092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 843092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 844092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 845092f0892SStanislav Fomichev return -EINVAL; 846092f0892SStanislav Fomichev } 847092f0892SStanislav Fomichev 848092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 849092f0892SStanislav Fomichev *mapfd = -1; 850092f0892SStanislav Fomichev return 0; 851092f0892SStanislav Fomichev } 852092f0892SStanislav Fomichev 853092f0892SStanislav Fomichev NEXT_ARG(); 854092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 855092f0892SStanislav Fomichev return -EINVAL; 856092f0892SStanislav Fomichev 857092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 858092f0892SStanislav Fomichev if (*mapfd < 0) 859092f0892SStanislav Fomichev return *mapfd; 860092f0892SStanislav Fomichev 861092f0892SStanislav Fomichev return 0; 862092f0892SStanislav Fomichev } 863092f0892SStanislav Fomichev 864b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 865b7d3826cSJohn Fastabend { 866b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 867092f0892SStanislav Fomichev int err, progfd; 868092f0892SStanislav Fomichev int mapfd; 869b7d3826cSJohn Fastabend 870092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 871092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 872092f0892SStanislav Fomichev if (err) 873092f0892SStanislav Fomichev return err; 874b7d3826cSJohn Fastabend 875b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 876b7d3826cSJohn Fastabend if (err) { 877b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 878b7d3826cSJohn Fastabend return -EINVAL; 879b7d3826cSJohn Fastabend } 880b7d3826cSJohn Fastabend 881b7d3826cSJohn Fastabend if (json_output) 882b7d3826cSJohn Fastabend jsonw_null(json_wtr); 883b7d3826cSJohn Fastabend return 0; 884b7d3826cSJohn Fastabend } 885b7d3826cSJohn Fastabend 886b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 887b7d3826cSJohn Fastabend { 888b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 889092f0892SStanislav Fomichev int err, progfd; 890092f0892SStanislav Fomichev int mapfd; 891b7d3826cSJohn Fastabend 892092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 893092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 894092f0892SStanislav Fomichev if (err) 895092f0892SStanislav Fomichev return err; 896b7d3826cSJohn Fastabend 897b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 898b7d3826cSJohn Fastabend if (err) { 899b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 900b7d3826cSJohn Fastabend return -EINVAL; 901b7d3826cSJohn Fastabend } 902b7d3826cSJohn Fastabend 903b7d3826cSJohn Fastabend if (json_output) 904b7d3826cSJohn Fastabend jsonw_null(json_wtr); 905b7d3826cSJohn Fastabend return 0; 906b7d3826cSJohn Fastabend } 90777380998SStanislav Fomichev 908ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 909ba95c745SQuentin Monnet { 910ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 911ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 912ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 913ba95c745SQuentin Monnet return -1; 914ba95c745SQuentin Monnet } 915ba95c745SQuentin Monnet 916ba95c745SQuentin Monnet return 0; 917ba95c745SQuentin Monnet } 918ba95c745SQuentin Monnet 919ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 920ba95c745SQuentin Monnet { 921ba95c745SQuentin Monnet size_t block_size = 256; 922ba95c745SQuentin Monnet size_t buf_size = block_size; 923ba95c745SQuentin Monnet size_t nb_read = 0; 924ba95c745SQuentin Monnet void *tmp; 925ba95c745SQuentin Monnet FILE *f; 926ba95c745SQuentin Monnet 927ba95c745SQuentin Monnet if (!fname) { 928ba95c745SQuentin Monnet *data_ptr = NULL; 929ba95c745SQuentin Monnet *size = 0; 930ba95c745SQuentin Monnet return 0; 931ba95c745SQuentin Monnet } 932ba95c745SQuentin Monnet 933ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 934ba95c745SQuentin Monnet f = stdin; 935ba95c745SQuentin Monnet else 936ba95c745SQuentin Monnet f = fopen(fname, "r"); 937ba95c745SQuentin Monnet if (!f) { 938ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 939ba95c745SQuentin Monnet return -1; 940ba95c745SQuentin Monnet } 941ba95c745SQuentin Monnet 942ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 943ba95c745SQuentin Monnet if (!*data_ptr) { 944ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 945ba95c745SQuentin Monnet strerror(errno)); 946ba95c745SQuentin Monnet goto err_fclose; 947ba95c745SQuentin Monnet } 948ba95c745SQuentin Monnet 949ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 950ba95c745SQuentin Monnet if (feof(f)) 951ba95c745SQuentin Monnet break; 952ba95c745SQuentin Monnet if (ferror(f)) { 953ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 954ba95c745SQuentin Monnet fname, strerror(errno)); 955ba95c745SQuentin Monnet goto err_free; 956ba95c745SQuentin Monnet } 957ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 958ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 959ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 960ba95c745SQuentin Monnet UINT32_MAX); 961ba95c745SQuentin Monnet goto err_free; 962ba95c745SQuentin Monnet } 963ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 964ba95c745SQuentin Monnet buf_size *= 2; 965ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 966ba95c745SQuentin Monnet if (!tmp) { 967ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 968ba95c745SQuentin Monnet strerror(errno)); 969ba95c745SQuentin Monnet goto err_free; 970ba95c745SQuentin Monnet } 971ba95c745SQuentin Monnet *data_ptr = tmp; 972ba95c745SQuentin Monnet } 973ba95c745SQuentin Monnet } 974ba95c745SQuentin Monnet if (f != stdin) 975ba95c745SQuentin Monnet fclose(f); 976ba95c745SQuentin Monnet 977ba95c745SQuentin Monnet *size = nb_read; 978ba95c745SQuentin Monnet return 0; 979ba95c745SQuentin Monnet 980ba95c745SQuentin Monnet err_free: 981ba95c745SQuentin Monnet free(*data_ptr); 982ba95c745SQuentin Monnet *data_ptr = NULL; 983ba95c745SQuentin Monnet err_fclose: 984ba95c745SQuentin Monnet if (f != stdin) 985ba95c745SQuentin Monnet fclose(f); 986ba95c745SQuentin Monnet return -1; 987ba95c745SQuentin Monnet } 988ba95c745SQuentin Monnet 989ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 990ba95c745SQuentin Monnet { 991ba95c745SQuentin Monnet size_t i, j; 992ba95c745SQuentin Monnet char c; 993ba95c745SQuentin Monnet 994ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 995ba95c745SQuentin Monnet /* Row offset */ 996ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 997ba95c745SQuentin Monnet 998ba95c745SQuentin Monnet /* Hexadecimal values */ 999ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1000ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1001ba95c745SQuentin Monnet j % 2 ? " " : ""); 1002ba95c745SQuentin Monnet for (; j < i + 16; j++) 1003ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1004ba95c745SQuentin Monnet 1005ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1006ba95c745SQuentin Monnet fprintf(f, "| "); 1007ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1008ba95c745SQuentin Monnet c = *(char *)(data + j); 1009ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1010ba95c745SQuentin Monnet c = '.'; 1011ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1012ba95c745SQuentin Monnet } 1013ba95c745SQuentin Monnet 1014ba95c745SQuentin Monnet fprintf(f, "\n"); 1015ba95c745SQuentin Monnet } 1016ba95c745SQuentin Monnet } 1017ba95c745SQuentin Monnet 1018ba95c745SQuentin Monnet static int 1019ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1020ba95c745SQuentin Monnet const char *json_key) 1021ba95c745SQuentin Monnet { 1022ba95c745SQuentin Monnet size_t nb_written; 1023ba95c745SQuentin Monnet FILE *f; 1024ba95c745SQuentin Monnet 1025ba95c745SQuentin Monnet if (!fname) 1026ba95c745SQuentin Monnet return 0; 1027ba95c745SQuentin Monnet 1028ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1029ba95c745SQuentin Monnet f = stdout; 1030ba95c745SQuentin Monnet if (json_output) { 1031ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1032ba95c745SQuentin Monnet print_data_json(data, size); 1033ba95c745SQuentin Monnet } else { 1034ba95c745SQuentin Monnet hex_print(data, size, f); 1035ba95c745SQuentin Monnet } 1036ba95c745SQuentin Monnet return 0; 1037ba95c745SQuentin Monnet } 1038ba95c745SQuentin Monnet 1039ba95c745SQuentin Monnet f = fopen(fname, "w"); 1040ba95c745SQuentin Monnet if (!f) { 1041ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1042ba95c745SQuentin Monnet return -1; 1043ba95c745SQuentin Monnet } 1044ba95c745SQuentin Monnet 1045ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1046ba95c745SQuentin Monnet fclose(f); 1047ba95c745SQuentin Monnet if (nb_written != size) { 1048ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1049ba95c745SQuentin Monnet return -1; 1050ba95c745SQuentin Monnet } 1051ba95c745SQuentin Monnet 1052ba95c745SQuentin Monnet return 0; 1053ba95c745SQuentin Monnet } 1054ba95c745SQuentin Monnet 1055ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1056ba95c745SQuentin Monnet { 1057ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1058ba95c745SQuentin Monnet if (!*data_ptr) { 1059ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1060ba95c745SQuentin Monnet strerror(errno)); 1061ba95c745SQuentin Monnet return -1; 1062ba95c745SQuentin Monnet } 1063ba95c745SQuentin Monnet 1064ba95c745SQuentin Monnet return 0; 1065ba95c745SQuentin Monnet } 1066ba95c745SQuentin Monnet 1067ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1068ba95c745SQuentin Monnet { 1069ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1070ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1071ba95c745SQuentin Monnet struct bpf_prog_test_run_attr test_attr = {0}; 1072ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1073ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1074ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1075ba95c745SQuentin Monnet unsigned int repeat = 1; 1076ba95c745SQuentin Monnet int fd, err; 1077ba95c745SQuentin Monnet 1078ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1079ba95c745SQuentin Monnet return -1; 1080ba95c745SQuentin Monnet 1081ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1082ba95c745SQuentin Monnet if (fd < 0) 1083ba95c745SQuentin Monnet return -1; 1084ba95c745SQuentin Monnet 1085ba95c745SQuentin Monnet while (argc) { 1086ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1087ba95c745SQuentin Monnet "data_size_out", NULL)) 1088ba95c745SQuentin Monnet return -1; 1089ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1090ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1091ba95c745SQuentin Monnet return -1; 1092ba95c745SQuentin Monnet 1093ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1094ba95c745SQuentin Monnet NEXT_ARG(); 1095ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1096ba95c745SQuentin Monnet return -1; 1097ba95c745SQuentin Monnet 1098ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1099ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1100ba95c745SQuentin Monnet return -1; 1101ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1102ba95c745SQuentin Monnet NEXT_ARG(); 1103ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1104ba95c745SQuentin Monnet return -1; 1105ba95c745SQuentin Monnet 1106ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1107ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1108ba95c745SQuentin Monnet char *endptr; 1109ba95c745SQuentin Monnet 1110ba95c745SQuentin Monnet NEXT_ARG(); 1111ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1112ba95c745SQuentin Monnet return -1; 1113ba95c745SQuentin Monnet 1114ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1115ba95c745SQuentin Monnet if (*endptr) { 1116ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1117ba95c745SQuentin Monnet *argv); 1118ba95c745SQuentin Monnet return -1; 1119ba95c745SQuentin Monnet } 1120ba95c745SQuentin Monnet NEXT_ARG(); 1121ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1122ba95c745SQuentin Monnet NEXT_ARG(); 1123ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1124ba95c745SQuentin Monnet return -1; 1125ba95c745SQuentin Monnet 1126ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1127ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1128ba95c745SQuentin Monnet return -1; 1129ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1130ba95c745SQuentin Monnet NEXT_ARG(); 1131ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1132ba95c745SQuentin Monnet return -1; 1133ba95c745SQuentin Monnet 1134ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1135ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1136ba95c745SQuentin Monnet char *endptr; 1137ba95c745SQuentin Monnet 1138ba95c745SQuentin Monnet NEXT_ARG(); 1139ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1140ba95c745SQuentin Monnet return -1; 1141ba95c745SQuentin Monnet 1142ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1143ba95c745SQuentin Monnet if (*endptr) { 1144ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1145ba95c745SQuentin Monnet *argv); 1146ba95c745SQuentin Monnet return -1; 1147ba95c745SQuentin Monnet } 1148ba95c745SQuentin Monnet NEXT_ARG(); 1149ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1150ba95c745SQuentin Monnet char *endptr; 1151ba95c745SQuentin Monnet 1152ba95c745SQuentin Monnet NEXT_ARG(); 1153ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1154ba95c745SQuentin Monnet return -1; 1155ba95c745SQuentin Monnet 1156ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1157ba95c745SQuentin Monnet if (*endptr) { 1158ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1159ba95c745SQuentin Monnet *argv); 1160ba95c745SQuentin Monnet return -1; 1161ba95c745SQuentin Monnet } 1162ba95c745SQuentin Monnet NEXT_ARG(); 1163ba95c745SQuentin Monnet } else { 1164ba95c745SQuentin 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'?", 1165ba95c745SQuentin Monnet *argv); 1166ba95c745SQuentin Monnet return -1; 1167ba95c745SQuentin Monnet } 1168ba95c745SQuentin Monnet } 1169ba95c745SQuentin Monnet 1170ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1171ba95c745SQuentin Monnet if (err) 1172ba95c745SQuentin Monnet return -1; 1173ba95c745SQuentin Monnet 1174ba95c745SQuentin Monnet if (data_in) { 1175ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1176ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1177ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1178ba95c745SQuentin Monnet if (err) 1179ba95c745SQuentin Monnet goto free_data_in; 1180ba95c745SQuentin Monnet } 1181ba95c745SQuentin Monnet 1182ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1183ba95c745SQuentin Monnet if (err) 1184ba95c745SQuentin Monnet goto free_data_out; 1185ba95c745SQuentin Monnet 1186ba95c745SQuentin Monnet if (ctx_in) { 1187ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1188ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1189ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1190ba95c745SQuentin Monnet if (err) 1191ba95c745SQuentin Monnet goto free_ctx_in; 1192ba95c745SQuentin Monnet } 1193ba95c745SQuentin Monnet 1194ba95c745SQuentin Monnet test_attr.prog_fd = fd; 1195ba95c745SQuentin Monnet test_attr.repeat = repeat; 1196ba95c745SQuentin Monnet test_attr.data_in = data_in; 1197ba95c745SQuentin Monnet test_attr.data_out = data_out; 1198ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1199ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1200ba95c745SQuentin Monnet 1201ba95c745SQuentin Monnet err = bpf_prog_test_run_xattr(&test_attr); 1202ba95c745SQuentin Monnet if (err) { 1203ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1204ba95c745SQuentin Monnet goto free_ctx_out; 1205ba95c745SQuentin Monnet } 1206ba95c745SQuentin Monnet 1207ba95c745SQuentin Monnet err = 0; 1208ba95c745SQuentin Monnet 1209ba95c745SQuentin Monnet if (json_output) 1210ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1211ba95c745SQuentin Monnet 1212ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1213ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1214ba95c745SQuentin Monnet */ 1215ba95c745SQuentin Monnet if (test_attr.data_size_out) 1216ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1217ba95c745SQuentin Monnet test_attr.data_size_out, 1218ba95c745SQuentin Monnet data_fname_out, "data_out"); 1219ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1220ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1221ba95c745SQuentin Monnet test_attr.ctx_size_out, 1222ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1223ba95c745SQuentin Monnet 1224ba95c745SQuentin Monnet if (json_output) { 1225ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1226ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1227ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1228ba95c745SQuentin Monnet } else { 1229ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1230ba95c745SQuentin Monnet test_attr.retval, 1231ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1232ba95c745SQuentin Monnet } 1233ba95c745SQuentin Monnet 1234ba95c745SQuentin Monnet free_ctx_out: 1235ba95c745SQuentin Monnet free(ctx_out); 1236ba95c745SQuentin Monnet free_ctx_in: 1237ba95c745SQuentin Monnet free(ctx_in); 1238ba95c745SQuentin Monnet free_data_out: 1239ba95c745SQuentin Monnet free(data_out); 1240ba95c745SQuentin Monnet free_data_in: 1241ba95c745SQuentin Monnet free(data_in); 1242ba95c745SQuentin Monnet 1243ba95c745SQuentin Monnet return err; 1244ba95c745SQuentin Monnet } 1245ba95c745SQuentin Monnet 124677380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 124749a086c2SRoman Gushchin { 124832e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1249e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1250e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1251e00aca65SAndrii Nakryiko ); 1252e00aca65SAndrii Nakryiko struct bpf_object_load_attr load_attr = { 0 }; 125355d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 12543ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 125577380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 12563ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 12573767a94bSStanislav Fomichev const char *pinmaps = NULL; 125849a086c2SRoman Gushchin struct bpf_object *obj; 1259c8406848SJakub Kicinski struct bpf_map *map; 1260c8406848SJakub Kicinski const char *pinfile; 12613ff5a4dcSJakub Kicinski unsigned int i, j; 1262c8406848SJakub Kicinski __u32 ifindex = 0; 126332e3e58eSAndrii Nakryiko const char *file; 12643ff5a4dcSJakub Kicinski int idx, err; 126549a086c2SRoman Gushchin 126632e3e58eSAndrii Nakryiko 12678d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 12688d1fc3deSJakub Kicinski return -1; 126932e3e58eSAndrii Nakryiko file = GET_ARG(); 12708d1fc3deSJakub Kicinski pinfile = GET_ARG(); 127149a086c2SRoman Gushchin 1272ba6dd679SJakub Kicinski while (argc) { 127349f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 127449f2cba3SJakub Kicinski char *type; 127549f2cba3SJakub Kicinski 127649f2cba3SJakub Kicinski NEXT_ARG(); 127749f2cba3SJakub Kicinski 127832e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 127949f2cba3SJakub Kicinski p_err("program type already specified"); 12803ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 128149f2cba3SJakub Kicinski } 128249f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 12833ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 128449f2cba3SJakub Kicinski 128549f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 128649f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 128749f2cba3SJakub Kicinski if (!type) { 128849f2cba3SJakub Kicinski p_err("mem alloc failed"); 12893ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 129049f2cba3SJakub Kicinski } 129149f2cba3SJakub Kicinski *type = 0; 129249f2cba3SJakub Kicinski strcat(type, *argv); 129349f2cba3SJakub Kicinski strcat(type, "/"); 129449f2cba3SJakub Kicinski 129532e3e58eSAndrii Nakryiko err = libbpf_prog_type_by_name(type, &common_prog_type, 1296c8406848SJakub Kicinski &expected_attach_type); 129749f2cba3SJakub Kicinski free(type); 1298c76e4c22STaeung Song if (err < 0) 12993ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1300c76e4c22STaeung Song 130149f2cba3SJakub Kicinski NEXT_ARG(); 13023ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1303dde7011aSJakub Kicinski void *new_map_replace; 13043ff5a4dcSJakub Kicinski char *endptr, *name; 13053ff5a4dcSJakub Kicinski int fd; 13063ff5a4dcSJakub Kicinski 13073ff5a4dcSJakub Kicinski NEXT_ARG(); 13083ff5a4dcSJakub Kicinski 13093ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 13103ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13113ff5a4dcSJakub Kicinski 13123ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 13133ff5a4dcSJakub Kicinski NEXT_ARG(); 13143ff5a4dcSJakub Kicinski 13153ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 13163ff5a4dcSJakub Kicinski if (*endptr) { 13173ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 13183ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13193ff5a4dcSJakub Kicinski } 13203ff5a4dcSJakub Kicinski name = NULL; 13213ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 13223ff5a4dcSJakub Kicinski NEXT_ARG(); 13233ff5a4dcSJakub Kicinski 13243ff5a4dcSJakub Kicinski name = *argv; 13253ff5a4dcSJakub Kicinski idx = -1; 13263ff5a4dcSJakub Kicinski } else { 13273ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 13283ff5a4dcSJakub Kicinski *argv); 13293ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13303ff5a4dcSJakub Kicinski } 13313ff5a4dcSJakub Kicinski NEXT_ARG(); 13323ff5a4dcSJakub Kicinski 13333ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 13343ff5a4dcSJakub Kicinski if (fd < 0) 13353ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13363ff5a4dcSJakub Kicinski 1337dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 1338dde7011aSJakub Kicinski old_map_fds + 1, 13393ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1340dde7011aSJakub Kicinski if (!new_map_replace) { 13413ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 13423ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13433ff5a4dcSJakub Kicinski } 1344dde7011aSJakub Kicinski map_replace = new_map_replace; 1345dde7011aSJakub Kicinski 13463ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 13473ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 13483ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 13493ff5a4dcSJakub Kicinski old_map_fds++; 135049f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1351ba6dd679SJakub Kicinski NEXT_ARG(); 1352ba6dd679SJakub Kicinski 1353c8406848SJakub Kicinski if (ifindex) { 1354ba6dd679SJakub Kicinski p_err("offload device already specified"); 13553ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1356ba6dd679SJakub Kicinski } 1357ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 13583ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1359ba6dd679SJakub Kicinski 1360c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1361c8406848SJakub Kicinski if (!ifindex) { 1362ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1363ba6dd679SJakub Kicinski *argv, strerror(errno)); 13643ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1365ba6dd679SJakub Kicinski } 1366ba6dd679SJakub Kicinski NEXT_ARG(); 13673767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 13683767a94bSStanislav Fomichev NEXT_ARG(); 13693767a94bSStanislav Fomichev 13703767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 13713767a94bSStanislav Fomichev goto err_free_reuse_maps; 13723767a94bSStanislav Fomichev 13733767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1374ba6dd679SJakub Kicinski } else { 13753ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1376ba6dd679SJakub Kicinski *argv); 13773ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1378ba6dd679SJakub Kicinski } 1379ba6dd679SJakub Kicinski } 1380ba6dd679SJakub Kicinski 1381ac4e0e05SYonghong Song set_max_rlimit(); 1382ac4e0e05SYonghong Song 138332e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1384c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 1385c8406848SJakub Kicinski p_err("failed to open object file"); 13863ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 138749a086c2SRoman Gushchin } 138849a086c2SRoman Gushchin 138977380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 139032e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1391c8406848SJakub Kicinski 139232e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 139377380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1394c8406848SJakub Kicinski 139577380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 1396c8406848SJakub Kicinski &expected_attach_type); 1397c76e4c22STaeung Song if (err < 0) 1398c8406848SJakub Kicinski goto err_close_obj; 1399c8406848SJakub Kicinski } 140077380998SStanislav Fomichev 140177380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 140277380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 140377380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 140477380998SStanislav Fomichev } 1405c8406848SJakub Kicinski 14063ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 14073ff5a4dcSJakub Kicinski map_replace_compar); 14083ff5a4dcSJakub Kicinski 14093ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 14103ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 14113ff5a4dcSJakub Kicinski */ 14123ff5a4dcSJakub Kicinski j = 0; 14133ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 14143ff5a4dcSJakub Kicinski i = 0; 1415f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 14163ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 14173ff5a4dcSJakub Kicinski map_replace[j].idx = i; 14183ff5a4dcSJakub Kicinski break; 14193ff5a4dcSJakub Kicinski } 14203ff5a4dcSJakub Kicinski i++; 14213ff5a4dcSJakub Kicinski } 14223ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 14233ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 14243ff5a4dcSJakub Kicinski goto err_close_obj; 14253ff5a4dcSJakub Kicinski } 14263ff5a4dcSJakub Kicinski j++; 14273ff5a4dcSJakub Kicinski } 14283ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 14293ff5a4dcSJakub Kicinski if (j) 14303ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 14313ff5a4dcSJakub Kicinski map_replace_compar); 14323ff5a4dcSJakub Kicinski 14333ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 14343ff5a4dcSJakub Kicinski j = 0; 14353ff5a4dcSJakub Kicinski idx = 0; 1436f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 1437c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1438c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1439c8406848SJakub Kicinski 14403ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 14413ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 14423ff5a4dcSJakub Kicinski if (err) { 14433ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 14443ff5a4dcSJakub Kicinski goto err_close_obj; 14453ff5a4dcSJakub Kicinski } 14463ff5a4dcSJakub Kicinski 14473ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 14483ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 14493ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 14503ff5a4dcSJakub Kicinski idx); 14513ff5a4dcSJakub Kicinski goto err_close_obj; 14523ff5a4dcSJakub Kicinski } 14533ff5a4dcSJakub Kicinski } 14543ff5a4dcSJakub Kicinski 14553ff5a4dcSJakub Kicinski idx++; 14563ff5a4dcSJakub Kicinski } 14573ff5a4dcSJakub Kicinski if (j < old_map_fds) { 14583ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 14593ff5a4dcSJakub Kicinski goto err_close_obj; 14603ff5a4dcSJakub Kicinski } 14613ff5a4dcSJakub Kicinski 146255d77807SQuentin Monnet load_attr.obj = obj; 146355d77807SQuentin Monnet if (verifier_logs) 146455d77807SQuentin Monnet /* log_level1 + log_level2 + stats, but not stable UAPI */ 146555d77807SQuentin Monnet load_attr.log_level = 1 + 2 + 4; 146655d77807SQuentin Monnet 146755d77807SQuentin Monnet err = bpf_object__load_xattr(&load_attr); 1468c8406848SJakub Kicinski if (err) { 1469c8406848SJakub Kicinski p_err("failed to load object file"); 1470c8406848SJakub Kicinski goto err_close_obj; 1471c8406848SJakub Kicinski } 1472c8406848SJakub Kicinski 147377380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 147477380998SStanislav Fomichev if (err) 1475bfee71fbSJakub Kicinski goto err_close_obj; 147649a086c2SRoman Gushchin 147777380998SStanislav Fomichev if (first_prog_only) { 147877380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 147977380998SStanislav Fomichev if (!prog) { 148077380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 148177380998SStanislav Fomichev goto err_close_obj; 148277380998SStanislav Fomichev } 148377380998SStanislav Fomichev 148477380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 148577380998SStanislav Fomichev if (err) { 148677380998SStanislav Fomichev p_err("failed to pin program %s", 148777380998SStanislav Fomichev bpf_program__title(prog, false)); 148877380998SStanislav Fomichev goto err_close_obj; 148977380998SStanislav Fomichev } 149077380998SStanislav Fomichev } else { 149177380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 149277380998SStanislav Fomichev if (err) { 149377380998SStanislav Fomichev p_err("failed to pin all programs"); 149477380998SStanislav Fomichev goto err_close_obj; 149577380998SStanislav Fomichev } 149677380998SStanislav Fomichev } 149777380998SStanislav Fomichev 14983767a94bSStanislav Fomichev if (pinmaps) { 14993767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 15003767a94bSStanislav Fomichev if (err) { 15013767a94bSStanislav Fomichev p_err("failed to pin all maps"); 15023767a94bSStanislav Fomichev goto err_unpin; 15033767a94bSStanislav Fomichev } 15043767a94bSStanislav Fomichev } 15053767a94bSStanislav Fomichev 150649a086c2SRoman Gushchin if (json_output) 150749a086c2SRoman Gushchin jsonw_null(json_wtr); 150849a086c2SRoman Gushchin 1509bfee71fbSJakub Kicinski bpf_object__close(obj); 15103ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 15113ff5a4dcSJakub Kicinski close(map_replace[i].fd); 15123ff5a4dcSJakub Kicinski free(map_replace); 1513bfee71fbSJakub Kicinski 151449a086c2SRoman Gushchin return 0; 1515bfee71fbSJakub Kicinski 15163767a94bSStanislav Fomichev err_unpin: 15173767a94bSStanislav Fomichev if (first_prog_only) 15183767a94bSStanislav Fomichev unlink(pinfile); 15193767a94bSStanislav Fomichev else 15203767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1521bfee71fbSJakub Kicinski err_close_obj: 1522bfee71fbSJakub Kicinski bpf_object__close(obj); 15233ff5a4dcSJakub Kicinski err_free_reuse_maps: 15243ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 15253ff5a4dcSJakub Kicinski close(map_replace[i].fd); 15263ff5a4dcSJakub Kicinski free(map_replace); 1527bfee71fbSJakub Kicinski return -1; 152849a086c2SRoman Gushchin } 152949a086c2SRoman Gushchin 153077380998SStanislav Fomichev static int do_load(int argc, char **argv) 153177380998SStanislav Fomichev { 153277380998SStanislav Fomichev return load_with_options(argc, argv, true); 153377380998SStanislav Fomichev } 153477380998SStanislav Fomichev 153577380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 153677380998SStanislav Fomichev { 153777380998SStanislav Fomichev return load_with_options(argc, argv, false); 153877380998SStanislav Fomichev } 153977380998SStanislav Fomichev 154071bb428fSJakub Kicinski static int do_help(int argc, char **argv) 154171bb428fSJakub Kicinski { 1542004b45c0SQuentin Monnet if (json_output) { 1543004b45c0SQuentin Monnet jsonw_null(json_wtr); 1544004b45c0SQuentin Monnet return 0; 1545004b45c0SQuentin Monnet } 1546004b45c0SQuentin Monnet 154771bb428fSJakub Kicinski fprintf(stderr, 15486ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1549b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1550b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 155171bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 155277380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 155377380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 15543767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 15553767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1556092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1557092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1558ba95c745SQuentin Monnet " %s %s run PROG \\\n" 1559ba95c745SQuentin Monnet " data_in FILE \\\n" 1560ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 1561ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1562ba95c745SQuentin Monnet " [repeat N]\n" 156330da46b5SQuentin Monnet " %s %s tracelog\n" 156471bb428fSJakub Kicinski " %s %s help\n" 156571bb428fSJakub Kicinski "\n" 15663ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 156771bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 156849f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 156949f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 157049f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 157149f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1572f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 157349f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 157449f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1575000aa125SDaniel Borkmann " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1576f6d08d9dSStanislav Fomichev " cgroup/recvmsg6 | cgroup/getsockopt |\n" 1577f6d08d9dSStanislav Fomichev " cgroup/setsockopt }\n" 1578a5d9265eSAlban Crequy " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1579092f0892SStanislav Fomichev " flow_dissector }\n" 15800641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 158171bb428fSJakub Kicinski "", 158271bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1583b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1584ba95c745SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1585ba95c745SQuentin Monnet bin_name, argv[-2]); 158671bb428fSJakub Kicinski 158771bb428fSJakub Kicinski return 0; 158871bb428fSJakub Kicinski } 158971bb428fSJakub Kicinski 159071bb428fSJakub Kicinski static const struct cmd cmds[] = { 159171bb428fSJakub Kicinski { "show", do_show }, 15926ebe6dbdSJakub Kicinski { "list", do_show }, 15939f606179SQuentin Monnet { "help", do_help }, 159471bb428fSJakub Kicinski { "dump", do_dump }, 159571bb428fSJakub Kicinski { "pin", do_pin }, 159649a086c2SRoman Gushchin { "load", do_load }, 159777380998SStanislav Fomichev { "loadall", do_loadall }, 1598b7d3826cSJohn Fastabend { "attach", do_attach }, 1599b7d3826cSJohn Fastabend { "detach", do_detach }, 160030da46b5SQuentin Monnet { "tracelog", do_tracelog }, 1601ba95c745SQuentin Monnet { "run", do_run }, 160271bb428fSJakub Kicinski { 0 } 160371bb428fSJakub Kicinski }; 160471bb428fSJakub Kicinski 160571bb428fSJakub Kicinski int do_prog(int argc, char **argv) 160671bb428fSJakub Kicinski { 160771bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 160871bb428fSJakub Kicinski } 1609