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 2071bb428fSJakub Kicinski #include <bpf.h> 21254471e5SYonghong Song #include <btf.h> 2249a086c2SRoman Gushchin #include <libbpf.h> 2371bb428fSJakub Kicinski 24b6c1cedbSJiong Wang #include "cfg.h" 2571bb428fSJakub Kicinski #include "main.h" 2673bb5b4fSJiong Wang #include "xlated_dumper.h" 2771bb428fSJakub Kicinski 28*ec202509SPaul Chaignon enum dump_mode { 29*ec202509SPaul Chaignon DUMP_JITED, 30*ec202509SPaul Chaignon DUMP_XLATED, 31*ec202509SPaul Chaignon }; 32*ec202509SPaul 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 85*ec202509SPaul Chaignon static int prog_fd_by_tag(unsigned char *tag, int **fds) 8671bb428fSJakub Kicinski { 8771bb428fSJakub Kicinski unsigned int id = 0; 88*ec202509SPaul Chaignon int fd, nb_fds = 0; 89*ec202509SPaul 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) { 98*ec202509SPaul Chaignon if (errno != ENOENT) { 999a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 100*ec202509SPaul Chaignon goto err_close_fds; 101*ec202509SPaul Chaignon } 102*ec202509SPaul 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)); 109*ec202509SPaul 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)); 116*ec202509SPaul Chaignon goto err_close_fd; 117*ec202509SPaul Chaignon } 118*ec202509SPaul Chaignon 119*ec202509SPaul Chaignon if (memcmp(tag, info.tag, BPF_TAG_SIZE)) { 12071bb428fSJakub Kicinski close(fd); 121*ec202509SPaul Chaignon continue; 122*ec202509SPaul Chaignon } 123*ec202509SPaul Chaignon 124*ec202509SPaul Chaignon if (nb_fds > 0) { 125*ec202509SPaul Chaignon tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); 126*ec202509SPaul Chaignon if (!tmp) { 127*ec202509SPaul Chaignon p_err("failed to realloc"); 128*ec202509SPaul Chaignon goto err_close_fd; 129*ec202509SPaul Chaignon } 130*ec202509SPaul Chaignon *fds = tmp; 131*ec202509SPaul Chaignon } 132*ec202509SPaul Chaignon (*fds)[nb_fds++] = fd; 133*ec202509SPaul Chaignon } 134*ec202509SPaul Chaignon 135*ec202509SPaul Chaignon err_close_fd: 136*ec202509SPaul Chaignon close(fd); 137*ec202509SPaul Chaignon err_close_fds: 138*ec202509SPaul Chaignon while (--nb_fds >= 0) 139*ec202509SPaul Chaignon close((*fds)[nb_fds]); 14071bb428fSJakub Kicinski return -1; 14171bb428fSJakub Kicinski } 14271bb428fSJakub Kicinski 143*ec202509SPaul Chaignon static int prog_parse_fds(int *argc, char ***argv, int **fds) 14471bb428fSJakub Kicinski { 14571bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 14671bb428fSJakub Kicinski unsigned int id; 14771bb428fSJakub Kicinski char *endptr; 14871bb428fSJakub Kicinski 14971bb428fSJakub Kicinski NEXT_ARGP(); 15071bb428fSJakub Kicinski 15171bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 15271bb428fSJakub Kicinski if (*endptr) { 1539a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 15471bb428fSJakub Kicinski return -1; 15571bb428fSJakub Kicinski } 15671bb428fSJakub Kicinski NEXT_ARGP(); 15771bb428fSJakub Kicinski 158*ec202509SPaul Chaignon (*fds)[0] = bpf_prog_get_fd_by_id(id); 159*ec202509SPaul Chaignon if ((*fds)[0] < 0) { 1609a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 161*ec202509SPaul Chaignon return -1; 162*ec202509SPaul Chaignon } 163*ec202509SPaul Chaignon return 1; 16471bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 16571bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 16671bb428fSJakub Kicinski 16771bb428fSJakub Kicinski NEXT_ARGP(); 16871bb428fSJakub Kicinski 16971bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 17071bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 17171bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1729a5ab8bfSQuentin Monnet p_err("can't parse tag"); 17371bb428fSJakub Kicinski return -1; 17471bb428fSJakub Kicinski } 17571bb428fSJakub Kicinski NEXT_ARGP(); 17671bb428fSJakub Kicinski 177*ec202509SPaul Chaignon return prog_fd_by_tag(tag, fds); 17871bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 17971bb428fSJakub Kicinski char *path; 18071bb428fSJakub Kicinski 18171bb428fSJakub Kicinski NEXT_ARGP(); 18271bb428fSJakub Kicinski 18371bb428fSJakub Kicinski path = **argv; 18471bb428fSJakub Kicinski NEXT_ARGP(); 18571bb428fSJakub Kicinski 186*ec202509SPaul Chaignon (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG); 187*ec202509SPaul Chaignon if ((*fds)[0] < 0) 188*ec202509SPaul Chaignon return -1; 189*ec202509SPaul Chaignon return 1; 19071bb428fSJakub Kicinski } 19171bb428fSJakub Kicinski 1929a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 19371bb428fSJakub Kicinski return -1; 19471bb428fSJakub Kicinski } 19571bb428fSJakub Kicinski 196*ec202509SPaul Chaignon int prog_parse_fd(int *argc, char ***argv) 197*ec202509SPaul Chaignon { 198*ec202509SPaul Chaignon int *fds = NULL; 199*ec202509SPaul Chaignon int nb_fds, fd; 200*ec202509SPaul Chaignon 201*ec202509SPaul Chaignon fds = malloc(sizeof(int)); 202*ec202509SPaul Chaignon if (!fds) { 203*ec202509SPaul Chaignon p_err("mem alloc failed"); 204*ec202509SPaul Chaignon return -1; 205*ec202509SPaul Chaignon } 206*ec202509SPaul Chaignon nb_fds = prog_parse_fds(argc, argv, &fds); 207*ec202509SPaul Chaignon if (nb_fds != 1) { 208*ec202509SPaul Chaignon if (nb_fds > 1) { 209*ec202509SPaul Chaignon p_err("several programs match this handle"); 210*ec202509SPaul Chaignon while (nb_fds--) 211*ec202509SPaul Chaignon close(fds[nb_fds]); 212*ec202509SPaul Chaignon } 213*ec202509SPaul Chaignon fd = -1; 214*ec202509SPaul Chaignon goto exit_free; 215*ec202509SPaul Chaignon } 216*ec202509SPaul Chaignon 217*ec202509SPaul Chaignon fd = fds[0]; 218*ec202509SPaul Chaignon exit_free: 219*ec202509SPaul Chaignon free(fds); 220*ec202509SPaul Chaignon return fd; 221*ec202509SPaul Chaignon } 222*ec202509SPaul Chaignon 22371bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 22471bb428fSJakub Kicinski { 22571bb428fSJakub Kicinski struct bpf_prog_info info = {}; 22671bb428fSJakub Kicinski __u32 len = sizeof(info); 22771bb428fSJakub Kicinski __u32 map_ids[num_maps]; 22871bb428fSJakub Kicinski unsigned int i; 22971bb428fSJakub Kicinski int err; 23071bb428fSJakub Kicinski 23171bb428fSJakub Kicinski info.nr_map_ids = num_maps; 23271bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 23371bb428fSJakub Kicinski 23471bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 23571bb428fSJakub Kicinski if (err || !info.nr_map_ids) 23671bb428fSJakub Kicinski return; 23771bb428fSJakub Kicinski 238743cc665SQuentin Monnet if (json_output) { 239743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 240743cc665SQuentin Monnet jsonw_start_array(json_wtr); 241743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 242743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 243743cc665SQuentin Monnet jsonw_end_array(json_wtr); 244743cc665SQuentin Monnet } else { 24571bb428fSJakub Kicinski printf(" map_ids "); 24671bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 24771bb428fSJakub Kicinski printf("%u%s", map_ids[i], 24871bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 24971bb428fSJakub Kicinski } 25071bb428fSJakub Kicinski } 25171bb428fSJakub Kicinski 252*ec202509SPaul Chaignon static void print_prog_header_json(struct bpf_prog_info *info) 253743cc665SQuentin Monnet { 254743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 255743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 256743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 257743cc665SQuentin Monnet prog_type_name[info->type]); 25871bb428fSJakub Kicinski else 259743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 26071bb428fSJakub Kicinski 261743cc665SQuentin Monnet if (*info->name) 262743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 26371bb428fSJakub Kicinski 264743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 265743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 266743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 267743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 26871bb428fSJakub Kicinski 2699b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 27088ad472bSAlexei Starovoitov if (info->run_time_ns) { 27188ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 27288ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 27388ad472bSAlexei Starovoitov } 274*ec202509SPaul Chaignon } 2759b984a20SJiri Olsa 276*ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 277*ec202509SPaul Chaignon { 278*ec202509SPaul Chaignon char *memlock; 279*ec202509SPaul Chaignon 280*ec202509SPaul Chaignon jsonw_start_object(json_wtr); 281*ec202509SPaul Chaignon print_prog_header_json(info); 28252262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 28352262210SJakub Kicinski 284743cc665SQuentin Monnet if (info->load_time) { 28571bb428fSJakub Kicinski char buf[32]; 28671bb428fSJakub Kicinski 287743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 28871bb428fSJakub Kicinski 28971bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 290a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 291a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 292743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 29371bb428fSJakub Kicinski } 29471bb428fSJakub Kicinski 295743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 29671bb428fSJakub Kicinski 297743cc665SQuentin Monnet if (info->jited_prog_len) { 298743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 299743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 300743cc665SQuentin Monnet } else { 301743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 302743cc665SQuentin Monnet } 303743cc665SQuentin Monnet 304743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 305743cc665SQuentin Monnet if (memlock) 306743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 307743cc665SQuentin Monnet free(memlock); 308743cc665SQuentin Monnet 309743cc665SQuentin Monnet if (info->nr_map_ids) 310743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 311743cc665SQuentin Monnet 312569b0c77SPrashant Bhole if (info->btf_id) 313569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 314569b0c77SPrashant Bhole 3154990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3164990f1f4SPrashant Bhole struct pinned_obj *obj; 3174990f1f4SPrashant Bhole 3184990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 3194990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 3204990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3214990f1f4SPrashant Bhole if (obj->id == info->id) 3224990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 3234990f1f4SPrashant Bhole } 3244990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 3254990f1f4SPrashant Bhole } 3264990f1f4SPrashant Bhole 327743cc665SQuentin Monnet jsonw_end_object(json_wtr); 328743cc665SQuentin Monnet } 329743cc665SQuentin Monnet 330*ec202509SPaul Chaignon static void print_prog_header_plain(struct bpf_prog_info *info) 331743cc665SQuentin Monnet { 332743cc665SQuentin Monnet printf("%u: ", info->id); 333743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 334743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 335743cc665SQuentin Monnet else 336743cc665SQuentin Monnet printf("type %u ", info->type); 337743cc665SQuentin Monnet 338743cc665SQuentin Monnet if (*info->name) 339743cc665SQuentin Monnet printf("name %s ", info->name); 340743cc665SQuentin Monnet 341743cc665SQuentin Monnet printf("tag "); 342743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 34352262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 3449b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 34588ad472bSAlexei Starovoitov if (info->run_time_ns) 34688ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 34788ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 348743cc665SQuentin Monnet printf("\n"); 349*ec202509SPaul Chaignon } 350*ec202509SPaul Chaignon 351*ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 352*ec202509SPaul Chaignon { 353*ec202509SPaul Chaignon char *memlock; 354*ec202509SPaul Chaignon 355*ec202509SPaul Chaignon print_prog_header_plain(info); 356743cc665SQuentin Monnet 357743cc665SQuentin Monnet if (info->load_time) { 358743cc665SQuentin Monnet char buf[32]; 359743cc665SQuentin Monnet 360743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 361743cc665SQuentin Monnet 362743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 363743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 364743cc665SQuentin Monnet } 365743cc665SQuentin Monnet 366743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 367743cc665SQuentin Monnet 368743cc665SQuentin Monnet if (info->jited_prog_len) 369743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 37071bb428fSJakub Kicinski else 37171bb428fSJakub Kicinski printf(" not jited"); 37271bb428fSJakub Kicinski 37371bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 37471bb428fSJakub Kicinski if (memlock) 37571bb428fSJakub Kicinski printf(" memlock %sB", memlock); 37671bb428fSJakub Kicinski free(memlock); 37771bb428fSJakub Kicinski 378743cc665SQuentin Monnet if (info->nr_map_ids) 379743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 38071bb428fSJakub Kicinski 3814990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3824990f1f4SPrashant Bhole struct pinned_obj *obj; 3834990f1f4SPrashant Bhole 3844990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3854990f1f4SPrashant Bhole if (obj->id == info->id) 386a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 3874990f1f4SPrashant Bhole } 3884990f1f4SPrashant Bhole } 3894990f1f4SPrashant Bhole 390569b0c77SPrashant Bhole if (info->btf_id) 391031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 392569b0c77SPrashant Bhole 39371bb428fSJakub Kicinski printf("\n"); 394743cc665SQuentin Monnet } 395743cc665SQuentin Monnet 396743cc665SQuentin Monnet static int show_prog(int fd) 397743cc665SQuentin Monnet { 398743cc665SQuentin Monnet struct bpf_prog_info info = {}; 399743cc665SQuentin Monnet __u32 len = sizeof(info); 400743cc665SQuentin Monnet int err; 401743cc665SQuentin Monnet 402743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 403743cc665SQuentin Monnet if (err) { 4049a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 405743cc665SQuentin Monnet return -1; 406743cc665SQuentin Monnet } 407743cc665SQuentin Monnet 408743cc665SQuentin Monnet if (json_output) 409743cc665SQuentin Monnet print_prog_json(&info, fd); 410743cc665SQuentin Monnet else 411743cc665SQuentin Monnet print_prog_plain(&info, fd); 41271bb428fSJakub Kicinski 41371bb428fSJakub Kicinski return 0; 41471bb428fSJakub Kicinski } 41571bb428fSJakub Kicinski 416*ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 417*ec202509SPaul Chaignon { 418*ec202509SPaul Chaignon int *fds = NULL; 419*ec202509SPaul Chaignon int nb_fds, i; 420*ec202509SPaul Chaignon int err = -1; 421*ec202509SPaul Chaignon 422*ec202509SPaul Chaignon fds = malloc(sizeof(int)); 423*ec202509SPaul Chaignon if (!fds) { 424*ec202509SPaul Chaignon p_err("mem alloc failed"); 425*ec202509SPaul Chaignon return -1; 426*ec202509SPaul Chaignon } 427*ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 428*ec202509SPaul Chaignon if (nb_fds < 1) 429*ec202509SPaul Chaignon goto exit_free; 430*ec202509SPaul Chaignon 431*ec202509SPaul Chaignon if (json_output && nb_fds > 1) 432*ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 433*ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 434*ec202509SPaul Chaignon err = show_prog(fds[i]); 435*ec202509SPaul Chaignon if (err) { 436*ec202509SPaul Chaignon for (; i < nb_fds; i++) 437*ec202509SPaul Chaignon close(fds[i]); 438*ec202509SPaul Chaignon break; 439*ec202509SPaul Chaignon } 440*ec202509SPaul Chaignon close(fds[i]); 441*ec202509SPaul Chaignon } 442*ec202509SPaul Chaignon if (json_output && nb_fds > 1) 443*ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 444*ec202509SPaul Chaignon 445*ec202509SPaul Chaignon exit_free: 446*ec202509SPaul Chaignon free(fds); 447*ec202509SPaul Chaignon return err; 448*ec202509SPaul Chaignon } 449*ec202509SPaul Chaignon 45071bb428fSJakub Kicinski static int do_show(int argc, char **argv) 451743cc665SQuentin Monnet { 452743cc665SQuentin Monnet __u32 id = 0; 45371bb428fSJakub Kicinski int err; 45471bb428fSJakub Kicinski int fd; 45571bb428fSJakub Kicinski 456c541b734SPrashant Bhole if (show_pinned) 4574990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 4584990f1f4SPrashant Bhole 459*ec202509SPaul Chaignon if (argc == 2) 460*ec202509SPaul Chaignon return do_show_subset(argc, argv); 46171bb428fSJakub Kicinski 46271bb428fSJakub Kicinski if (argc) 46371bb428fSJakub Kicinski return BAD_ARG(); 46471bb428fSJakub Kicinski 465743cc665SQuentin Monnet if (json_output) 466743cc665SQuentin Monnet jsonw_start_array(json_wtr); 46771bb428fSJakub Kicinski while (true) { 46871bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 46971bb428fSJakub Kicinski if (err) { 4701739c26dSQuentin Monnet if (errno == ENOENT) { 4711739c26dSQuentin Monnet err = 0; 47271bb428fSJakub Kicinski break; 4731739c26dSQuentin Monnet } 4749a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 4759a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 476743cc665SQuentin Monnet err = -1; 477743cc665SQuentin Monnet break; 47871bb428fSJakub Kicinski } 47971bb428fSJakub Kicinski 48071bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 48171bb428fSJakub Kicinski if (fd < 0) { 4828207c6ddSJakub Kicinski if (errno == ENOENT) 4838207c6ddSJakub Kicinski continue; 4849a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 48571bb428fSJakub Kicinski id, strerror(errno)); 486743cc665SQuentin Monnet err = -1; 487743cc665SQuentin Monnet break; 48871bb428fSJakub Kicinski } 48971bb428fSJakub Kicinski 49071bb428fSJakub Kicinski err = show_prog(fd); 49171bb428fSJakub Kicinski close(fd); 49271bb428fSJakub Kicinski if (err) 493743cc665SQuentin Monnet break; 49471bb428fSJakub Kicinski } 49571bb428fSJakub Kicinski 496743cc665SQuentin Monnet if (json_output) 497743cc665SQuentin Monnet jsonw_end_array(json_wtr); 498743cc665SQuentin Monnet 499743cc665SQuentin Monnet return err; 50071bb428fSJakub Kicinski } 50171bb428fSJakub Kicinski 502*ec202509SPaul Chaignon static int 503*ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 504*ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 50571bb428fSJakub Kicinski { 506b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 5073ddeac67SJakub Kicinski const char *disasm_opt = NULL; 5087105e828SDaniel Borkmann struct dump_data dd = {}; 509cae73f23SSong Liu void *func_info = NULL; 510254471e5SYonghong Song struct btf *btf = NULL; 511254471e5SYonghong Song char func_sig[1024]; 51271bb428fSJakub Kicinski unsigned char *buf; 513cae73f23SSong Liu __u32 member_len; 51471bb428fSJakub Kicinski ssize_t n; 51571bb428fSJakub Kicinski int fd; 51671bb428fSJakub Kicinski 517cae73f23SSong Liu if (mode == DUMP_JITED) { 518cae73f23SSong Liu if (info->jited_prog_len == 0) { 5199a5ab8bfSQuentin Monnet p_info("no instructions returned"); 520*ec202509SPaul Chaignon return -1; 521f84192eeSSandipan Das } 522cae73f23SSong Liu buf = (unsigned char *)(info->jited_prog_insns); 523cae73f23SSong Liu member_len = info->jited_prog_len; 524cae73f23SSong Liu } else { /* DUMP_XLATED */ 525cae73f23SSong Liu if (info->xlated_prog_len == 0) { 5267105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 527*ec202509SPaul Chaignon return -1; 5287105e828SDaniel Borkmann } 529cae73f23SSong Liu buf = (unsigned char *)info->xlated_prog_insns; 530cae73f23SSong Liu member_len = info->xlated_prog_len; 531cae73f23SSong Liu } 5327105e828SDaniel Borkmann 533cae73f23SSong Liu if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 534254471e5SYonghong Song p_err("failed to get btf"); 535*ec202509SPaul Chaignon return -1; 536254471e5SYonghong Song } 537254471e5SYonghong Song 538cae73f23SSong Liu func_info = (void *)info->func_info; 539cae73f23SSong Liu 540cae73f23SSong Liu if (info->nr_line_info) { 541cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 542b053b439SMartin KaFai Lau if (!prog_linfo) 54310a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 544b053b439SMartin KaFai Lau } 545b053b439SMartin KaFai Lau 54671bb428fSJakub Kicinski if (filepath) { 54771bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 54871bb428fSJakub Kicinski if (fd < 0) { 5499a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 55071bb428fSJakub Kicinski strerror(errno)); 551*ec202509SPaul Chaignon return -1; 55271bb428fSJakub Kicinski } 55371bb428fSJakub Kicinski 554cae73f23SSong Liu n = write(fd, buf, member_len); 55571bb428fSJakub Kicinski close(fd); 556cae73f23SSong Liu if (n != member_len) { 5579a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 55871bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 559*ec202509SPaul Chaignon return -1; 56071bb428fSJakub Kicinski } 56152c84d36SQuentin Monnet 56252c84d36SQuentin Monnet if (json_output) 56352c84d36SQuentin Monnet jsonw_null(json_wtr); 564cae73f23SSong Liu } else if (mode == DUMP_JITED) { 565e6593596SJiong Wang const char *name = NULL; 566e6593596SJiong Wang 567cae73f23SSong Liu if (info->ifindex) { 568cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 569cae73f23SSong Liu info->netns_dev, 570cae73f23SSong Liu info->netns_ino, 5713ddeac67SJakub Kicinski &disasm_opt); 572e6593596SJiong Wang if (!name) 573*ec202509SPaul Chaignon return -1; 574e6593596SJiong Wang } 575e6593596SJiong Wang 576cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 577f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 578254471e5SYonghong Song struct bpf_func_info *record; 579f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 580f7f62c71SSandipan Das unsigned char *img = buf; 581f7f62c71SSandipan Das __u64 *ksyms = NULL; 582f7f62c71SSandipan Das __u32 *lens; 583f7f62c71SSandipan Das __u32 i; 584cae73f23SSong Liu if (info->nr_jited_ksyms) { 585f7f62c71SSandipan Das kernel_syms_load(&dd); 586cae73f23SSong Liu ksyms = (__u64 *) info->jited_ksyms; 587f7f62c71SSandipan Das } 588f7f62c71SSandipan Das 589f7f62c71SSandipan Das if (json_output) 590f7f62c71SSandipan Das jsonw_start_array(json_wtr); 591f7f62c71SSandipan Das 592cae73f23SSong Liu lens = (__u32 *) info->jited_func_lens; 593cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 594f7f62c71SSandipan Das if (ksyms) { 595f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 596f7f62c71SSandipan Das if (sym) 597f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 598f7f62c71SSandipan Das else 599f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 600f7f62c71SSandipan Das } else { 601f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 602f7f62c71SSandipan Das } 603f7f62c71SSandipan Das 604254471e5SYonghong Song if (func_info) { 605cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 606254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 607254471e5SYonghong Song func_sig, 608254471e5SYonghong Song sizeof(func_sig)); 609254471e5SYonghong Song } 610254471e5SYonghong Song 611f7f62c71SSandipan Das if (json_output) { 612f7f62c71SSandipan Das jsonw_start_object(json_wtr); 613254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 614254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 615254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 616254471e5SYonghong Song } 617f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 618f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 619f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 620f7f62c71SSandipan Das } else { 621254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 622254471e5SYonghong Song printf("%s:\n", func_sig); 623f7f62c71SSandipan Das printf("%s:\n", sym_name); 624f7f62c71SSandipan Das } 625f7f62c71SSandipan Das 626b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 627b053b439SMartin KaFai Lau name, disasm_opt, btf, 628b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 629b053b439SMartin KaFai Lau linum); 630b053b439SMartin KaFai Lau 631f7f62c71SSandipan Das img += lens[i]; 632f7f62c71SSandipan Das 633f7f62c71SSandipan Das if (json_output) 634f7f62c71SSandipan Das jsonw_end_object(json_wtr); 635f7f62c71SSandipan Das else 636f7f62c71SSandipan Das printf("\n"); 637f7f62c71SSandipan Das } 638f7f62c71SSandipan Das 639f7f62c71SSandipan Das if (json_output) 640f7f62c71SSandipan Das jsonw_end_array(json_wtr); 641f7f62c71SSandipan Das } else { 642cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 643b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 644f7f62c71SSandipan Das } 645b6c1cedbSJiong Wang } else if (visual) { 646b6c1cedbSJiong Wang if (json_output) 647b6c1cedbSJiong Wang jsonw_null(json_wtr); 648b6c1cedbSJiong Wang else 649cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 6507105e828SDaniel Borkmann } else { 6517105e828SDaniel Borkmann kernel_syms_load(&dd); 652cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 653cae73f23SSong Liu dd.jited_ksyms = (__u64 *) info->jited_ksyms; 654254471e5SYonghong Song dd.btf = btf; 655254471e5SYonghong Song dd.func_info = func_info; 656cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 657b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 658f84192eeSSandipan Das 659f05e2c32SQuentin Monnet if (json_output) 660cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 661b053b439SMartin KaFai Lau linum); 662f05e2c32SQuentin Monnet else 663cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 664b053b439SMartin KaFai Lau linum); 6657105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6667105e828SDaniel Borkmann } 66771bb428fSJakub Kicinski 66871bb428fSJakub Kicinski return 0; 669*ec202509SPaul Chaignon } 67071bb428fSJakub Kicinski 671*ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 672*ec202509SPaul Chaignon { 673*ec202509SPaul Chaignon struct bpf_prog_info_linear *info_linear; 674*ec202509SPaul Chaignon char *filepath = NULL; 675*ec202509SPaul Chaignon bool opcodes = false; 676*ec202509SPaul Chaignon bool visual = false; 677*ec202509SPaul Chaignon enum dump_mode mode; 678*ec202509SPaul Chaignon bool linum = false; 679*ec202509SPaul Chaignon int *fds = NULL; 680*ec202509SPaul Chaignon int nb_fds, i = 0; 681*ec202509SPaul Chaignon int err = -1; 682*ec202509SPaul Chaignon __u64 arrays; 683*ec202509SPaul Chaignon 684*ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 685*ec202509SPaul Chaignon if (disasm_init()) 68671bb428fSJakub Kicinski return -1; 687*ec202509SPaul Chaignon mode = DUMP_JITED; 688*ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 689*ec202509SPaul Chaignon mode = DUMP_XLATED; 690*ec202509SPaul Chaignon } else { 691*ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 692*ec202509SPaul Chaignon return -1; 693*ec202509SPaul Chaignon } 694*ec202509SPaul Chaignon NEXT_ARG(); 695*ec202509SPaul Chaignon 696*ec202509SPaul Chaignon if (argc < 2) 697*ec202509SPaul Chaignon usage(); 698*ec202509SPaul Chaignon 699*ec202509SPaul Chaignon fds = malloc(sizeof(int)); 700*ec202509SPaul Chaignon if (!fds) { 701*ec202509SPaul Chaignon p_err("mem alloc failed"); 702*ec202509SPaul Chaignon return -1; 703*ec202509SPaul Chaignon } 704*ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 705*ec202509SPaul Chaignon if (nb_fds < 1) 706*ec202509SPaul Chaignon goto exit_free; 707*ec202509SPaul Chaignon 708*ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 709*ec202509SPaul Chaignon NEXT_ARG(); 710*ec202509SPaul Chaignon if (!argc) { 711*ec202509SPaul Chaignon p_err("expected file path"); 712*ec202509SPaul Chaignon goto exit_close; 713*ec202509SPaul Chaignon } 714*ec202509SPaul Chaignon if (nb_fds > 1) { 715*ec202509SPaul Chaignon p_err("several programs matched"); 716*ec202509SPaul Chaignon goto exit_close; 717*ec202509SPaul Chaignon } 718*ec202509SPaul Chaignon 719*ec202509SPaul Chaignon filepath = *argv; 720*ec202509SPaul Chaignon NEXT_ARG(); 721*ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 722*ec202509SPaul Chaignon opcodes = true; 723*ec202509SPaul Chaignon NEXT_ARG(); 724*ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 725*ec202509SPaul Chaignon if (nb_fds > 1) { 726*ec202509SPaul Chaignon p_err("several programs matched"); 727*ec202509SPaul Chaignon goto exit_close; 728*ec202509SPaul Chaignon } 729*ec202509SPaul Chaignon 730*ec202509SPaul Chaignon visual = true; 731*ec202509SPaul Chaignon NEXT_ARG(); 732*ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 733*ec202509SPaul Chaignon linum = true; 734*ec202509SPaul Chaignon NEXT_ARG(); 735*ec202509SPaul Chaignon } 736*ec202509SPaul Chaignon 737*ec202509SPaul Chaignon if (argc) { 738*ec202509SPaul Chaignon usage(); 739*ec202509SPaul Chaignon goto exit_close; 740*ec202509SPaul Chaignon } 741*ec202509SPaul Chaignon 742*ec202509SPaul Chaignon if (mode == DUMP_JITED) 743*ec202509SPaul Chaignon arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 744*ec202509SPaul Chaignon else 745*ec202509SPaul Chaignon arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 746*ec202509SPaul Chaignon 747*ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 748*ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 749*ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 750*ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 751*ec202509SPaul Chaignon arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 752*ec202509SPaul Chaignon 753*ec202509SPaul Chaignon if (json_output && nb_fds > 1) 754*ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 755*ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 756*ec202509SPaul Chaignon info_linear = bpf_program__get_prog_info_linear(fds[i], arrays); 757*ec202509SPaul Chaignon if (IS_ERR_OR_NULL(info_linear)) { 758*ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 759*ec202509SPaul Chaignon break; 760*ec202509SPaul Chaignon } 761*ec202509SPaul Chaignon 762*ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 763*ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 764*ec202509SPaul Chaignon print_prog_header_json(&info_linear->info); 765*ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 766*ec202509SPaul Chaignon } else if (nb_fds > 1) { 767*ec202509SPaul Chaignon print_prog_header_plain(&info_linear->info); 768*ec202509SPaul Chaignon } 769*ec202509SPaul Chaignon 770*ec202509SPaul Chaignon err = prog_dump(&info_linear->info, mode, filepath, opcodes, 771*ec202509SPaul Chaignon visual, linum); 772*ec202509SPaul Chaignon 773*ec202509SPaul Chaignon if (json_output && nb_fds > 1) 774*ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 775*ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 776*ec202509SPaul Chaignon printf("\n"); 777*ec202509SPaul Chaignon 778*ec202509SPaul Chaignon free(info_linear); 779*ec202509SPaul Chaignon if (err) 780*ec202509SPaul Chaignon break; 781*ec202509SPaul Chaignon close(fds[i]); 782*ec202509SPaul Chaignon } 783*ec202509SPaul Chaignon if (json_output && nb_fds > 1) 784*ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 785*ec202509SPaul Chaignon 786*ec202509SPaul Chaignon exit_close: 787*ec202509SPaul Chaignon for (; i < nb_fds; i++) 788*ec202509SPaul Chaignon close(fds[i]); 789*ec202509SPaul Chaignon exit_free: 790*ec202509SPaul Chaignon free(fds); 791*ec202509SPaul Chaignon return err; 79271bb428fSJakub Kicinski } 79371bb428fSJakub Kicinski 79471bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 79571bb428fSJakub Kicinski { 796004b45c0SQuentin Monnet int err; 797004b45c0SQuentin Monnet 798004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 799004b45c0SQuentin Monnet if (!err && json_output) 800004b45c0SQuentin Monnet jsonw_null(json_wtr); 801004b45c0SQuentin Monnet return err; 80271bb428fSJakub Kicinski } 80371bb428fSJakub Kicinski 8043ff5a4dcSJakub Kicinski struct map_replace { 8053ff5a4dcSJakub Kicinski int idx; 8063ff5a4dcSJakub Kicinski int fd; 8073ff5a4dcSJakub Kicinski char *name; 8083ff5a4dcSJakub Kicinski }; 8093ff5a4dcSJakub Kicinski 810c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 8113ff5a4dcSJakub Kicinski { 8123ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 8133ff5a4dcSJakub Kicinski 8143ff5a4dcSJakub Kicinski return a->idx - b->idx; 8153ff5a4dcSJakub Kicinski } 8163ff5a4dcSJakub Kicinski 817092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 818092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 819092f0892SStanislav Fomichev int *mapfd) 820092f0892SStanislav Fomichev { 821092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 822092f0892SStanislav Fomichev return -EINVAL; 823092f0892SStanislav Fomichev 824092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 825092f0892SStanislav Fomichev if (*progfd < 0) 826092f0892SStanislav Fomichev return *progfd; 827092f0892SStanislav Fomichev 828092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 829092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 830092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 831092f0892SStanislav Fomichev return -EINVAL; 832092f0892SStanislav Fomichev } 833092f0892SStanislav Fomichev 834092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 835092f0892SStanislav Fomichev *mapfd = -1; 836092f0892SStanislav Fomichev return 0; 837092f0892SStanislav Fomichev } 838092f0892SStanislav Fomichev 839092f0892SStanislav Fomichev NEXT_ARG(); 840092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 841092f0892SStanislav Fomichev return -EINVAL; 842092f0892SStanislav Fomichev 843092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 844092f0892SStanislav Fomichev if (*mapfd < 0) 845092f0892SStanislav Fomichev return *mapfd; 846092f0892SStanislav Fomichev 847092f0892SStanislav Fomichev return 0; 848092f0892SStanislav Fomichev } 849092f0892SStanislav Fomichev 850b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 851b7d3826cSJohn Fastabend { 852b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 853092f0892SStanislav Fomichev int err, progfd; 854092f0892SStanislav Fomichev int mapfd; 855b7d3826cSJohn Fastabend 856092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 857092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 858092f0892SStanislav Fomichev if (err) 859092f0892SStanislav Fomichev return err; 860b7d3826cSJohn Fastabend 861b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 862b7d3826cSJohn Fastabend if (err) { 863b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 864b7d3826cSJohn Fastabend return -EINVAL; 865b7d3826cSJohn Fastabend } 866b7d3826cSJohn Fastabend 867b7d3826cSJohn Fastabend if (json_output) 868b7d3826cSJohn Fastabend jsonw_null(json_wtr); 869b7d3826cSJohn Fastabend return 0; 870b7d3826cSJohn Fastabend } 871b7d3826cSJohn Fastabend 872b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 873b7d3826cSJohn Fastabend { 874b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 875092f0892SStanislav Fomichev int err, progfd; 876092f0892SStanislav Fomichev int mapfd; 877b7d3826cSJohn Fastabend 878092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 879092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 880092f0892SStanislav Fomichev if (err) 881092f0892SStanislav Fomichev return err; 882b7d3826cSJohn Fastabend 883b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 884b7d3826cSJohn Fastabend if (err) { 885b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 886b7d3826cSJohn Fastabend return -EINVAL; 887b7d3826cSJohn Fastabend } 888b7d3826cSJohn Fastabend 889b7d3826cSJohn Fastabend if (json_output) 890b7d3826cSJohn Fastabend jsonw_null(json_wtr); 891b7d3826cSJohn Fastabend return 0; 892b7d3826cSJohn Fastabend } 89377380998SStanislav Fomichev 894ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 895ba95c745SQuentin Monnet { 896ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 897ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 898ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 899ba95c745SQuentin Monnet return -1; 900ba95c745SQuentin Monnet } 901ba95c745SQuentin Monnet 902ba95c745SQuentin Monnet return 0; 903ba95c745SQuentin Monnet } 904ba95c745SQuentin Monnet 905ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 906ba95c745SQuentin Monnet { 907ba95c745SQuentin Monnet size_t block_size = 256; 908ba95c745SQuentin Monnet size_t buf_size = block_size; 909ba95c745SQuentin Monnet size_t nb_read = 0; 910ba95c745SQuentin Monnet void *tmp; 911ba95c745SQuentin Monnet FILE *f; 912ba95c745SQuentin Monnet 913ba95c745SQuentin Monnet if (!fname) { 914ba95c745SQuentin Monnet *data_ptr = NULL; 915ba95c745SQuentin Monnet *size = 0; 916ba95c745SQuentin Monnet return 0; 917ba95c745SQuentin Monnet } 918ba95c745SQuentin Monnet 919ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 920ba95c745SQuentin Monnet f = stdin; 921ba95c745SQuentin Monnet else 922ba95c745SQuentin Monnet f = fopen(fname, "r"); 923ba95c745SQuentin Monnet if (!f) { 924ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 925ba95c745SQuentin Monnet return -1; 926ba95c745SQuentin Monnet } 927ba95c745SQuentin Monnet 928ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 929ba95c745SQuentin Monnet if (!*data_ptr) { 930ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 931ba95c745SQuentin Monnet strerror(errno)); 932ba95c745SQuentin Monnet goto err_fclose; 933ba95c745SQuentin Monnet } 934ba95c745SQuentin Monnet 935ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 936ba95c745SQuentin Monnet if (feof(f)) 937ba95c745SQuentin Monnet break; 938ba95c745SQuentin Monnet if (ferror(f)) { 939ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 940ba95c745SQuentin Monnet fname, strerror(errno)); 941ba95c745SQuentin Monnet goto err_free; 942ba95c745SQuentin Monnet } 943ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 944ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 945ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 946ba95c745SQuentin Monnet UINT32_MAX); 947ba95c745SQuentin Monnet goto err_free; 948ba95c745SQuentin Monnet } 949ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 950ba95c745SQuentin Monnet buf_size *= 2; 951ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 952ba95c745SQuentin Monnet if (!tmp) { 953ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 954ba95c745SQuentin Monnet strerror(errno)); 955ba95c745SQuentin Monnet goto err_free; 956ba95c745SQuentin Monnet } 957ba95c745SQuentin Monnet *data_ptr = tmp; 958ba95c745SQuentin Monnet } 959ba95c745SQuentin Monnet } 960ba95c745SQuentin Monnet if (f != stdin) 961ba95c745SQuentin Monnet fclose(f); 962ba95c745SQuentin Monnet 963ba95c745SQuentin Monnet *size = nb_read; 964ba95c745SQuentin Monnet return 0; 965ba95c745SQuentin Monnet 966ba95c745SQuentin Monnet err_free: 967ba95c745SQuentin Monnet free(*data_ptr); 968ba95c745SQuentin Monnet *data_ptr = NULL; 969ba95c745SQuentin Monnet err_fclose: 970ba95c745SQuentin Monnet if (f != stdin) 971ba95c745SQuentin Monnet fclose(f); 972ba95c745SQuentin Monnet return -1; 973ba95c745SQuentin Monnet } 974ba95c745SQuentin Monnet 975ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 976ba95c745SQuentin Monnet { 977ba95c745SQuentin Monnet size_t i, j; 978ba95c745SQuentin Monnet char c; 979ba95c745SQuentin Monnet 980ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 981ba95c745SQuentin Monnet /* Row offset */ 982ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 983ba95c745SQuentin Monnet 984ba95c745SQuentin Monnet /* Hexadecimal values */ 985ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 986ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 987ba95c745SQuentin Monnet j % 2 ? " " : ""); 988ba95c745SQuentin Monnet for (; j < i + 16; j++) 989ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 990ba95c745SQuentin Monnet 991ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 992ba95c745SQuentin Monnet fprintf(f, "| "); 993ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 994ba95c745SQuentin Monnet c = *(char *)(data + j); 995ba95c745SQuentin Monnet if (c < ' ' || c > '~') 996ba95c745SQuentin Monnet c = '.'; 997ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 998ba95c745SQuentin Monnet } 999ba95c745SQuentin Monnet 1000ba95c745SQuentin Monnet fprintf(f, "\n"); 1001ba95c745SQuentin Monnet } 1002ba95c745SQuentin Monnet } 1003ba95c745SQuentin Monnet 1004ba95c745SQuentin Monnet static int 1005ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1006ba95c745SQuentin Monnet const char *json_key) 1007ba95c745SQuentin Monnet { 1008ba95c745SQuentin Monnet size_t nb_written; 1009ba95c745SQuentin Monnet FILE *f; 1010ba95c745SQuentin Monnet 1011ba95c745SQuentin Monnet if (!fname) 1012ba95c745SQuentin Monnet return 0; 1013ba95c745SQuentin Monnet 1014ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1015ba95c745SQuentin Monnet f = stdout; 1016ba95c745SQuentin Monnet if (json_output) { 1017ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1018ba95c745SQuentin Monnet print_data_json(data, size); 1019ba95c745SQuentin Monnet } else { 1020ba95c745SQuentin Monnet hex_print(data, size, f); 1021ba95c745SQuentin Monnet } 1022ba95c745SQuentin Monnet return 0; 1023ba95c745SQuentin Monnet } 1024ba95c745SQuentin Monnet 1025ba95c745SQuentin Monnet f = fopen(fname, "w"); 1026ba95c745SQuentin Monnet if (!f) { 1027ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1028ba95c745SQuentin Monnet return -1; 1029ba95c745SQuentin Monnet } 1030ba95c745SQuentin Monnet 1031ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1032ba95c745SQuentin Monnet fclose(f); 1033ba95c745SQuentin Monnet if (nb_written != size) { 1034ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1035ba95c745SQuentin Monnet return -1; 1036ba95c745SQuentin Monnet } 1037ba95c745SQuentin Monnet 1038ba95c745SQuentin Monnet return 0; 1039ba95c745SQuentin Monnet } 1040ba95c745SQuentin Monnet 1041ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1042ba95c745SQuentin Monnet { 1043ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1044ba95c745SQuentin Monnet if (!*data_ptr) { 1045ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1046ba95c745SQuentin Monnet strerror(errno)); 1047ba95c745SQuentin Monnet return -1; 1048ba95c745SQuentin Monnet } 1049ba95c745SQuentin Monnet 1050ba95c745SQuentin Monnet return 0; 1051ba95c745SQuentin Monnet } 1052ba95c745SQuentin Monnet 1053ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1054ba95c745SQuentin Monnet { 1055ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1056ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1057ba95c745SQuentin Monnet struct bpf_prog_test_run_attr test_attr = {0}; 1058ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1059ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1060ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1061ba95c745SQuentin Monnet unsigned int repeat = 1; 1062ba95c745SQuentin Monnet int fd, err; 1063ba95c745SQuentin Monnet 1064ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1065ba95c745SQuentin Monnet return -1; 1066ba95c745SQuentin Monnet 1067ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1068ba95c745SQuentin Monnet if (fd < 0) 1069ba95c745SQuentin Monnet return -1; 1070ba95c745SQuentin Monnet 1071ba95c745SQuentin Monnet while (argc) { 1072ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1073ba95c745SQuentin Monnet "data_size_out", NULL)) 1074ba95c745SQuentin Monnet return -1; 1075ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1076ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1077ba95c745SQuentin Monnet return -1; 1078ba95c745SQuentin Monnet 1079ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1080ba95c745SQuentin Monnet NEXT_ARG(); 1081ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1082ba95c745SQuentin Monnet return -1; 1083ba95c745SQuentin Monnet 1084ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1085ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1086ba95c745SQuentin Monnet return -1; 1087ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1088ba95c745SQuentin Monnet NEXT_ARG(); 1089ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1090ba95c745SQuentin Monnet return -1; 1091ba95c745SQuentin Monnet 1092ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1093ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1094ba95c745SQuentin Monnet char *endptr; 1095ba95c745SQuentin Monnet 1096ba95c745SQuentin Monnet NEXT_ARG(); 1097ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1098ba95c745SQuentin Monnet return -1; 1099ba95c745SQuentin Monnet 1100ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1101ba95c745SQuentin Monnet if (*endptr) { 1102ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1103ba95c745SQuentin Monnet *argv); 1104ba95c745SQuentin Monnet return -1; 1105ba95c745SQuentin Monnet } 1106ba95c745SQuentin Monnet NEXT_ARG(); 1107ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1108ba95c745SQuentin Monnet NEXT_ARG(); 1109ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1110ba95c745SQuentin Monnet return -1; 1111ba95c745SQuentin Monnet 1112ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1113ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1114ba95c745SQuentin Monnet return -1; 1115ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1116ba95c745SQuentin Monnet NEXT_ARG(); 1117ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1118ba95c745SQuentin Monnet return -1; 1119ba95c745SQuentin Monnet 1120ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1121ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1122ba95c745SQuentin Monnet char *endptr; 1123ba95c745SQuentin Monnet 1124ba95c745SQuentin Monnet NEXT_ARG(); 1125ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1126ba95c745SQuentin Monnet return -1; 1127ba95c745SQuentin Monnet 1128ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1129ba95c745SQuentin Monnet if (*endptr) { 1130ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1131ba95c745SQuentin Monnet *argv); 1132ba95c745SQuentin Monnet return -1; 1133ba95c745SQuentin Monnet } 1134ba95c745SQuentin Monnet NEXT_ARG(); 1135ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1136ba95c745SQuentin Monnet char *endptr; 1137ba95c745SQuentin Monnet 1138ba95c745SQuentin Monnet NEXT_ARG(); 1139ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1140ba95c745SQuentin Monnet return -1; 1141ba95c745SQuentin Monnet 1142ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1143ba95c745SQuentin Monnet if (*endptr) { 1144ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1145ba95c745SQuentin Monnet *argv); 1146ba95c745SQuentin Monnet return -1; 1147ba95c745SQuentin Monnet } 1148ba95c745SQuentin Monnet NEXT_ARG(); 1149ba95c745SQuentin Monnet } else { 1150ba95c745SQuentin 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'?", 1151ba95c745SQuentin Monnet *argv); 1152ba95c745SQuentin Monnet return -1; 1153ba95c745SQuentin Monnet } 1154ba95c745SQuentin Monnet } 1155ba95c745SQuentin Monnet 1156ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1157ba95c745SQuentin Monnet if (err) 1158ba95c745SQuentin Monnet return -1; 1159ba95c745SQuentin Monnet 1160ba95c745SQuentin Monnet if (data_in) { 1161ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1162ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1163ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1164ba95c745SQuentin Monnet if (err) 1165ba95c745SQuentin Monnet goto free_data_in; 1166ba95c745SQuentin Monnet } 1167ba95c745SQuentin Monnet 1168ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1169ba95c745SQuentin Monnet if (err) 1170ba95c745SQuentin Monnet goto free_data_out; 1171ba95c745SQuentin Monnet 1172ba95c745SQuentin Monnet if (ctx_in) { 1173ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1174ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1175ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1176ba95c745SQuentin Monnet if (err) 1177ba95c745SQuentin Monnet goto free_ctx_in; 1178ba95c745SQuentin Monnet } 1179ba95c745SQuentin Monnet 1180ba95c745SQuentin Monnet test_attr.prog_fd = fd; 1181ba95c745SQuentin Monnet test_attr.repeat = repeat; 1182ba95c745SQuentin Monnet test_attr.data_in = data_in; 1183ba95c745SQuentin Monnet test_attr.data_out = data_out; 1184ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1185ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1186ba95c745SQuentin Monnet 1187ba95c745SQuentin Monnet err = bpf_prog_test_run_xattr(&test_attr); 1188ba95c745SQuentin Monnet if (err) { 1189ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1190ba95c745SQuentin Monnet goto free_ctx_out; 1191ba95c745SQuentin Monnet } 1192ba95c745SQuentin Monnet 1193ba95c745SQuentin Monnet err = 0; 1194ba95c745SQuentin Monnet 1195ba95c745SQuentin Monnet if (json_output) 1196ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1197ba95c745SQuentin Monnet 1198ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1199ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1200ba95c745SQuentin Monnet */ 1201ba95c745SQuentin Monnet if (test_attr.data_size_out) 1202ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1203ba95c745SQuentin Monnet test_attr.data_size_out, 1204ba95c745SQuentin Monnet data_fname_out, "data_out"); 1205ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1206ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1207ba95c745SQuentin Monnet test_attr.ctx_size_out, 1208ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1209ba95c745SQuentin Monnet 1210ba95c745SQuentin Monnet if (json_output) { 1211ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1212ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1213ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1214ba95c745SQuentin Monnet } else { 1215ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1216ba95c745SQuentin Monnet test_attr.retval, 1217ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1218ba95c745SQuentin Monnet } 1219ba95c745SQuentin Monnet 1220ba95c745SQuentin Monnet free_ctx_out: 1221ba95c745SQuentin Monnet free(ctx_out); 1222ba95c745SQuentin Monnet free_ctx_in: 1223ba95c745SQuentin Monnet free(ctx_in); 1224ba95c745SQuentin Monnet free_data_out: 1225ba95c745SQuentin Monnet free(data_out); 1226ba95c745SQuentin Monnet free_data_in: 1227ba95c745SQuentin Monnet free(data_in); 1228ba95c745SQuentin Monnet 1229ba95c745SQuentin Monnet return err; 1230ba95c745SQuentin Monnet } 1231ba95c745SQuentin Monnet 123277380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 123349a086c2SRoman Gushchin { 123432e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1235e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1236e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1237e00aca65SAndrii Nakryiko ); 1238e00aca65SAndrii Nakryiko struct bpf_object_load_attr load_attr = { 0 }; 123955d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 12403ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 124177380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 12423ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 12433767a94bSStanislav Fomichev const char *pinmaps = NULL; 124449a086c2SRoman Gushchin struct bpf_object *obj; 1245c8406848SJakub Kicinski struct bpf_map *map; 1246c8406848SJakub Kicinski const char *pinfile; 12473ff5a4dcSJakub Kicinski unsigned int i, j; 1248c8406848SJakub Kicinski __u32 ifindex = 0; 124932e3e58eSAndrii Nakryiko const char *file; 12503ff5a4dcSJakub Kicinski int idx, err; 125149a086c2SRoman Gushchin 125232e3e58eSAndrii Nakryiko 12538d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 12548d1fc3deSJakub Kicinski return -1; 125532e3e58eSAndrii Nakryiko file = GET_ARG(); 12568d1fc3deSJakub Kicinski pinfile = GET_ARG(); 125749a086c2SRoman Gushchin 1258ba6dd679SJakub Kicinski while (argc) { 125949f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 126049f2cba3SJakub Kicinski char *type; 126149f2cba3SJakub Kicinski 126249f2cba3SJakub Kicinski NEXT_ARG(); 126349f2cba3SJakub Kicinski 126432e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 126549f2cba3SJakub Kicinski p_err("program type already specified"); 12663ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 126749f2cba3SJakub Kicinski } 126849f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 12693ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 127049f2cba3SJakub Kicinski 127149f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 127249f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 127349f2cba3SJakub Kicinski if (!type) { 127449f2cba3SJakub Kicinski p_err("mem alloc failed"); 12753ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 127649f2cba3SJakub Kicinski } 127749f2cba3SJakub Kicinski *type = 0; 127849f2cba3SJakub Kicinski strcat(type, *argv); 127949f2cba3SJakub Kicinski strcat(type, "/"); 128049f2cba3SJakub Kicinski 128132e3e58eSAndrii Nakryiko err = libbpf_prog_type_by_name(type, &common_prog_type, 1282c8406848SJakub Kicinski &expected_attach_type); 128349f2cba3SJakub Kicinski free(type); 1284c76e4c22STaeung Song if (err < 0) 12853ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1286c76e4c22STaeung Song 128749f2cba3SJakub Kicinski NEXT_ARG(); 12883ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1289dde7011aSJakub Kicinski void *new_map_replace; 12903ff5a4dcSJakub Kicinski char *endptr, *name; 12913ff5a4dcSJakub Kicinski int fd; 12923ff5a4dcSJakub Kicinski 12933ff5a4dcSJakub Kicinski NEXT_ARG(); 12943ff5a4dcSJakub Kicinski 12953ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 12963ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 12973ff5a4dcSJakub Kicinski 12983ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 12993ff5a4dcSJakub Kicinski NEXT_ARG(); 13003ff5a4dcSJakub Kicinski 13013ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 13023ff5a4dcSJakub Kicinski if (*endptr) { 13033ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 13043ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13053ff5a4dcSJakub Kicinski } 13063ff5a4dcSJakub Kicinski name = NULL; 13073ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 13083ff5a4dcSJakub Kicinski NEXT_ARG(); 13093ff5a4dcSJakub Kicinski 13103ff5a4dcSJakub Kicinski name = *argv; 13113ff5a4dcSJakub Kicinski idx = -1; 13123ff5a4dcSJakub Kicinski } else { 13133ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 13143ff5a4dcSJakub Kicinski *argv); 13153ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13163ff5a4dcSJakub Kicinski } 13173ff5a4dcSJakub Kicinski NEXT_ARG(); 13183ff5a4dcSJakub Kicinski 13193ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 13203ff5a4dcSJakub Kicinski if (fd < 0) 13213ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13223ff5a4dcSJakub Kicinski 1323dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 1324dde7011aSJakub Kicinski old_map_fds + 1, 13253ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1326dde7011aSJakub Kicinski if (!new_map_replace) { 13273ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 13283ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 13293ff5a4dcSJakub Kicinski } 1330dde7011aSJakub Kicinski map_replace = new_map_replace; 1331dde7011aSJakub Kicinski 13323ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 13333ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 13343ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 13353ff5a4dcSJakub Kicinski old_map_fds++; 133649f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1337ba6dd679SJakub Kicinski NEXT_ARG(); 1338ba6dd679SJakub Kicinski 1339c8406848SJakub Kicinski if (ifindex) { 1340ba6dd679SJakub Kicinski p_err("offload device already specified"); 13413ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1342ba6dd679SJakub Kicinski } 1343ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 13443ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1345ba6dd679SJakub Kicinski 1346c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1347c8406848SJakub Kicinski if (!ifindex) { 1348ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1349ba6dd679SJakub Kicinski *argv, strerror(errno)); 13503ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1351ba6dd679SJakub Kicinski } 1352ba6dd679SJakub Kicinski NEXT_ARG(); 13533767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 13543767a94bSStanislav Fomichev NEXT_ARG(); 13553767a94bSStanislav Fomichev 13563767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 13573767a94bSStanislav Fomichev goto err_free_reuse_maps; 13583767a94bSStanislav Fomichev 13593767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1360ba6dd679SJakub Kicinski } else { 13613ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1362ba6dd679SJakub Kicinski *argv); 13633ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1364ba6dd679SJakub Kicinski } 1365ba6dd679SJakub Kicinski } 1366ba6dd679SJakub Kicinski 1367ac4e0e05SYonghong Song set_max_rlimit(); 1368ac4e0e05SYonghong Song 136932e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1370c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 1371c8406848SJakub Kicinski p_err("failed to open object file"); 13723ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 137349a086c2SRoman Gushchin } 137449a086c2SRoman Gushchin 137577380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 137632e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1377c8406848SJakub Kicinski 137832e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 137977380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1380c8406848SJakub Kicinski 138177380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 1382c8406848SJakub Kicinski &expected_attach_type); 1383c76e4c22STaeung Song if (err < 0) 1384c8406848SJakub Kicinski goto err_close_obj; 1385c8406848SJakub Kicinski } 138677380998SStanislav Fomichev 138777380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 138877380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 138977380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 139077380998SStanislav Fomichev } 1391c8406848SJakub Kicinski 13923ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 13933ff5a4dcSJakub Kicinski map_replace_compar); 13943ff5a4dcSJakub Kicinski 13953ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 13963ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 13973ff5a4dcSJakub Kicinski */ 13983ff5a4dcSJakub Kicinski j = 0; 13993ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 14003ff5a4dcSJakub Kicinski i = 0; 1401f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 14023ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 14033ff5a4dcSJakub Kicinski map_replace[j].idx = i; 14043ff5a4dcSJakub Kicinski break; 14053ff5a4dcSJakub Kicinski } 14063ff5a4dcSJakub Kicinski i++; 14073ff5a4dcSJakub Kicinski } 14083ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 14093ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 14103ff5a4dcSJakub Kicinski goto err_close_obj; 14113ff5a4dcSJakub Kicinski } 14123ff5a4dcSJakub Kicinski j++; 14133ff5a4dcSJakub Kicinski } 14143ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 14153ff5a4dcSJakub Kicinski if (j) 14163ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 14173ff5a4dcSJakub Kicinski map_replace_compar); 14183ff5a4dcSJakub Kicinski 14193ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 14203ff5a4dcSJakub Kicinski j = 0; 14213ff5a4dcSJakub Kicinski idx = 0; 1422f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 1423c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1424c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1425c8406848SJakub Kicinski 14263ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 14273ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 14283ff5a4dcSJakub Kicinski if (err) { 14293ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 14303ff5a4dcSJakub Kicinski goto err_close_obj; 14313ff5a4dcSJakub Kicinski } 14323ff5a4dcSJakub Kicinski 14333ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 14343ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 14353ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 14363ff5a4dcSJakub Kicinski idx); 14373ff5a4dcSJakub Kicinski goto err_close_obj; 14383ff5a4dcSJakub Kicinski } 14393ff5a4dcSJakub Kicinski } 14403ff5a4dcSJakub Kicinski 14413ff5a4dcSJakub Kicinski idx++; 14423ff5a4dcSJakub Kicinski } 14433ff5a4dcSJakub Kicinski if (j < old_map_fds) { 14443ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 14453ff5a4dcSJakub Kicinski goto err_close_obj; 14463ff5a4dcSJakub Kicinski } 14473ff5a4dcSJakub Kicinski 144855d77807SQuentin Monnet load_attr.obj = obj; 144955d77807SQuentin Monnet if (verifier_logs) 145055d77807SQuentin Monnet /* log_level1 + log_level2 + stats, but not stable UAPI */ 145155d77807SQuentin Monnet load_attr.log_level = 1 + 2 + 4; 145255d77807SQuentin Monnet 145355d77807SQuentin Monnet err = bpf_object__load_xattr(&load_attr); 1454c8406848SJakub Kicinski if (err) { 1455c8406848SJakub Kicinski p_err("failed to load object file"); 1456c8406848SJakub Kicinski goto err_close_obj; 1457c8406848SJakub Kicinski } 1458c8406848SJakub Kicinski 145977380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 146077380998SStanislav Fomichev if (err) 1461bfee71fbSJakub Kicinski goto err_close_obj; 146249a086c2SRoman Gushchin 146377380998SStanislav Fomichev if (first_prog_only) { 146477380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 146577380998SStanislav Fomichev if (!prog) { 146677380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 146777380998SStanislav Fomichev goto err_close_obj; 146877380998SStanislav Fomichev } 146977380998SStanislav Fomichev 147077380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 147177380998SStanislav Fomichev if (err) { 147277380998SStanislav Fomichev p_err("failed to pin program %s", 147377380998SStanislav Fomichev bpf_program__title(prog, false)); 147477380998SStanislav Fomichev goto err_close_obj; 147577380998SStanislav Fomichev } 147677380998SStanislav Fomichev } else { 147777380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 147877380998SStanislav Fomichev if (err) { 147977380998SStanislav Fomichev p_err("failed to pin all programs"); 148077380998SStanislav Fomichev goto err_close_obj; 148177380998SStanislav Fomichev } 148277380998SStanislav Fomichev } 148377380998SStanislav Fomichev 14843767a94bSStanislav Fomichev if (pinmaps) { 14853767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 14863767a94bSStanislav Fomichev if (err) { 14873767a94bSStanislav Fomichev p_err("failed to pin all maps"); 14883767a94bSStanislav Fomichev goto err_unpin; 14893767a94bSStanislav Fomichev } 14903767a94bSStanislav Fomichev } 14913767a94bSStanislav Fomichev 149249a086c2SRoman Gushchin if (json_output) 149349a086c2SRoman Gushchin jsonw_null(json_wtr); 149449a086c2SRoman Gushchin 1495bfee71fbSJakub Kicinski bpf_object__close(obj); 14963ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 14973ff5a4dcSJakub Kicinski close(map_replace[i].fd); 14983ff5a4dcSJakub Kicinski free(map_replace); 1499bfee71fbSJakub Kicinski 150049a086c2SRoman Gushchin return 0; 1501bfee71fbSJakub Kicinski 15023767a94bSStanislav Fomichev err_unpin: 15033767a94bSStanislav Fomichev if (first_prog_only) 15043767a94bSStanislav Fomichev unlink(pinfile); 15053767a94bSStanislav Fomichev else 15063767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1507bfee71fbSJakub Kicinski err_close_obj: 1508bfee71fbSJakub Kicinski bpf_object__close(obj); 15093ff5a4dcSJakub Kicinski err_free_reuse_maps: 15103ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 15113ff5a4dcSJakub Kicinski close(map_replace[i].fd); 15123ff5a4dcSJakub Kicinski free(map_replace); 1513bfee71fbSJakub Kicinski return -1; 151449a086c2SRoman Gushchin } 151549a086c2SRoman Gushchin 151677380998SStanislav Fomichev static int do_load(int argc, char **argv) 151777380998SStanislav Fomichev { 151877380998SStanislav Fomichev return load_with_options(argc, argv, true); 151977380998SStanislav Fomichev } 152077380998SStanislav Fomichev 152177380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 152277380998SStanislav Fomichev { 152377380998SStanislav Fomichev return load_with_options(argc, argv, false); 152477380998SStanislav Fomichev } 152577380998SStanislav Fomichev 152671bb428fSJakub Kicinski static int do_help(int argc, char **argv) 152771bb428fSJakub Kicinski { 1528004b45c0SQuentin Monnet if (json_output) { 1529004b45c0SQuentin Monnet jsonw_null(json_wtr); 1530004b45c0SQuentin Monnet return 0; 1531004b45c0SQuentin Monnet } 1532004b45c0SQuentin Monnet 153371bb428fSJakub Kicinski fprintf(stderr, 15346ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1535b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1536b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 153771bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 153877380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 153977380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 15403767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 15413767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1542092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1543092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1544ba95c745SQuentin Monnet " %s %s run PROG \\\n" 1545ba95c745SQuentin Monnet " data_in FILE \\\n" 1546ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 1547ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1548ba95c745SQuentin Monnet " [repeat N]\n" 154930da46b5SQuentin Monnet " %s %s tracelog\n" 155071bb428fSJakub Kicinski " %s %s help\n" 155171bb428fSJakub Kicinski "\n" 15523ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 155371bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 155449f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 155549f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 155649f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 155749f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1558f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 155949f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 156049f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1561000aa125SDaniel Borkmann " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1562f6d08d9dSStanislav Fomichev " cgroup/recvmsg6 | cgroup/getsockopt |\n" 1563f6d08d9dSStanislav Fomichev " cgroup/setsockopt }\n" 1564a5d9265eSAlban Crequy " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1565092f0892SStanislav Fomichev " flow_dissector }\n" 15660641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 156771bb428fSJakub Kicinski "", 156871bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1569b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1570ba95c745SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1571ba95c745SQuentin Monnet bin_name, argv[-2]); 157271bb428fSJakub Kicinski 157371bb428fSJakub Kicinski return 0; 157471bb428fSJakub Kicinski } 157571bb428fSJakub Kicinski 157671bb428fSJakub Kicinski static const struct cmd cmds[] = { 157771bb428fSJakub Kicinski { "show", do_show }, 15786ebe6dbdSJakub Kicinski { "list", do_show }, 15799f606179SQuentin Monnet { "help", do_help }, 158071bb428fSJakub Kicinski { "dump", do_dump }, 158171bb428fSJakub Kicinski { "pin", do_pin }, 158249a086c2SRoman Gushchin { "load", do_load }, 158377380998SStanislav Fomichev { "loadall", do_loadall }, 1584b7d3826cSJohn Fastabend { "attach", do_attach }, 1585b7d3826cSJohn Fastabend { "detach", do_detach }, 158630da46b5SQuentin Monnet { "tracelog", do_tracelog }, 1587ba95c745SQuentin Monnet { "run", do_run }, 158871bb428fSJakub Kicinski { 0 } 158971bb428fSJakub Kicinski }; 159071bb428fSJakub Kicinski 159171bb428fSJakub Kicinski int do_prog(int argc, char **argv) 159271bb428fSJakub Kicinski { 159371bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 159471bb428fSJakub Kicinski } 1595