1*02ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2*02ff58dcSJakub 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> 18c8406848SJakub Kicinski 1971bb428fSJakub Kicinski #include <bpf.h> 20254471e5SYonghong Song #include <btf.h> 2149a086c2SRoman Gushchin #include <libbpf.h> 2271bb428fSJakub Kicinski 23b6c1cedbSJiong Wang #include "cfg.h" 2471bb428fSJakub Kicinski #include "main.h" 2573bb5b4fSJiong Wang #include "xlated_dumper.h" 2671bb428fSJakub Kicinski 27b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 28b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 29b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 30b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 31092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 32b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 33b7d3826cSJohn Fastabend }; 34b7d3826cSJohn Fastabend 35b7d3826cSJohn Fastabend enum bpf_attach_type parse_attach_type(const char *str) 36b7d3826cSJohn Fastabend { 37b7d3826cSJohn Fastabend enum bpf_attach_type type; 38b7d3826cSJohn Fastabend 39b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 40b7d3826cSJohn Fastabend if (attach_type_strings[type] && 41b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 42b7d3826cSJohn Fastabend return type; 43b7d3826cSJohn Fastabend } 44b7d3826cSJohn Fastabend 45b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 46b7d3826cSJohn Fastabend } 47b7d3826cSJohn Fastabend 4871bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 4971bb428fSJakub Kicinski { 5071bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 5171bb428fSJakub Kicinski time_t wallclock_secs; 5271bb428fSJakub Kicinski struct tm load_tm; 5371bb428fSJakub Kicinski 5471bb428fSJakub Kicinski buf[--size] = '\0'; 5571bb428fSJakub Kicinski 5671bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 5771bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 5871bb428fSJakub Kicinski perror("Can't read clocks"); 5971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 6071bb428fSJakub Kicinski return; 6171bb428fSJakub Kicinski } 6271bb428fSJakub Kicinski 6371bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 6407480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 6507480cbcSJakub Kicinski 1000000000; 6607480cbcSJakub Kicinski 6771bb428fSJakub Kicinski 6871bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 6971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 7071bb428fSJakub Kicinski return; 7171bb428fSJakub Kicinski } 7271bb428fSJakub Kicinski 73a3fe1f6fSQuentin Monnet if (json_output) 74a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 75a3fe1f6fSQuentin Monnet else 76a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 7771bb428fSJakub Kicinski } 7871bb428fSJakub Kicinski 7971bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 8071bb428fSJakub Kicinski { 8171bb428fSJakub Kicinski struct bpf_prog_info info = {}; 8271bb428fSJakub Kicinski __u32 len = sizeof(info); 8371bb428fSJakub Kicinski unsigned int id = 0; 8471bb428fSJakub Kicinski int err; 8571bb428fSJakub Kicinski int fd; 8671bb428fSJakub Kicinski 8771bb428fSJakub Kicinski while (true) { 8871bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 8971bb428fSJakub Kicinski if (err) { 909a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 9171bb428fSJakub Kicinski return -1; 9271bb428fSJakub Kicinski } 9371bb428fSJakub Kicinski 9471bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 9571bb428fSJakub Kicinski if (fd < 0) { 969a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 9771bb428fSJakub Kicinski id, strerror(errno)); 9871bb428fSJakub Kicinski return -1; 9971bb428fSJakub Kicinski } 10071bb428fSJakub Kicinski 10171bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 10271bb428fSJakub Kicinski if (err) { 1039a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 10471bb428fSJakub Kicinski id, strerror(errno)); 10571bb428fSJakub Kicinski close(fd); 10671bb428fSJakub Kicinski return -1; 10771bb428fSJakub Kicinski } 10871bb428fSJakub Kicinski 10971bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 11071bb428fSJakub Kicinski return fd; 11171bb428fSJakub Kicinski 11271bb428fSJakub Kicinski close(fd); 11371bb428fSJakub Kicinski } 11471bb428fSJakub Kicinski } 11571bb428fSJakub Kicinski 11671bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 11771bb428fSJakub Kicinski { 11871bb428fSJakub Kicinski int fd; 11971bb428fSJakub Kicinski 12071bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 12171bb428fSJakub Kicinski unsigned int id; 12271bb428fSJakub Kicinski char *endptr; 12371bb428fSJakub Kicinski 12471bb428fSJakub Kicinski NEXT_ARGP(); 12571bb428fSJakub Kicinski 12671bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 12771bb428fSJakub Kicinski if (*endptr) { 1289a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 12971bb428fSJakub Kicinski return -1; 13071bb428fSJakub Kicinski } 13171bb428fSJakub Kicinski NEXT_ARGP(); 13271bb428fSJakub Kicinski 13371bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 13471bb428fSJakub Kicinski if (fd < 0) 1359a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 13671bb428fSJakub Kicinski return fd; 13771bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 13871bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 13971bb428fSJakub Kicinski 14071bb428fSJakub Kicinski NEXT_ARGP(); 14171bb428fSJakub Kicinski 14271bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 14371bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 14471bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1459a5ab8bfSQuentin Monnet p_err("can't parse tag"); 14671bb428fSJakub Kicinski return -1; 14771bb428fSJakub Kicinski } 14871bb428fSJakub Kicinski NEXT_ARGP(); 14971bb428fSJakub Kicinski 15071bb428fSJakub Kicinski return prog_fd_by_tag(tag); 15171bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 15271bb428fSJakub Kicinski char *path; 15371bb428fSJakub Kicinski 15471bb428fSJakub Kicinski NEXT_ARGP(); 15571bb428fSJakub Kicinski 15671bb428fSJakub Kicinski path = **argv; 15771bb428fSJakub Kicinski NEXT_ARGP(); 15871bb428fSJakub Kicinski 15971bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 16071bb428fSJakub Kicinski } 16171bb428fSJakub Kicinski 1629a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 16371bb428fSJakub Kicinski return -1; 16471bb428fSJakub Kicinski } 16571bb428fSJakub Kicinski 16671bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 16771bb428fSJakub Kicinski { 16871bb428fSJakub Kicinski struct bpf_prog_info info = {}; 16971bb428fSJakub Kicinski __u32 len = sizeof(info); 17071bb428fSJakub Kicinski __u32 map_ids[num_maps]; 17171bb428fSJakub Kicinski unsigned int i; 17271bb428fSJakub Kicinski int err; 17371bb428fSJakub Kicinski 17471bb428fSJakub Kicinski info.nr_map_ids = num_maps; 17571bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 17671bb428fSJakub Kicinski 17771bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 17871bb428fSJakub Kicinski if (err || !info.nr_map_ids) 17971bb428fSJakub Kicinski return; 18071bb428fSJakub Kicinski 181743cc665SQuentin Monnet if (json_output) { 182743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 183743cc665SQuentin Monnet jsonw_start_array(json_wtr); 184743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 185743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 186743cc665SQuentin Monnet jsonw_end_array(json_wtr); 187743cc665SQuentin Monnet } else { 18871bb428fSJakub Kicinski printf(" map_ids "); 18971bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 19071bb428fSJakub Kicinski printf("%u%s", map_ids[i], 19171bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 19271bb428fSJakub Kicinski } 19371bb428fSJakub Kicinski } 19471bb428fSJakub Kicinski 195743cc665SQuentin Monnet static void print_prog_json(struct bpf_prog_info *info, int fd) 196743cc665SQuentin Monnet { 197743cc665SQuentin Monnet char *memlock; 198743cc665SQuentin Monnet 199743cc665SQuentin Monnet jsonw_start_object(json_wtr); 200743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 201743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 202743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 203743cc665SQuentin Monnet prog_type_name[info->type]); 20471bb428fSJakub Kicinski else 205743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 20671bb428fSJakub Kicinski 207743cc665SQuentin Monnet if (*info->name) 208743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 20971bb428fSJakub Kicinski 210743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 211743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 212743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 213743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 21471bb428fSJakub Kicinski 2159b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 2169b984a20SJiri Olsa 21752262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 21852262210SJakub Kicinski 219743cc665SQuentin Monnet if (info->load_time) { 22071bb428fSJakub Kicinski char buf[32]; 22171bb428fSJakub Kicinski 222743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 22371bb428fSJakub Kicinski 22471bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 225a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 226a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 227743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 22871bb428fSJakub Kicinski } 22971bb428fSJakub Kicinski 230743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 23171bb428fSJakub Kicinski 232743cc665SQuentin Monnet if (info->jited_prog_len) { 233743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 234743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 235743cc665SQuentin Monnet } else { 236743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 237743cc665SQuentin Monnet } 238743cc665SQuentin Monnet 239743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 240743cc665SQuentin Monnet if (memlock) 241743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 242743cc665SQuentin Monnet free(memlock); 243743cc665SQuentin Monnet 244743cc665SQuentin Monnet if (info->nr_map_ids) 245743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 246743cc665SQuentin Monnet 2474990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 2484990f1f4SPrashant Bhole struct pinned_obj *obj; 2494990f1f4SPrashant Bhole 2504990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 2514990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 2524990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 2534990f1f4SPrashant Bhole if (obj->id == info->id) 2544990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 2554990f1f4SPrashant Bhole } 2564990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 2574990f1f4SPrashant Bhole } 2584990f1f4SPrashant Bhole 259743cc665SQuentin Monnet jsonw_end_object(json_wtr); 260743cc665SQuentin Monnet } 261743cc665SQuentin Monnet 262743cc665SQuentin Monnet static void print_prog_plain(struct bpf_prog_info *info, int fd) 263743cc665SQuentin Monnet { 264743cc665SQuentin Monnet char *memlock; 265743cc665SQuentin Monnet 266743cc665SQuentin Monnet printf("%u: ", info->id); 267743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 268743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 269743cc665SQuentin Monnet else 270743cc665SQuentin Monnet printf("type %u ", info->type); 271743cc665SQuentin Monnet 272743cc665SQuentin Monnet if (*info->name) 273743cc665SQuentin Monnet printf("name %s ", info->name); 274743cc665SQuentin Monnet 275743cc665SQuentin Monnet printf("tag "); 276743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 27752262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 2789b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 279743cc665SQuentin Monnet printf("\n"); 280743cc665SQuentin Monnet 281743cc665SQuentin Monnet if (info->load_time) { 282743cc665SQuentin Monnet char buf[32]; 283743cc665SQuentin Monnet 284743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 285743cc665SQuentin Monnet 286743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 287743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 288743cc665SQuentin Monnet } 289743cc665SQuentin Monnet 290743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 291743cc665SQuentin Monnet 292743cc665SQuentin Monnet if (info->jited_prog_len) 293743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 29471bb428fSJakub Kicinski else 29571bb428fSJakub Kicinski printf(" not jited"); 29671bb428fSJakub Kicinski 29771bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 29871bb428fSJakub Kicinski if (memlock) 29971bb428fSJakub Kicinski printf(" memlock %sB", memlock); 30071bb428fSJakub Kicinski free(memlock); 30171bb428fSJakub Kicinski 302743cc665SQuentin Monnet if (info->nr_map_ids) 303743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 30471bb428fSJakub Kicinski 3054990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3064990f1f4SPrashant Bhole struct pinned_obj *obj; 3074990f1f4SPrashant Bhole 3084990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3094990f1f4SPrashant Bhole if (obj->id == info->id) 310a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 3114990f1f4SPrashant Bhole } 3124990f1f4SPrashant Bhole } 3134990f1f4SPrashant Bhole 31471bb428fSJakub Kicinski printf("\n"); 315743cc665SQuentin Monnet } 316743cc665SQuentin Monnet 317743cc665SQuentin Monnet static int show_prog(int fd) 318743cc665SQuentin Monnet { 319743cc665SQuentin Monnet struct bpf_prog_info info = {}; 320743cc665SQuentin Monnet __u32 len = sizeof(info); 321743cc665SQuentin Monnet int err; 322743cc665SQuentin Monnet 323743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 324743cc665SQuentin Monnet if (err) { 3259a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 326743cc665SQuentin Monnet return -1; 327743cc665SQuentin Monnet } 328743cc665SQuentin Monnet 329743cc665SQuentin Monnet if (json_output) 330743cc665SQuentin Monnet print_prog_json(&info, fd); 331743cc665SQuentin Monnet else 332743cc665SQuentin Monnet print_prog_plain(&info, fd); 33371bb428fSJakub Kicinski 33471bb428fSJakub Kicinski return 0; 33571bb428fSJakub Kicinski } 33671bb428fSJakub Kicinski 33771bb428fSJakub Kicinski static int do_show(int argc, char **argv) 338743cc665SQuentin Monnet { 339743cc665SQuentin Monnet __u32 id = 0; 34071bb428fSJakub Kicinski int err; 34171bb428fSJakub Kicinski int fd; 34271bb428fSJakub Kicinski 343c541b734SPrashant Bhole if (show_pinned) 3444990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 3454990f1f4SPrashant Bhole 34671bb428fSJakub Kicinski if (argc == 2) { 34771bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 34871bb428fSJakub Kicinski if (fd < 0) 34971bb428fSJakub Kicinski return -1; 35071bb428fSJakub Kicinski 35171bb428fSJakub Kicinski return show_prog(fd); 35271bb428fSJakub Kicinski } 35371bb428fSJakub Kicinski 35471bb428fSJakub Kicinski if (argc) 35571bb428fSJakub Kicinski return BAD_ARG(); 35671bb428fSJakub Kicinski 357743cc665SQuentin Monnet if (json_output) 358743cc665SQuentin Monnet jsonw_start_array(json_wtr); 35971bb428fSJakub Kicinski while (true) { 36071bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 36171bb428fSJakub Kicinski if (err) { 3621739c26dSQuentin Monnet if (errno == ENOENT) { 3631739c26dSQuentin Monnet err = 0; 36471bb428fSJakub Kicinski break; 3651739c26dSQuentin Monnet } 3669a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 3679a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 368743cc665SQuentin Monnet err = -1; 369743cc665SQuentin Monnet break; 37071bb428fSJakub Kicinski } 37171bb428fSJakub Kicinski 37271bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 37371bb428fSJakub Kicinski if (fd < 0) { 3748207c6ddSJakub Kicinski if (errno == ENOENT) 3758207c6ddSJakub Kicinski continue; 3769a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 37771bb428fSJakub Kicinski id, strerror(errno)); 378743cc665SQuentin Monnet err = -1; 379743cc665SQuentin Monnet break; 38071bb428fSJakub Kicinski } 38171bb428fSJakub Kicinski 38271bb428fSJakub Kicinski err = show_prog(fd); 38371bb428fSJakub Kicinski close(fd); 38471bb428fSJakub Kicinski if (err) 385743cc665SQuentin Monnet break; 38671bb428fSJakub Kicinski } 38771bb428fSJakub Kicinski 388743cc665SQuentin Monnet if (json_output) 389743cc665SQuentin Monnet jsonw_end_array(json_wtr); 390743cc665SQuentin Monnet 391743cc665SQuentin Monnet return err; 39271bb428fSJakub Kicinski } 39371bb428fSJakub Kicinski 39471bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 39571bb428fSJakub Kicinski { 396b053b439SMartin KaFai Lau unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size; 397b053b439SMartin KaFai Lau void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL; 398cfc54241SYonghong Song unsigned int nr_finfo, nr_linfo = 0, nr_jited_linfo = 0; 399b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 400f84192eeSSandipan Das unsigned long *func_ksyms = NULL; 40171bb428fSJakub Kicinski struct bpf_prog_info info = {}; 402f7f62c71SSandipan Das unsigned int *func_lens = NULL; 4033ddeac67SJakub Kicinski const char *disasm_opt = NULL; 404f84192eeSSandipan Das unsigned int nr_func_ksyms; 405f7f62c71SSandipan Das unsigned int nr_func_lens; 4067105e828SDaniel Borkmann struct dump_data dd = {}; 40771bb428fSJakub Kicinski __u32 len = sizeof(info); 408254471e5SYonghong Song struct btf *btf = NULL; 40971bb428fSJakub Kicinski unsigned int buf_size; 41071bb428fSJakub Kicinski char *filepath = NULL; 41171bb428fSJakub Kicinski bool opcodes = false; 412b6c1cedbSJiong Wang bool visual = false; 413254471e5SYonghong Song char func_sig[1024]; 41471bb428fSJakub Kicinski unsigned char *buf; 415b053b439SMartin KaFai Lau bool linum = false; 41671bb428fSJakub Kicinski __u32 *member_len; 41771bb428fSJakub Kicinski __u64 *member_ptr; 41871bb428fSJakub Kicinski ssize_t n; 41971bb428fSJakub Kicinski int err; 42071bb428fSJakub Kicinski int fd; 42171bb428fSJakub Kicinski 42271bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 42329a9c10eSStanislav Fomichev if (disasm_init()) 42429a9c10eSStanislav Fomichev return -1; 42529a9c10eSStanislav Fomichev 42671bb428fSJakub Kicinski member_len = &info.jited_prog_len; 42771bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 42871bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 42971bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 43071bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 43171bb428fSJakub Kicinski } else { 4329a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 43371bb428fSJakub Kicinski return -1; 43471bb428fSJakub Kicinski } 43571bb428fSJakub Kicinski NEXT_ARG(); 43671bb428fSJakub Kicinski 43771bb428fSJakub Kicinski if (argc < 2) 43871bb428fSJakub Kicinski usage(); 43971bb428fSJakub Kicinski 44071bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 44171bb428fSJakub Kicinski if (fd < 0) 44271bb428fSJakub Kicinski return -1; 44371bb428fSJakub Kicinski 44471bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 44571bb428fSJakub Kicinski NEXT_ARG(); 44671bb428fSJakub Kicinski if (!argc) { 4479a5ab8bfSQuentin Monnet p_err("expected file path"); 44871bb428fSJakub Kicinski return -1; 44971bb428fSJakub Kicinski } 45071bb428fSJakub Kicinski 45171bb428fSJakub Kicinski filepath = *argv; 45271bb428fSJakub Kicinski NEXT_ARG(); 45371bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 45471bb428fSJakub Kicinski opcodes = true; 45571bb428fSJakub Kicinski NEXT_ARG(); 456b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 457b6c1cedbSJiong Wang visual = true; 458b6c1cedbSJiong Wang NEXT_ARG(); 459b053b439SMartin KaFai Lau } else if (is_prefix(*argv, "linum")) { 460b053b439SMartin KaFai Lau linum = true; 461b053b439SMartin KaFai Lau NEXT_ARG(); 46271bb428fSJakub Kicinski } 46371bb428fSJakub Kicinski 46471bb428fSJakub Kicinski if (argc) { 46571bb428fSJakub Kicinski usage(); 46671bb428fSJakub Kicinski return -1; 46771bb428fSJakub Kicinski } 46871bb428fSJakub Kicinski 46971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 47071bb428fSJakub Kicinski if (err) { 4719a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 47271bb428fSJakub Kicinski return -1; 47371bb428fSJakub Kicinski } 47471bb428fSJakub Kicinski 47571bb428fSJakub Kicinski if (!*member_len) { 4769a5ab8bfSQuentin Monnet p_info("no instructions returned"); 47771bb428fSJakub Kicinski close(fd); 47871bb428fSJakub Kicinski return 0; 47971bb428fSJakub Kicinski } 48071bb428fSJakub Kicinski 48171bb428fSJakub Kicinski buf_size = *member_len; 48271bb428fSJakub Kicinski 48371bb428fSJakub Kicinski buf = malloc(buf_size); 48471bb428fSJakub Kicinski if (!buf) { 4859a5ab8bfSQuentin Monnet p_err("mem alloc failed"); 48671bb428fSJakub Kicinski close(fd); 48771bb428fSJakub Kicinski return -1; 48871bb428fSJakub Kicinski } 48971bb428fSJakub Kicinski 490f84192eeSSandipan Das nr_func_ksyms = info.nr_jited_ksyms; 491f84192eeSSandipan Das if (nr_func_ksyms) { 492f84192eeSSandipan Das func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 493f84192eeSSandipan Das if (!func_ksyms) { 494f84192eeSSandipan Das p_err("mem alloc failed"); 495f84192eeSSandipan Das close(fd); 496f84192eeSSandipan Das goto err_free; 497f84192eeSSandipan Das } 498f84192eeSSandipan Das } 499f84192eeSSandipan Das 500f7f62c71SSandipan Das nr_func_lens = info.nr_jited_func_lens; 501f7f62c71SSandipan Das if (nr_func_lens) { 502f7f62c71SSandipan Das func_lens = malloc(nr_func_lens * sizeof(__u32)); 503f7f62c71SSandipan Das if (!func_lens) { 504f7f62c71SSandipan Das p_err("mem alloc failed"); 505f7f62c71SSandipan Das close(fd); 506f7f62c71SSandipan Das goto err_free; 507f7f62c71SSandipan Das } 508f7f62c71SSandipan Das } 509f7f62c71SSandipan Das 510cfc54241SYonghong Song nr_finfo = info.nr_func_info; 511254471e5SYonghong Song finfo_rec_size = info.func_info_rec_size; 512cfc54241SYonghong Song if (nr_finfo && finfo_rec_size) { 513cfc54241SYonghong Song func_info = malloc(nr_finfo * finfo_rec_size); 514254471e5SYonghong Song if (!func_info) { 515254471e5SYonghong Song p_err("mem alloc failed"); 516254471e5SYonghong Song close(fd); 517254471e5SYonghong Song goto err_free; 518254471e5SYonghong Song } 519254471e5SYonghong Song } 520254471e5SYonghong Song 521b053b439SMartin KaFai Lau linfo_rec_size = info.line_info_rec_size; 522cfc54241SYonghong Song if (info.nr_line_info && linfo_rec_size && info.btf_id) { 523cfc54241SYonghong Song nr_linfo = info.nr_line_info; 524cfc54241SYonghong Song linfo = malloc(nr_linfo * linfo_rec_size); 525b053b439SMartin KaFai Lau if (!linfo) { 526b053b439SMartin KaFai Lau p_err("mem alloc failed"); 527b053b439SMartin KaFai Lau close(fd); 528b053b439SMartin KaFai Lau goto err_free; 529b053b439SMartin KaFai Lau } 530b053b439SMartin KaFai Lau } 531b053b439SMartin KaFai Lau 532b053b439SMartin KaFai Lau jited_linfo_rec_size = info.jited_line_info_rec_size; 533cfc54241SYonghong Song if (info.nr_jited_line_info && 534b053b439SMartin KaFai Lau jited_linfo_rec_size && 535b053b439SMartin KaFai Lau info.nr_jited_ksyms && 536b053b439SMartin KaFai Lau info.nr_jited_func_lens && 537b053b439SMartin KaFai Lau info.btf_id) { 538cfc54241SYonghong Song nr_jited_linfo = info.nr_jited_line_info; 539cfc54241SYonghong Song jited_linfo = malloc(nr_jited_linfo * jited_linfo_rec_size); 540b053b439SMartin KaFai Lau if (!jited_linfo) { 541b053b439SMartin KaFai Lau p_err("mem alloc failed"); 542b053b439SMartin KaFai Lau close(fd); 543b053b439SMartin KaFai Lau goto err_free; 544b053b439SMartin KaFai Lau } 545b053b439SMartin KaFai Lau } 546b053b439SMartin KaFai Lau 54771bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 54871bb428fSJakub Kicinski 54971bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 55071bb428fSJakub Kicinski *member_len = buf_size; 551f84192eeSSandipan Das info.jited_ksyms = ptr_to_u64(func_ksyms); 552f84192eeSSandipan Das info.nr_jited_ksyms = nr_func_ksyms; 553f7f62c71SSandipan Das info.jited_func_lens = ptr_to_u64(func_lens); 554f7f62c71SSandipan Das info.nr_jited_func_lens = nr_func_lens; 555cfc54241SYonghong Song info.nr_func_info = nr_finfo; 556254471e5SYonghong Song info.func_info_rec_size = finfo_rec_size; 557254471e5SYonghong Song info.func_info = ptr_to_u64(func_info); 558cfc54241SYonghong Song info.nr_line_info = nr_linfo; 559b053b439SMartin KaFai Lau info.line_info_rec_size = linfo_rec_size; 560b053b439SMartin KaFai Lau info.line_info = ptr_to_u64(linfo); 561cfc54241SYonghong Song info.nr_jited_line_info = nr_jited_linfo; 562b053b439SMartin KaFai Lau info.jited_line_info_rec_size = jited_linfo_rec_size; 563b053b439SMartin KaFai Lau info.jited_line_info = ptr_to_u64(jited_linfo); 564b053b439SMartin KaFai Lau 56571bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 56671bb428fSJakub Kicinski close(fd); 56771bb428fSJakub Kicinski if (err) { 5689a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 56971bb428fSJakub Kicinski goto err_free; 57071bb428fSJakub Kicinski } 57171bb428fSJakub Kicinski 57271bb428fSJakub Kicinski if (*member_len > buf_size) { 5739a5ab8bfSQuentin Monnet p_err("too many instructions returned"); 57471bb428fSJakub Kicinski goto err_free; 57571bb428fSJakub Kicinski } 57671bb428fSJakub Kicinski 577f84192eeSSandipan Das if (info.nr_jited_ksyms > nr_func_ksyms) { 578f84192eeSSandipan Das p_err("too many addresses returned"); 579f84192eeSSandipan Das goto err_free; 580f84192eeSSandipan Das } 581f84192eeSSandipan Das 582f7f62c71SSandipan Das if (info.nr_jited_func_lens > nr_func_lens) { 583f7f62c71SSandipan Das p_err("too many values returned"); 584f7f62c71SSandipan Das goto err_free; 585f7f62c71SSandipan Das } 586f7f62c71SSandipan Das 587cfc54241SYonghong Song if (info.nr_func_info != nr_finfo) { 588cfc54241SYonghong Song p_err("incorrect nr_func_info %d vs. expected %d", 589cfc54241SYonghong Song info.nr_func_info, nr_finfo); 590254471e5SYonghong Song goto err_free; 591254471e5SYonghong Song } 592254471e5SYonghong Song 593254471e5SYonghong Song if (info.func_info_rec_size != finfo_rec_size) { 594254471e5SYonghong Song p_err("incorrect func_info_rec_size %d vs. expected %d", 595254471e5SYonghong Song info.func_info_rec_size, finfo_rec_size); 596254471e5SYonghong Song goto err_free; 597254471e5SYonghong Song } 598254471e5SYonghong Song 59984ecc1f9SMartin KaFai Lau if (func_info && !info.func_info) { 60084ecc1f9SMartin KaFai Lau /* kernel.kptr_restrict is set. No func_info available. */ 60184ecc1f9SMartin KaFai Lau free(func_info); 60284ecc1f9SMartin KaFai Lau func_info = NULL; 603cfc54241SYonghong Song nr_finfo = 0; 60484ecc1f9SMartin KaFai Lau } 60584ecc1f9SMartin KaFai Lau 606cfc54241SYonghong Song if (linfo && info.nr_line_info != nr_linfo) { 607cfc54241SYonghong Song p_err("incorrect nr_line_info %u vs. expected %u", 608cfc54241SYonghong Song info.nr_line_info, nr_linfo); 609b053b439SMartin KaFai Lau goto err_free; 610b053b439SMartin KaFai Lau } 611b053b439SMartin KaFai Lau 612b053b439SMartin KaFai Lau if (info.line_info_rec_size != linfo_rec_size) { 613b053b439SMartin KaFai Lau p_err("incorrect line_info_rec_size %u vs. expected %u", 614b053b439SMartin KaFai Lau info.line_info_rec_size, linfo_rec_size); 615b053b439SMartin KaFai Lau goto err_free; 616b053b439SMartin KaFai Lau } 617b053b439SMartin KaFai Lau 618cfc54241SYonghong Song if (jited_linfo && info.nr_jited_line_info != nr_jited_linfo) { 619cfc54241SYonghong Song p_err("incorrect nr_jited_line_info %u vs. expected %u", 620cfc54241SYonghong Song info.nr_jited_line_info, nr_jited_linfo); 621b053b439SMartin KaFai Lau goto err_free; 622b053b439SMartin KaFai Lau } 623b053b439SMartin KaFai Lau 624b053b439SMartin KaFai Lau if (info.jited_line_info_rec_size != jited_linfo_rec_size) { 625b053b439SMartin KaFai Lau p_err("incorrect jited_line_info_rec_size %u vs. expected %u", 626b053b439SMartin KaFai Lau info.jited_line_info_rec_size, jited_linfo_rec_size); 627b053b439SMartin KaFai Lau goto err_free; 628b053b439SMartin KaFai Lau } 629b053b439SMartin KaFai Lau 6307105e828SDaniel Borkmann if ((member_len == &info.jited_prog_len && 6317105e828SDaniel Borkmann info.jited_prog_insns == 0) || 6327105e828SDaniel Borkmann (member_len == &info.xlated_prog_len && 6337105e828SDaniel Borkmann info.xlated_prog_insns == 0)) { 6347105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 6357105e828SDaniel Borkmann goto err_free; 6367105e828SDaniel Borkmann } 6377105e828SDaniel Borkmann 6381d2f44caSMartin KaFai Lau if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) { 639254471e5SYonghong Song p_err("failed to get btf"); 640254471e5SYonghong Song goto err_free; 641254471e5SYonghong Song } 642254471e5SYonghong Song 643cfc54241SYonghong Song if (nr_linfo) { 644b053b439SMartin KaFai Lau prog_linfo = bpf_prog_linfo__new(&info); 645b053b439SMartin KaFai Lau if (!prog_linfo) 64610a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 647b053b439SMartin KaFai Lau } 648b053b439SMartin KaFai Lau 64971bb428fSJakub Kicinski if (filepath) { 65071bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 65171bb428fSJakub Kicinski if (fd < 0) { 6529a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 65371bb428fSJakub Kicinski strerror(errno)); 65471bb428fSJakub Kicinski goto err_free; 65571bb428fSJakub Kicinski } 65671bb428fSJakub Kicinski 65771bb428fSJakub Kicinski n = write(fd, buf, *member_len); 65871bb428fSJakub Kicinski close(fd); 65971bb428fSJakub Kicinski if (n != *member_len) { 6609a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 66171bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 66271bb428fSJakub Kicinski goto err_free; 66371bb428fSJakub Kicinski } 66452c84d36SQuentin Monnet 66552c84d36SQuentin Monnet if (json_output) 66652c84d36SQuentin Monnet jsonw_null(json_wtr); 6673197239dSJiong Wang } else if (member_len == &info.jited_prog_len) { 668e6593596SJiong Wang const char *name = NULL; 669e6593596SJiong Wang 670e6593596SJiong Wang if (info.ifindex) { 6713ddeac67SJakub Kicinski name = ifindex_to_bfd_params(info.ifindex, 672e6593596SJiong Wang info.netns_dev, 6733ddeac67SJakub Kicinski info.netns_ino, 6743ddeac67SJakub Kicinski &disasm_opt); 675e6593596SJiong Wang if (!name) 676e6593596SJiong Wang goto err_free; 677e6593596SJiong Wang } 678e6593596SJiong Wang 679f7f62c71SSandipan Das if (info.nr_jited_func_lens && info.jited_func_lens) { 680f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 681254471e5SYonghong Song struct bpf_func_info *record; 682f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 683f7f62c71SSandipan Das unsigned char *img = buf; 684f7f62c71SSandipan Das __u64 *ksyms = NULL; 685f7f62c71SSandipan Das __u32 *lens; 686f7f62c71SSandipan Das __u32 i; 687f7f62c71SSandipan Das 688f7f62c71SSandipan Das if (info.nr_jited_ksyms) { 689f7f62c71SSandipan Das kernel_syms_load(&dd); 690f7f62c71SSandipan Das ksyms = (__u64 *) info.jited_ksyms; 691f7f62c71SSandipan Das } 692f7f62c71SSandipan Das 693f7f62c71SSandipan Das if (json_output) 694f7f62c71SSandipan Das jsonw_start_array(json_wtr); 695f7f62c71SSandipan Das 696f7f62c71SSandipan Das lens = (__u32 *) info.jited_func_lens; 697f7f62c71SSandipan Das for (i = 0; i < info.nr_jited_func_lens; i++) { 698f7f62c71SSandipan Das if (ksyms) { 699f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 700f7f62c71SSandipan Das if (sym) 701f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 702f7f62c71SSandipan Das else 703f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 704f7f62c71SSandipan Das } else { 705f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 706f7f62c71SSandipan Das } 707f7f62c71SSandipan Das 708254471e5SYonghong Song if (func_info) { 709254471e5SYonghong Song record = func_info + i * finfo_rec_size; 710254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 711254471e5SYonghong Song func_sig, 712254471e5SYonghong Song sizeof(func_sig)); 713254471e5SYonghong Song } 714254471e5SYonghong Song 715f7f62c71SSandipan Das if (json_output) { 716f7f62c71SSandipan Das jsonw_start_object(json_wtr); 717254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 718254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 719254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 720254471e5SYonghong Song } 721f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 722f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 723f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 724f7f62c71SSandipan Das } else { 725254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 726254471e5SYonghong Song printf("%s:\n", func_sig); 727f7f62c71SSandipan Das printf("%s:\n", sym_name); 728f7f62c71SSandipan Das } 729f7f62c71SSandipan Das 730b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 731b053b439SMartin KaFai Lau name, disasm_opt, btf, 732b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 733b053b439SMartin KaFai Lau linum); 734b053b439SMartin KaFai Lau 735f7f62c71SSandipan Das img += lens[i]; 736f7f62c71SSandipan Das 737f7f62c71SSandipan Das if (json_output) 738f7f62c71SSandipan Das jsonw_end_object(json_wtr); 739f7f62c71SSandipan Das else 740f7f62c71SSandipan Das printf("\n"); 741f7f62c71SSandipan Das } 742f7f62c71SSandipan Das 743f7f62c71SSandipan Das if (json_output) 744f7f62c71SSandipan Das jsonw_end_array(json_wtr); 745f7f62c71SSandipan Das } else { 7463ddeac67SJakub Kicinski disasm_print_insn(buf, *member_len, opcodes, name, 747b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 748f7f62c71SSandipan Das } 749b6c1cedbSJiong Wang } else if (visual) { 750b6c1cedbSJiong Wang if (json_output) 751b6c1cedbSJiong Wang jsonw_null(json_wtr); 752b6c1cedbSJiong Wang else 753b6c1cedbSJiong Wang dump_xlated_cfg(buf, *member_len); 7547105e828SDaniel Borkmann } else { 7557105e828SDaniel Borkmann kernel_syms_load(&dd); 756f84192eeSSandipan Das dd.nr_jited_ksyms = info.nr_jited_ksyms; 757f84192eeSSandipan Das dd.jited_ksyms = (__u64 *) info.jited_ksyms; 758254471e5SYonghong Song dd.btf = btf; 759254471e5SYonghong Song dd.func_info = func_info; 760254471e5SYonghong Song dd.finfo_rec_size = finfo_rec_size; 761b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 762f84192eeSSandipan Das 763f05e2c32SQuentin Monnet if (json_output) 764b053b439SMartin KaFai Lau dump_xlated_json(&dd, buf, *member_len, opcodes, 765b053b439SMartin KaFai Lau linum); 766f05e2c32SQuentin Monnet else 767b053b439SMartin KaFai Lau dump_xlated_plain(&dd, buf, *member_len, opcodes, 768b053b439SMartin KaFai Lau linum); 7697105e828SDaniel Borkmann kernel_syms_destroy(&dd); 7707105e828SDaniel Borkmann } 77171bb428fSJakub Kicinski 77271bb428fSJakub Kicinski free(buf); 773f84192eeSSandipan Das free(func_ksyms); 774f7f62c71SSandipan Das free(func_lens); 775254471e5SYonghong Song free(func_info); 776b053b439SMartin KaFai Lau free(linfo); 777b053b439SMartin KaFai Lau free(jited_linfo); 778b053b439SMartin KaFai Lau bpf_prog_linfo__free(prog_linfo); 77971bb428fSJakub Kicinski return 0; 78071bb428fSJakub Kicinski 78171bb428fSJakub Kicinski err_free: 78271bb428fSJakub Kicinski free(buf); 783f84192eeSSandipan Das free(func_ksyms); 784f7f62c71SSandipan Das free(func_lens); 785254471e5SYonghong Song free(func_info); 786b053b439SMartin KaFai Lau free(linfo); 787b053b439SMartin KaFai Lau free(jited_linfo); 788b053b439SMartin KaFai Lau bpf_prog_linfo__free(prog_linfo); 78971bb428fSJakub Kicinski return -1; 79071bb428fSJakub Kicinski } 79171bb428fSJakub Kicinski 79271bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 79371bb428fSJakub Kicinski { 794004b45c0SQuentin Monnet int err; 795004b45c0SQuentin Monnet 796004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 797004b45c0SQuentin Monnet if (!err && json_output) 798004b45c0SQuentin Monnet jsonw_null(json_wtr); 799004b45c0SQuentin Monnet return err; 80071bb428fSJakub Kicinski } 80171bb428fSJakub Kicinski 8023ff5a4dcSJakub Kicinski struct map_replace { 8033ff5a4dcSJakub Kicinski int idx; 8043ff5a4dcSJakub Kicinski int fd; 8053ff5a4dcSJakub Kicinski char *name; 8063ff5a4dcSJakub Kicinski }; 8073ff5a4dcSJakub Kicinski 8083ff5a4dcSJakub Kicinski int map_replace_compar(const void *p1, const void *p2) 8093ff5a4dcSJakub Kicinski { 8103ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 8113ff5a4dcSJakub Kicinski 8123ff5a4dcSJakub Kicinski return a->idx - b->idx; 8133ff5a4dcSJakub Kicinski } 8143ff5a4dcSJakub Kicinski 815092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 816092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 817092f0892SStanislav Fomichev int *mapfd) 818092f0892SStanislav Fomichev { 819092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 820092f0892SStanislav Fomichev return -EINVAL; 821092f0892SStanislav Fomichev 822092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 823092f0892SStanislav Fomichev if (*progfd < 0) 824092f0892SStanislav Fomichev return *progfd; 825092f0892SStanislav Fomichev 826092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 827092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 828092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 829092f0892SStanislav Fomichev return -EINVAL; 830092f0892SStanislav Fomichev } 831092f0892SStanislav Fomichev 832092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 833092f0892SStanislav Fomichev *mapfd = -1; 834092f0892SStanislav Fomichev return 0; 835092f0892SStanislav Fomichev } 836092f0892SStanislav Fomichev 837092f0892SStanislav Fomichev NEXT_ARG(); 838092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 839092f0892SStanislav Fomichev return -EINVAL; 840092f0892SStanislav Fomichev 841092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 842092f0892SStanislav Fomichev if (*mapfd < 0) 843092f0892SStanislav Fomichev return *mapfd; 844092f0892SStanislav Fomichev 845092f0892SStanislav Fomichev return 0; 846092f0892SStanislav Fomichev } 847092f0892SStanislav Fomichev 848b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 849b7d3826cSJohn Fastabend { 850b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 851092f0892SStanislav Fomichev int err, progfd; 852092f0892SStanislav Fomichev int mapfd; 853b7d3826cSJohn Fastabend 854092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 855092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 856092f0892SStanislav Fomichev if (err) 857092f0892SStanislav Fomichev return err; 858b7d3826cSJohn Fastabend 859b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 860b7d3826cSJohn Fastabend if (err) { 861b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 862b7d3826cSJohn Fastabend return -EINVAL; 863b7d3826cSJohn Fastabend } 864b7d3826cSJohn Fastabend 865b7d3826cSJohn Fastabend if (json_output) 866b7d3826cSJohn Fastabend jsonw_null(json_wtr); 867b7d3826cSJohn Fastabend return 0; 868b7d3826cSJohn Fastabend } 869b7d3826cSJohn Fastabend 870b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 871b7d3826cSJohn Fastabend { 872b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 873092f0892SStanislav Fomichev int err, progfd; 874092f0892SStanislav Fomichev int mapfd; 875b7d3826cSJohn Fastabend 876092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 877092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 878092f0892SStanislav Fomichev if (err) 879092f0892SStanislav Fomichev return err; 880b7d3826cSJohn Fastabend 881b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 882b7d3826cSJohn Fastabend if (err) { 883b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 884b7d3826cSJohn Fastabend return -EINVAL; 885b7d3826cSJohn Fastabend } 886b7d3826cSJohn Fastabend 887b7d3826cSJohn Fastabend if (json_output) 888b7d3826cSJohn Fastabend jsonw_null(json_wtr); 889b7d3826cSJohn Fastabend return 0; 890b7d3826cSJohn Fastabend } 89177380998SStanislav Fomichev 89277380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 89349a086c2SRoman Gushchin { 894c8406848SJakub Kicinski enum bpf_attach_type expected_attach_type; 895c8406848SJakub Kicinski struct bpf_object_open_attr attr = { 896ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 897ba6dd679SJakub Kicinski }; 8983ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 89977380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 9003ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 9013767a94bSStanislav Fomichev const char *pinmaps = NULL; 90249a086c2SRoman Gushchin struct bpf_object *obj; 903c8406848SJakub Kicinski struct bpf_map *map; 904c8406848SJakub Kicinski const char *pinfile; 9053ff5a4dcSJakub Kicinski unsigned int i, j; 906c8406848SJakub Kicinski __u32 ifindex = 0; 9073ff5a4dcSJakub Kicinski int idx, err; 90849a086c2SRoman Gushchin 9098d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 9108d1fc3deSJakub Kicinski return -1; 911c8406848SJakub Kicinski attr.file = GET_ARG(); 9128d1fc3deSJakub Kicinski pinfile = GET_ARG(); 91349a086c2SRoman Gushchin 914ba6dd679SJakub Kicinski while (argc) { 91549f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 91649f2cba3SJakub Kicinski char *type; 91749f2cba3SJakub Kicinski 91849f2cba3SJakub Kicinski NEXT_ARG(); 91949f2cba3SJakub Kicinski 92049f2cba3SJakub Kicinski if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 92149f2cba3SJakub Kicinski p_err("program type already specified"); 9223ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 92349f2cba3SJakub Kicinski } 92449f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 9253ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 92649f2cba3SJakub Kicinski 92749f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 92849f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 92949f2cba3SJakub Kicinski if (!type) { 93049f2cba3SJakub Kicinski p_err("mem alloc failed"); 9313ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 93249f2cba3SJakub Kicinski } 93349f2cba3SJakub Kicinski *type = 0; 93449f2cba3SJakub Kicinski strcat(type, *argv); 93549f2cba3SJakub Kicinski strcat(type, "/"); 93649f2cba3SJakub Kicinski 93749f2cba3SJakub Kicinski err = libbpf_prog_type_by_name(type, &attr.prog_type, 938c8406848SJakub Kicinski &expected_attach_type); 93949f2cba3SJakub Kicinski free(type); 94049f2cba3SJakub Kicinski if (err < 0) { 94149f2cba3SJakub Kicinski p_err("unknown program type '%s'", *argv); 9423ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 94349f2cba3SJakub Kicinski } 94449f2cba3SJakub Kicinski NEXT_ARG(); 9453ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 946dde7011aSJakub Kicinski void *new_map_replace; 9473ff5a4dcSJakub Kicinski char *endptr, *name; 9483ff5a4dcSJakub Kicinski int fd; 9493ff5a4dcSJakub Kicinski 9503ff5a4dcSJakub Kicinski NEXT_ARG(); 9513ff5a4dcSJakub Kicinski 9523ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 9533ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9543ff5a4dcSJakub Kicinski 9553ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 9563ff5a4dcSJakub Kicinski NEXT_ARG(); 9573ff5a4dcSJakub Kicinski 9583ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 9593ff5a4dcSJakub Kicinski if (*endptr) { 9603ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 9613ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9623ff5a4dcSJakub Kicinski } 9633ff5a4dcSJakub Kicinski name = NULL; 9643ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 9653ff5a4dcSJakub Kicinski NEXT_ARG(); 9663ff5a4dcSJakub Kicinski 9673ff5a4dcSJakub Kicinski name = *argv; 9683ff5a4dcSJakub Kicinski idx = -1; 9693ff5a4dcSJakub Kicinski } else { 9703ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 9713ff5a4dcSJakub Kicinski *argv); 9723ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9733ff5a4dcSJakub Kicinski } 9743ff5a4dcSJakub Kicinski NEXT_ARG(); 9753ff5a4dcSJakub Kicinski 9763ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 9773ff5a4dcSJakub Kicinski if (fd < 0) 9783ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9793ff5a4dcSJakub Kicinski 980dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 981dde7011aSJakub Kicinski old_map_fds + 1, 9823ff5a4dcSJakub Kicinski sizeof(*map_replace)); 983dde7011aSJakub Kicinski if (!new_map_replace) { 9843ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 9853ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9863ff5a4dcSJakub Kicinski } 987dde7011aSJakub Kicinski map_replace = new_map_replace; 988dde7011aSJakub Kicinski 9893ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 9903ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 9913ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 9923ff5a4dcSJakub Kicinski old_map_fds++; 99349f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 994ba6dd679SJakub Kicinski NEXT_ARG(); 995ba6dd679SJakub Kicinski 996c8406848SJakub Kicinski if (ifindex) { 997ba6dd679SJakub Kicinski p_err("offload device already specified"); 9983ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 999ba6dd679SJakub Kicinski } 1000ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 10013ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1002ba6dd679SJakub Kicinski 1003c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1004c8406848SJakub Kicinski if (!ifindex) { 1005ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1006ba6dd679SJakub Kicinski *argv, strerror(errno)); 10073ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1008ba6dd679SJakub Kicinski } 1009ba6dd679SJakub Kicinski NEXT_ARG(); 10103767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 10113767a94bSStanislav Fomichev NEXT_ARG(); 10123767a94bSStanislav Fomichev 10133767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 10143767a94bSStanislav Fomichev goto err_free_reuse_maps; 10153767a94bSStanislav Fomichev 10163767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1017ba6dd679SJakub Kicinski } else { 10183ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1019ba6dd679SJakub Kicinski *argv); 10203ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1021ba6dd679SJakub Kicinski } 1022ba6dd679SJakub Kicinski } 1023ba6dd679SJakub Kicinski 1024c034a177SJohn Fastabend obj = __bpf_object__open_xattr(&attr, bpf_flags); 1025c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 1026c8406848SJakub Kicinski p_err("failed to open object file"); 10273ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 102849a086c2SRoman Gushchin } 102949a086c2SRoman Gushchin 103077380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 103177380998SStanislav Fomichev enum bpf_prog_type prog_type = attr.prog_type; 1032c8406848SJakub Kicinski 1033c8406848SJakub Kicinski if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 103477380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1035c8406848SJakub Kicinski 103677380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 1037c8406848SJakub Kicinski &expected_attach_type); 1038c8406848SJakub Kicinski if (err < 0) { 1039c8406848SJakub Kicinski p_err("failed to guess program type based on section name %s\n", 1040c8406848SJakub Kicinski sec_name); 1041c8406848SJakub Kicinski goto err_close_obj; 1042c8406848SJakub Kicinski } 1043c8406848SJakub Kicinski } 104477380998SStanislav Fomichev 104577380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 104677380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 104777380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 104877380998SStanislav Fomichev } 1049c8406848SJakub Kicinski 10503ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 10513ff5a4dcSJakub Kicinski map_replace_compar); 10523ff5a4dcSJakub Kicinski 10533ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 10543ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 10553ff5a4dcSJakub Kicinski */ 10563ff5a4dcSJakub Kicinski j = 0; 10573ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 10583ff5a4dcSJakub Kicinski i = 0; 10593ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 10603ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 10613ff5a4dcSJakub Kicinski map_replace[j].idx = i; 10623ff5a4dcSJakub Kicinski break; 10633ff5a4dcSJakub Kicinski } 10643ff5a4dcSJakub Kicinski i++; 10653ff5a4dcSJakub Kicinski } 10663ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 10673ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 10683ff5a4dcSJakub Kicinski goto err_close_obj; 10693ff5a4dcSJakub Kicinski } 10703ff5a4dcSJakub Kicinski j++; 10713ff5a4dcSJakub Kicinski } 10723ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 10733ff5a4dcSJakub Kicinski if (j) 10743ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 10753ff5a4dcSJakub Kicinski map_replace_compar); 10763ff5a4dcSJakub Kicinski 10773ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 10783ff5a4dcSJakub Kicinski j = 0; 10793ff5a4dcSJakub Kicinski idx = 0; 10803ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 1081c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1082c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1083c8406848SJakub Kicinski 10843ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 10853ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 10863ff5a4dcSJakub Kicinski if (err) { 10873ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 10883ff5a4dcSJakub Kicinski goto err_close_obj; 10893ff5a4dcSJakub Kicinski } 10903ff5a4dcSJakub Kicinski 10913ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 10923ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 10933ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 10943ff5a4dcSJakub Kicinski idx); 10953ff5a4dcSJakub Kicinski goto err_close_obj; 10963ff5a4dcSJakub Kicinski } 10973ff5a4dcSJakub Kicinski } 10983ff5a4dcSJakub Kicinski 10993ff5a4dcSJakub Kicinski idx++; 11003ff5a4dcSJakub Kicinski } 11013ff5a4dcSJakub Kicinski if (j < old_map_fds) { 11023ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 11033ff5a4dcSJakub Kicinski goto err_close_obj; 11043ff5a4dcSJakub Kicinski } 11053ff5a4dcSJakub Kicinski 11068302b9bdSQuentin Monnet set_max_rlimit(); 11078302b9bdSQuentin Monnet 1108c8406848SJakub Kicinski err = bpf_object__load(obj); 1109c8406848SJakub Kicinski if (err) { 1110c8406848SJakub Kicinski p_err("failed to load object file"); 1111c8406848SJakub Kicinski goto err_close_obj; 1112c8406848SJakub Kicinski } 1113c8406848SJakub Kicinski 111477380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 111577380998SStanislav Fomichev if (err) 1116bfee71fbSJakub Kicinski goto err_close_obj; 111749a086c2SRoman Gushchin 111877380998SStanislav Fomichev if (first_prog_only) { 111977380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 112077380998SStanislav Fomichev if (!prog) { 112177380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 112277380998SStanislav Fomichev goto err_close_obj; 112377380998SStanislav Fomichev } 112477380998SStanislav Fomichev 112577380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 112677380998SStanislav Fomichev if (err) { 112777380998SStanislav Fomichev p_err("failed to pin program %s", 112877380998SStanislav Fomichev bpf_program__title(prog, false)); 112977380998SStanislav Fomichev goto err_close_obj; 113077380998SStanislav Fomichev } 113177380998SStanislav Fomichev } else { 113277380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 113377380998SStanislav Fomichev if (err) { 113477380998SStanislav Fomichev p_err("failed to pin all programs"); 113577380998SStanislav Fomichev goto err_close_obj; 113677380998SStanislav Fomichev } 113777380998SStanislav Fomichev } 113877380998SStanislav Fomichev 11393767a94bSStanislav Fomichev if (pinmaps) { 11403767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 11413767a94bSStanislav Fomichev if (err) { 11423767a94bSStanislav Fomichev p_err("failed to pin all maps"); 11433767a94bSStanislav Fomichev goto err_unpin; 11443767a94bSStanislav Fomichev } 11453767a94bSStanislav Fomichev } 11463767a94bSStanislav Fomichev 114749a086c2SRoman Gushchin if (json_output) 114849a086c2SRoman Gushchin jsonw_null(json_wtr); 114949a086c2SRoman Gushchin 1150bfee71fbSJakub Kicinski bpf_object__close(obj); 11513ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 11523ff5a4dcSJakub Kicinski close(map_replace[i].fd); 11533ff5a4dcSJakub Kicinski free(map_replace); 1154bfee71fbSJakub Kicinski 115549a086c2SRoman Gushchin return 0; 1156bfee71fbSJakub Kicinski 11573767a94bSStanislav Fomichev err_unpin: 11583767a94bSStanislav Fomichev if (first_prog_only) 11593767a94bSStanislav Fomichev unlink(pinfile); 11603767a94bSStanislav Fomichev else 11613767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1162bfee71fbSJakub Kicinski err_close_obj: 1163bfee71fbSJakub Kicinski bpf_object__close(obj); 11643ff5a4dcSJakub Kicinski err_free_reuse_maps: 11653ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 11663ff5a4dcSJakub Kicinski close(map_replace[i].fd); 11673ff5a4dcSJakub Kicinski free(map_replace); 1168bfee71fbSJakub Kicinski return -1; 116949a086c2SRoman Gushchin } 117049a086c2SRoman Gushchin 117177380998SStanislav Fomichev static int do_load(int argc, char **argv) 117277380998SStanislav Fomichev { 117377380998SStanislav Fomichev return load_with_options(argc, argv, true); 117477380998SStanislav Fomichev } 117577380998SStanislav Fomichev 117677380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 117777380998SStanislav Fomichev { 117877380998SStanislav Fomichev return load_with_options(argc, argv, false); 117977380998SStanislav Fomichev } 118077380998SStanislav Fomichev 118171bb428fSJakub Kicinski static int do_help(int argc, char **argv) 118271bb428fSJakub Kicinski { 1183004b45c0SQuentin Monnet if (json_output) { 1184004b45c0SQuentin Monnet jsonw_null(json_wtr); 1185004b45c0SQuentin Monnet return 0; 1186004b45c0SQuentin Monnet } 1187004b45c0SQuentin Monnet 118871bb428fSJakub Kicinski fprintf(stderr, 11896ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1190b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1191b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 119271bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 119377380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 119477380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 11953767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 11963767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1197092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1198092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 119930da46b5SQuentin Monnet " %s %s tracelog\n" 120071bb428fSJakub Kicinski " %s %s help\n" 120171bb428fSJakub Kicinski "\n" 12023ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 120371bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 120449f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 120549f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 120649f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 120749f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 120899a44befSQuentin Monnet " sk_reuseport | flow_dissector |\n" 120949f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 121049f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 121149f2cba3SJakub Kicinski " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 1212092f0892SStanislav Fomichev " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse |\n" 1213092f0892SStanislav Fomichev " flow_dissector }\n" 12140641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 121571bb428fSJakub Kicinski "", 121671bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1217b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 121830da46b5SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 121971bb428fSJakub Kicinski 122071bb428fSJakub Kicinski return 0; 122171bb428fSJakub Kicinski } 122271bb428fSJakub Kicinski 122371bb428fSJakub Kicinski static const struct cmd cmds[] = { 122471bb428fSJakub Kicinski { "show", do_show }, 12256ebe6dbdSJakub Kicinski { "list", do_show }, 12269f606179SQuentin Monnet { "help", do_help }, 122771bb428fSJakub Kicinski { "dump", do_dump }, 122871bb428fSJakub Kicinski { "pin", do_pin }, 122949a086c2SRoman Gushchin { "load", do_load }, 123077380998SStanislav Fomichev { "loadall", do_loadall }, 1231b7d3826cSJohn Fastabend { "attach", do_attach }, 1232b7d3826cSJohn Fastabend { "detach", do_detach }, 123330da46b5SQuentin Monnet { "tracelog", do_tracelog }, 123471bb428fSJakub Kicinski { 0 } 123571bb428fSJakub Kicinski }; 123671bb428fSJakub Kicinski 123771bb428fSJakub Kicinski int do_prog(int argc, char **argv) 123871bb428fSJakub Kicinski { 123971bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 124071bb428fSJakub Kicinski } 1241