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> 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 35c101189bSQuentin Monnet static 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 unsigned int id = 0; 8271bb428fSJakub Kicinski int err; 8371bb428fSJakub Kicinski int fd; 8471bb428fSJakub Kicinski 8571bb428fSJakub Kicinski while (true) { 86752bcf80SJiri Olsa struct bpf_prog_info info = {}; 87752bcf80SJiri Olsa __u32 len = sizeof(info); 88752bcf80SJiri Olsa 8971bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 9071bb428fSJakub Kicinski if (err) { 919a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 9271bb428fSJakub Kicinski return -1; 9371bb428fSJakub Kicinski } 9471bb428fSJakub Kicinski 9571bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 9671bb428fSJakub Kicinski if (fd < 0) { 979a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 9871bb428fSJakub Kicinski id, strerror(errno)); 9971bb428fSJakub Kicinski return -1; 10071bb428fSJakub Kicinski } 10171bb428fSJakub Kicinski 10271bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 10371bb428fSJakub Kicinski if (err) { 1049a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 10571bb428fSJakub Kicinski id, strerror(errno)); 10671bb428fSJakub Kicinski close(fd); 10771bb428fSJakub Kicinski return -1; 10871bb428fSJakub Kicinski } 10971bb428fSJakub Kicinski 11071bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 11171bb428fSJakub Kicinski return fd; 11271bb428fSJakub Kicinski 11371bb428fSJakub Kicinski close(fd); 11471bb428fSJakub Kicinski } 11571bb428fSJakub Kicinski } 11671bb428fSJakub Kicinski 11771bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 11871bb428fSJakub Kicinski { 11971bb428fSJakub Kicinski int fd; 12071bb428fSJakub Kicinski 12171bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 12271bb428fSJakub Kicinski unsigned int id; 12371bb428fSJakub Kicinski char *endptr; 12471bb428fSJakub Kicinski 12571bb428fSJakub Kicinski NEXT_ARGP(); 12671bb428fSJakub Kicinski 12771bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 12871bb428fSJakub Kicinski if (*endptr) { 1299a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 13071bb428fSJakub Kicinski return -1; 13171bb428fSJakub Kicinski } 13271bb428fSJakub Kicinski NEXT_ARGP(); 13371bb428fSJakub Kicinski 13471bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 13571bb428fSJakub Kicinski if (fd < 0) 1369a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 13771bb428fSJakub Kicinski return fd; 13871bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 13971bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 14071bb428fSJakub Kicinski 14171bb428fSJakub Kicinski NEXT_ARGP(); 14271bb428fSJakub Kicinski 14371bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 14471bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 14571bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1469a5ab8bfSQuentin Monnet p_err("can't parse tag"); 14771bb428fSJakub Kicinski return -1; 14871bb428fSJakub Kicinski } 14971bb428fSJakub Kicinski NEXT_ARGP(); 15071bb428fSJakub Kicinski 15171bb428fSJakub Kicinski return prog_fd_by_tag(tag); 15271bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 15371bb428fSJakub Kicinski char *path; 15471bb428fSJakub Kicinski 15571bb428fSJakub Kicinski NEXT_ARGP(); 15671bb428fSJakub Kicinski 15771bb428fSJakub Kicinski path = **argv; 15871bb428fSJakub Kicinski NEXT_ARGP(); 15971bb428fSJakub Kicinski 16071bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 16171bb428fSJakub Kicinski } 16271bb428fSJakub Kicinski 1639a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 16471bb428fSJakub Kicinski return -1; 16571bb428fSJakub Kicinski } 16671bb428fSJakub Kicinski 16771bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 16871bb428fSJakub Kicinski { 16971bb428fSJakub Kicinski struct bpf_prog_info info = {}; 17071bb428fSJakub Kicinski __u32 len = sizeof(info); 17171bb428fSJakub Kicinski __u32 map_ids[num_maps]; 17271bb428fSJakub Kicinski unsigned int i; 17371bb428fSJakub Kicinski int err; 17471bb428fSJakub Kicinski 17571bb428fSJakub Kicinski info.nr_map_ids = num_maps; 17671bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 17771bb428fSJakub Kicinski 17871bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 17971bb428fSJakub Kicinski if (err || !info.nr_map_ids) 18071bb428fSJakub Kicinski return; 18171bb428fSJakub Kicinski 182743cc665SQuentin Monnet if (json_output) { 183743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 184743cc665SQuentin Monnet jsonw_start_array(json_wtr); 185743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 186743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 187743cc665SQuentin Monnet jsonw_end_array(json_wtr); 188743cc665SQuentin Monnet } else { 18971bb428fSJakub Kicinski printf(" map_ids "); 19071bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 19171bb428fSJakub Kicinski printf("%u%s", map_ids[i], 19271bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 19371bb428fSJakub Kicinski } 19471bb428fSJakub Kicinski } 19571bb428fSJakub Kicinski 196743cc665SQuentin Monnet static void print_prog_json(struct bpf_prog_info *info, int fd) 197743cc665SQuentin Monnet { 198743cc665SQuentin Monnet char *memlock; 199743cc665SQuentin Monnet 200743cc665SQuentin Monnet jsonw_start_object(json_wtr); 201743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 202743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 203743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 204743cc665SQuentin Monnet prog_type_name[info->type]); 20571bb428fSJakub Kicinski else 206743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 20771bb428fSJakub Kicinski 208743cc665SQuentin Monnet if (*info->name) 209743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 21071bb428fSJakub Kicinski 211743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 212743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 213743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 214743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 21571bb428fSJakub Kicinski 2169b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 21788ad472bSAlexei Starovoitov if (info->run_time_ns) { 21888ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 21988ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 22088ad472bSAlexei Starovoitov } 2219b984a20SJiri Olsa 22252262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 22352262210SJakub Kicinski 224743cc665SQuentin Monnet if (info->load_time) { 22571bb428fSJakub Kicinski char buf[32]; 22671bb428fSJakub Kicinski 227743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 22871bb428fSJakub Kicinski 22971bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 230a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 231a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 232743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 23371bb428fSJakub Kicinski } 23471bb428fSJakub Kicinski 235743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 23671bb428fSJakub Kicinski 237743cc665SQuentin Monnet if (info->jited_prog_len) { 238743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 239743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 240743cc665SQuentin Monnet } else { 241743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 242743cc665SQuentin Monnet } 243743cc665SQuentin Monnet 244743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 245743cc665SQuentin Monnet if (memlock) 246743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 247743cc665SQuentin Monnet free(memlock); 248743cc665SQuentin Monnet 249743cc665SQuentin Monnet if (info->nr_map_ids) 250743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 251743cc665SQuentin Monnet 252569b0c77SPrashant Bhole if (info->btf_id) 253569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 254569b0c77SPrashant Bhole 2554990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 2564990f1f4SPrashant Bhole struct pinned_obj *obj; 2574990f1f4SPrashant Bhole 2584990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 2594990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 2604990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 2614990f1f4SPrashant Bhole if (obj->id == info->id) 2624990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 2634990f1f4SPrashant Bhole } 2644990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 2654990f1f4SPrashant Bhole } 2664990f1f4SPrashant Bhole 267743cc665SQuentin Monnet jsonw_end_object(json_wtr); 268743cc665SQuentin Monnet } 269743cc665SQuentin Monnet 270743cc665SQuentin Monnet static void print_prog_plain(struct bpf_prog_info *info, int fd) 271743cc665SQuentin Monnet { 272743cc665SQuentin Monnet char *memlock; 273743cc665SQuentin Monnet 274743cc665SQuentin Monnet printf("%u: ", info->id); 275743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 276743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 277743cc665SQuentin Monnet else 278743cc665SQuentin Monnet printf("type %u ", info->type); 279743cc665SQuentin Monnet 280743cc665SQuentin Monnet if (*info->name) 281743cc665SQuentin Monnet printf("name %s ", info->name); 282743cc665SQuentin Monnet 283743cc665SQuentin Monnet printf("tag "); 284743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 28552262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 2869b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 28788ad472bSAlexei Starovoitov if (info->run_time_ns) 28888ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 28988ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 290743cc665SQuentin Monnet printf("\n"); 291743cc665SQuentin Monnet 292743cc665SQuentin Monnet if (info->load_time) { 293743cc665SQuentin Monnet char buf[32]; 294743cc665SQuentin Monnet 295743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 296743cc665SQuentin Monnet 297743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 298743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 299743cc665SQuentin Monnet } 300743cc665SQuentin Monnet 301743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 302743cc665SQuentin Monnet 303743cc665SQuentin Monnet if (info->jited_prog_len) 304743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 30571bb428fSJakub Kicinski else 30671bb428fSJakub Kicinski printf(" not jited"); 30771bb428fSJakub Kicinski 30871bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 30971bb428fSJakub Kicinski if (memlock) 31071bb428fSJakub Kicinski printf(" memlock %sB", memlock); 31171bb428fSJakub Kicinski free(memlock); 31271bb428fSJakub Kicinski 313743cc665SQuentin Monnet if (info->nr_map_ids) 314743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 31571bb428fSJakub Kicinski 3164990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3174990f1f4SPrashant Bhole struct pinned_obj *obj; 3184990f1f4SPrashant Bhole 3194990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3204990f1f4SPrashant Bhole if (obj->id == info->id) 321a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 3224990f1f4SPrashant Bhole } 3234990f1f4SPrashant Bhole } 3244990f1f4SPrashant Bhole 325569b0c77SPrashant Bhole if (info->btf_id) 326*031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 327569b0c77SPrashant Bhole 32871bb428fSJakub Kicinski printf("\n"); 329743cc665SQuentin Monnet } 330743cc665SQuentin Monnet 331743cc665SQuentin Monnet static int show_prog(int fd) 332743cc665SQuentin Monnet { 333743cc665SQuentin Monnet struct bpf_prog_info info = {}; 334743cc665SQuentin Monnet __u32 len = sizeof(info); 335743cc665SQuentin Monnet int err; 336743cc665SQuentin Monnet 337743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 338743cc665SQuentin Monnet if (err) { 3399a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 340743cc665SQuentin Monnet return -1; 341743cc665SQuentin Monnet } 342743cc665SQuentin Monnet 343743cc665SQuentin Monnet if (json_output) 344743cc665SQuentin Monnet print_prog_json(&info, fd); 345743cc665SQuentin Monnet else 346743cc665SQuentin Monnet print_prog_plain(&info, fd); 34771bb428fSJakub Kicinski 34871bb428fSJakub Kicinski return 0; 34971bb428fSJakub Kicinski } 35071bb428fSJakub Kicinski 35171bb428fSJakub Kicinski static int do_show(int argc, char **argv) 352743cc665SQuentin Monnet { 353743cc665SQuentin Monnet __u32 id = 0; 35471bb428fSJakub Kicinski int err; 35571bb428fSJakub Kicinski int fd; 35671bb428fSJakub Kicinski 357c541b734SPrashant Bhole if (show_pinned) 3584990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 3594990f1f4SPrashant Bhole 36071bb428fSJakub Kicinski if (argc == 2) { 36171bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 36271bb428fSJakub Kicinski if (fd < 0) 36371bb428fSJakub Kicinski return -1; 36471bb428fSJakub Kicinski 36571bb428fSJakub Kicinski return show_prog(fd); 36671bb428fSJakub Kicinski } 36771bb428fSJakub Kicinski 36871bb428fSJakub Kicinski if (argc) 36971bb428fSJakub Kicinski return BAD_ARG(); 37071bb428fSJakub Kicinski 371743cc665SQuentin Monnet if (json_output) 372743cc665SQuentin Monnet jsonw_start_array(json_wtr); 37371bb428fSJakub Kicinski while (true) { 37471bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 37571bb428fSJakub Kicinski if (err) { 3761739c26dSQuentin Monnet if (errno == ENOENT) { 3771739c26dSQuentin Monnet err = 0; 37871bb428fSJakub Kicinski break; 3791739c26dSQuentin Monnet } 3809a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 3819a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 382743cc665SQuentin Monnet err = -1; 383743cc665SQuentin Monnet break; 38471bb428fSJakub Kicinski } 38571bb428fSJakub Kicinski 38671bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 38771bb428fSJakub Kicinski if (fd < 0) { 3888207c6ddSJakub Kicinski if (errno == ENOENT) 3898207c6ddSJakub Kicinski continue; 3909a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 39171bb428fSJakub Kicinski id, strerror(errno)); 392743cc665SQuentin Monnet err = -1; 393743cc665SQuentin Monnet break; 39471bb428fSJakub Kicinski } 39571bb428fSJakub Kicinski 39671bb428fSJakub Kicinski err = show_prog(fd); 39771bb428fSJakub Kicinski close(fd); 39871bb428fSJakub Kicinski if (err) 399743cc665SQuentin Monnet break; 40071bb428fSJakub Kicinski } 40171bb428fSJakub Kicinski 402743cc665SQuentin Monnet if (json_output) 403743cc665SQuentin Monnet jsonw_end_array(json_wtr); 404743cc665SQuentin Monnet 405743cc665SQuentin Monnet return err; 40671bb428fSJakub Kicinski } 40771bb428fSJakub Kicinski 40871bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 40971bb428fSJakub Kicinski { 410cae73f23SSong Liu struct bpf_prog_info_linear *info_linear; 411b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 412cae73f23SSong Liu enum {DUMP_JITED, DUMP_XLATED} mode; 4133ddeac67SJakub Kicinski const char *disasm_opt = NULL; 414cae73f23SSong Liu struct bpf_prog_info *info; 4157105e828SDaniel Borkmann struct dump_data dd = {}; 416cae73f23SSong Liu void *func_info = NULL; 417254471e5SYonghong Song struct btf *btf = NULL; 41871bb428fSJakub Kicinski char *filepath = NULL; 41971bb428fSJakub Kicinski bool opcodes = false; 420b6c1cedbSJiong Wang bool visual = false; 421254471e5SYonghong Song char func_sig[1024]; 42271bb428fSJakub Kicinski unsigned char *buf; 423b053b439SMartin KaFai Lau bool linum = false; 424cae73f23SSong Liu __u32 member_len; 425cae73f23SSong Liu __u64 arrays; 42671bb428fSJakub Kicinski ssize_t n; 42771bb428fSJakub Kicinski int fd; 42871bb428fSJakub Kicinski 42971bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 43029a9c10eSStanislav Fomichev if (disasm_init()) 43129a9c10eSStanislav Fomichev return -1; 432cae73f23SSong Liu mode = DUMP_JITED; 43371bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 434cae73f23SSong Liu mode = DUMP_XLATED; 43571bb428fSJakub Kicinski } else { 4369a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 43771bb428fSJakub Kicinski return -1; 43871bb428fSJakub Kicinski } 43971bb428fSJakub Kicinski NEXT_ARG(); 44071bb428fSJakub Kicinski 44171bb428fSJakub Kicinski if (argc < 2) 44271bb428fSJakub Kicinski usage(); 44371bb428fSJakub Kicinski 44471bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 44571bb428fSJakub Kicinski if (fd < 0) 44671bb428fSJakub Kicinski return -1; 44771bb428fSJakub Kicinski 44871bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 44971bb428fSJakub Kicinski NEXT_ARG(); 45071bb428fSJakub Kicinski if (!argc) { 4519a5ab8bfSQuentin Monnet p_err("expected file path"); 45271bb428fSJakub Kicinski return -1; 45371bb428fSJakub Kicinski } 45471bb428fSJakub Kicinski 45571bb428fSJakub Kicinski filepath = *argv; 45671bb428fSJakub Kicinski NEXT_ARG(); 45771bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 45871bb428fSJakub Kicinski opcodes = true; 45971bb428fSJakub Kicinski NEXT_ARG(); 460b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 461b6c1cedbSJiong Wang visual = true; 462b6c1cedbSJiong Wang NEXT_ARG(); 463b053b439SMartin KaFai Lau } else if (is_prefix(*argv, "linum")) { 464b053b439SMartin KaFai Lau linum = true; 465b053b439SMartin KaFai Lau NEXT_ARG(); 46671bb428fSJakub Kicinski } 46771bb428fSJakub Kicinski 46871bb428fSJakub Kicinski if (argc) { 46971bb428fSJakub Kicinski usage(); 47071bb428fSJakub Kicinski return -1; 47171bb428fSJakub Kicinski } 47271bb428fSJakub Kicinski 473cae73f23SSong Liu if (mode == DUMP_JITED) 474cae73f23SSong Liu arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 475cae73f23SSong Liu else 476cae73f23SSong Liu arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 477cae73f23SSong Liu 478cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 479cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 480cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 481cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 482cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 483cae73f23SSong Liu 484cae73f23SSong Liu info_linear = bpf_program__get_prog_info_linear(fd, arrays); 485cae73f23SSong Liu close(fd); 486cae73f23SSong Liu if (IS_ERR_OR_NULL(info_linear)) { 4879a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 48871bb428fSJakub Kicinski return -1; 48971bb428fSJakub Kicinski } 49071bb428fSJakub Kicinski 491cae73f23SSong Liu info = &info_linear->info; 492cae73f23SSong Liu if (mode == DUMP_JITED) { 493cae73f23SSong Liu if (info->jited_prog_len == 0) { 4949a5ab8bfSQuentin Monnet p_info("no instructions returned"); 495f84192eeSSandipan Das goto err_free; 496f84192eeSSandipan Das } 497cae73f23SSong Liu buf = (unsigned char *)(info->jited_prog_insns); 498cae73f23SSong Liu member_len = info->jited_prog_len; 499cae73f23SSong Liu } else { /* DUMP_XLATED */ 500cae73f23SSong Liu if (info->xlated_prog_len == 0) { 5017105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 5027105e828SDaniel Borkmann goto err_free; 5037105e828SDaniel Borkmann } 504cae73f23SSong Liu buf = (unsigned char *)info->xlated_prog_insns; 505cae73f23SSong Liu member_len = info->xlated_prog_len; 506cae73f23SSong Liu } 5077105e828SDaniel Borkmann 508cae73f23SSong Liu if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 509254471e5SYonghong Song p_err("failed to get btf"); 510254471e5SYonghong Song goto err_free; 511254471e5SYonghong Song } 512254471e5SYonghong Song 513cae73f23SSong Liu func_info = (void *)info->func_info; 514cae73f23SSong Liu 515cae73f23SSong Liu if (info->nr_line_info) { 516cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 517b053b439SMartin KaFai Lau if (!prog_linfo) 51810a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 519b053b439SMartin KaFai Lau } 520b053b439SMartin KaFai Lau 52171bb428fSJakub Kicinski if (filepath) { 52271bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 52371bb428fSJakub Kicinski if (fd < 0) { 5249a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 52571bb428fSJakub Kicinski strerror(errno)); 52671bb428fSJakub Kicinski goto err_free; 52771bb428fSJakub Kicinski } 52871bb428fSJakub Kicinski 529cae73f23SSong Liu n = write(fd, buf, member_len); 53071bb428fSJakub Kicinski close(fd); 531cae73f23SSong Liu if (n != member_len) { 5329a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 53371bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 53471bb428fSJakub Kicinski goto err_free; 53571bb428fSJakub Kicinski } 53652c84d36SQuentin Monnet 53752c84d36SQuentin Monnet if (json_output) 53852c84d36SQuentin Monnet jsonw_null(json_wtr); 539cae73f23SSong Liu } else if (mode == DUMP_JITED) { 540e6593596SJiong Wang const char *name = NULL; 541e6593596SJiong Wang 542cae73f23SSong Liu if (info->ifindex) { 543cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 544cae73f23SSong Liu info->netns_dev, 545cae73f23SSong Liu info->netns_ino, 5463ddeac67SJakub Kicinski &disasm_opt); 547e6593596SJiong Wang if (!name) 548e6593596SJiong Wang goto err_free; 549e6593596SJiong Wang } 550e6593596SJiong Wang 551cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 552f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 553254471e5SYonghong Song struct bpf_func_info *record; 554f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 555f7f62c71SSandipan Das unsigned char *img = buf; 556f7f62c71SSandipan Das __u64 *ksyms = NULL; 557f7f62c71SSandipan Das __u32 *lens; 558f7f62c71SSandipan Das __u32 i; 559cae73f23SSong Liu if (info->nr_jited_ksyms) { 560f7f62c71SSandipan Das kernel_syms_load(&dd); 561cae73f23SSong Liu ksyms = (__u64 *) info->jited_ksyms; 562f7f62c71SSandipan Das } 563f7f62c71SSandipan Das 564f7f62c71SSandipan Das if (json_output) 565f7f62c71SSandipan Das jsonw_start_array(json_wtr); 566f7f62c71SSandipan Das 567cae73f23SSong Liu lens = (__u32 *) info->jited_func_lens; 568cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 569f7f62c71SSandipan Das if (ksyms) { 570f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 571f7f62c71SSandipan Das if (sym) 572f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 573f7f62c71SSandipan Das else 574f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 575f7f62c71SSandipan Das } else { 576f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 577f7f62c71SSandipan Das } 578f7f62c71SSandipan Das 579254471e5SYonghong Song if (func_info) { 580cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 581254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 582254471e5SYonghong Song func_sig, 583254471e5SYonghong Song sizeof(func_sig)); 584254471e5SYonghong Song } 585254471e5SYonghong Song 586f7f62c71SSandipan Das if (json_output) { 587f7f62c71SSandipan Das jsonw_start_object(json_wtr); 588254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 589254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 590254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 591254471e5SYonghong Song } 592f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 593f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 594f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 595f7f62c71SSandipan Das } else { 596254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 597254471e5SYonghong Song printf("%s:\n", func_sig); 598f7f62c71SSandipan Das printf("%s:\n", sym_name); 599f7f62c71SSandipan Das } 600f7f62c71SSandipan Das 601b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 602b053b439SMartin KaFai Lau name, disasm_opt, btf, 603b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 604b053b439SMartin KaFai Lau linum); 605b053b439SMartin KaFai Lau 606f7f62c71SSandipan Das img += lens[i]; 607f7f62c71SSandipan Das 608f7f62c71SSandipan Das if (json_output) 609f7f62c71SSandipan Das jsonw_end_object(json_wtr); 610f7f62c71SSandipan Das else 611f7f62c71SSandipan Das printf("\n"); 612f7f62c71SSandipan Das } 613f7f62c71SSandipan Das 614f7f62c71SSandipan Das if (json_output) 615f7f62c71SSandipan Das jsonw_end_array(json_wtr); 616f7f62c71SSandipan Das } else { 617cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 618b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 619f7f62c71SSandipan Das } 620b6c1cedbSJiong Wang } else if (visual) { 621b6c1cedbSJiong Wang if (json_output) 622b6c1cedbSJiong Wang jsonw_null(json_wtr); 623b6c1cedbSJiong Wang else 624cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 6257105e828SDaniel Borkmann } else { 6267105e828SDaniel Borkmann kernel_syms_load(&dd); 627cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 628cae73f23SSong Liu dd.jited_ksyms = (__u64 *) info->jited_ksyms; 629254471e5SYonghong Song dd.btf = btf; 630254471e5SYonghong Song dd.func_info = func_info; 631cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 632b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 633f84192eeSSandipan Das 634f05e2c32SQuentin Monnet if (json_output) 635cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 636b053b439SMartin KaFai Lau linum); 637f05e2c32SQuentin Monnet else 638cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 639b053b439SMartin KaFai Lau linum); 6407105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6417105e828SDaniel Borkmann } 64271bb428fSJakub Kicinski 643cae73f23SSong Liu free(info_linear); 64471bb428fSJakub Kicinski return 0; 64571bb428fSJakub Kicinski 64671bb428fSJakub Kicinski err_free: 647cae73f23SSong Liu free(info_linear); 64871bb428fSJakub Kicinski return -1; 64971bb428fSJakub Kicinski } 65071bb428fSJakub Kicinski 65171bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 65271bb428fSJakub Kicinski { 653004b45c0SQuentin Monnet int err; 654004b45c0SQuentin Monnet 655004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 656004b45c0SQuentin Monnet if (!err && json_output) 657004b45c0SQuentin Monnet jsonw_null(json_wtr); 658004b45c0SQuentin Monnet return err; 65971bb428fSJakub Kicinski } 66071bb428fSJakub Kicinski 6613ff5a4dcSJakub Kicinski struct map_replace { 6623ff5a4dcSJakub Kicinski int idx; 6633ff5a4dcSJakub Kicinski int fd; 6643ff5a4dcSJakub Kicinski char *name; 6653ff5a4dcSJakub Kicinski }; 6663ff5a4dcSJakub Kicinski 667c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 6683ff5a4dcSJakub Kicinski { 6693ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 6703ff5a4dcSJakub Kicinski 6713ff5a4dcSJakub Kicinski return a->idx - b->idx; 6723ff5a4dcSJakub Kicinski } 6733ff5a4dcSJakub Kicinski 674092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 675092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 676092f0892SStanislav Fomichev int *mapfd) 677092f0892SStanislav Fomichev { 678092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 679092f0892SStanislav Fomichev return -EINVAL; 680092f0892SStanislav Fomichev 681092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 682092f0892SStanislav Fomichev if (*progfd < 0) 683092f0892SStanislav Fomichev return *progfd; 684092f0892SStanislav Fomichev 685092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 686092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 687092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 688092f0892SStanislav Fomichev return -EINVAL; 689092f0892SStanislav Fomichev } 690092f0892SStanislav Fomichev 691092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 692092f0892SStanislav Fomichev *mapfd = -1; 693092f0892SStanislav Fomichev return 0; 694092f0892SStanislav Fomichev } 695092f0892SStanislav Fomichev 696092f0892SStanislav Fomichev NEXT_ARG(); 697092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 698092f0892SStanislav Fomichev return -EINVAL; 699092f0892SStanislav Fomichev 700092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 701092f0892SStanislav Fomichev if (*mapfd < 0) 702092f0892SStanislav Fomichev return *mapfd; 703092f0892SStanislav Fomichev 704092f0892SStanislav Fomichev return 0; 705092f0892SStanislav Fomichev } 706092f0892SStanislav Fomichev 707b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 708b7d3826cSJohn Fastabend { 709b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 710092f0892SStanislav Fomichev int err, progfd; 711092f0892SStanislav Fomichev int mapfd; 712b7d3826cSJohn Fastabend 713092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 714092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 715092f0892SStanislav Fomichev if (err) 716092f0892SStanislav Fomichev return err; 717b7d3826cSJohn Fastabend 718b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 719b7d3826cSJohn Fastabend if (err) { 720b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 721b7d3826cSJohn Fastabend return -EINVAL; 722b7d3826cSJohn Fastabend } 723b7d3826cSJohn Fastabend 724b7d3826cSJohn Fastabend if (json_output) 725b7d3826cSJohn Fastabend jsonw_null(json_wtr); 726b7d3826cSJohn Fastabend return 0; 727b7d3826cSJohn Fastabend } 728b7d3826cSJohn Fastabend 729b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 730b7d3826cSJohn Fastabend { 731b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 732092f0892SStanislav Fomichev int err, progfd; 733092f0892SStanislav Fomichev int mapfd; 734b7d3826cSJohn Fastabend 735092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 736092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 737092f0892SStanislav Fomichev if (err) 738092f0892SStanislav Fomichev return err; 739b7d3826cSJohn Fastabend 740b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 741b7d3826cSJohn Fastabend if (err) { 742b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 743b7d3826cSJohn Fastabend return -EINVAL; 744b7d3826cSJohn Fastabend } 745b7d3826cSJohn Fastabend 746b7d3826cSJohn Fastabend if (json_output) 747b7d3826cSJohn Fastabend jsonw_null(json_wtr); 748b7d3826cSJohn Fastabend return 0; 749b7d3826cSJohn Fastabend } 75077380998SStanislav Fomichev 75177380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 75249a086c2SRoman Gushchin { 753c8406848SJakub Kicinski enum bpf_attach_type expected_attach_type; 754c8406848SJakub Kicinski struct bpf_object_open_attr attr = { 755ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 756ba6dd679SJakub Kicinski }; 7573ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 75877380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 7593ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 7603767a94bSStanislav Fomichev const char *pinmaps = NULL; 76149a086c2SRoman Gushchin struct bpf_object *obj; 762c8406848SJakub Kicinski struct bpf_map *map; 763c8406848SJakub Kicinski const char *pinfile; 7643ff5a4dcSJakub Kicinski unsigned int i, j; 765c8406848SJakub Kicinski __u32 ifindex = 0; 7663ff5a4dcSJakub Kicinski int idx, err; 76749a086c2SRoman Gushchin 7688d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 7698d1fc3deSJakub Kicinski return -1; 770c8406848SJakub Kicinski attr.file = GET_ARG(); 7718d1fc3deSJakub Kicinski pinfile = GET_ARG(); 77249a086c2SRoman Gushchin 773ba6dd679SJakub Kicinski while (argc) { 77449f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 77549f2cba3SJakub Kicinski char *type; 77649f2cba3SJakub Kicinski 77749f2cba3SJakub Kicinski NEXT_ARG(); 77849f2cba3SJakub Kicinski 77949f2cba3SJakub Kicinski if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 78049f2cba3SJakub Kicinski p_err("program type already specified"); 7813ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 78249f2cba3SJakub Kicinski } 78349f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 7843ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 78549f2cba3SJakub Kicinski 78649f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 78749f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 78849f2cba3SJakub Kicinski if (!type) { 78949f2cba3SJakub Kicinski p_err("mem alloc failed"); 7903ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 79149f2cba3SJakub Kicinski } 79249f2cba3SJakub Kicinski *type = 0; 79349f2cba3SJakub Kicinski strcat(type, *argv); 79449f2cba3SJakub Kicinski strcat(type, "/"); 79549f2cba3SJakub Kicinski 79649f2cba3SJakub Kicinski err = libbpf_prog_type_by_name(type, &attr.prog_type, 797c8406848SJakub Kicinski &expected_attach_type); 79849f2cba3SJakub Kicinski free(type); 799c76e4c22STaeung Song if (err < 0) 8003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 801c76e4c22STaeung Song 80249f2cba3SJakub Kicinski NEXT_ARG(); 8033ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 804dde7011aSJakub Kicinski void *new_map_replace; 8053ff5a4dcSJakub Kicinski char *endptr, *name; 8063ff5a4dcSJakub Kicinski int fd; 8073ff5a4dcSJakub Kicinski 8083ff5a4dcSJakub Kicinski NEXT_ARG(); 8093ff5a4dcSJakub Kicinski 8103ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 8113ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 8123ff5a4dcSJakub Kicinski 8133ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 8143ff5a4dcSJakub Kicinski NEXT_ARG(); 8153ff5a4dcSJakub Kicinski 8163ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 8173ff5a4dcSJakub Kicinski if (*endptr) { 8183ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 8193ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 8203ff5a4dcSJakub Kicinski } 8213ff5a4dcSJakub Kicinski name = NULL; 8223ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 8233ff5a4dcSJakub Kicinski NEXT_ARG(); 8243ff5a4dcSJakub Kicinski 8253ff5a4dcSJakub Kicinski name = *argv; 8263ff5a4dcSJakub Kicinski idx = -1; 8273ff5a4dcSJakub Kicinski } else { 8283ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 8293ff5a4dcSJakub Kicinski *argv); 8303ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 8313ff5a4dcSJakub Kicinski } 8323ff5a4dcSJakub Kicinski NEXT_ARG(); 8333ff5a4dcSJakub Kicinski 8343ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 8353ff5a4dcSJakub Kicinski if (fd < 0) 8363ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 8373ff5a4dcSJakub Kicinski 838dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 839dde7011aSJakub Kicinski old_map_fds + 1, 8403ff5a4dcSJakub Kicinski sizeof(*map_replace)); 841dde7011aSJakub Kicinski if (!new_map_replace) { 8423ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 8433ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 8443ff5a4dcSJakub Kicinski } 845dde7011aSJakub Kicinski map_replace = new_map_replace; 846dde7011aSJakub Kicinski 8473ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 8483ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 8493ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 8503ff5a4dcSJakub Kicinski old_map_fds++; 85149f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 852ba6dd679SJakub Kicinski NEXT_ARG(); 853ba6dd679SJakub Kicinski 854c8406848SJakub Kicinski if (ifindex) { 855ba6dd679SJakub Kicinski p_err("offload device already specified"); 8563ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 857ba6dd679SJakub Kicinski } 858ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 8593ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 860ba6dd679SJakub Kicinski 861c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 862c8406848SJakub Kicinski if (!ifindex) { 863ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 864ba6dd679SJakub Kicinski *argv, strerror(errno)); 8653ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 866ba6dd679SJakub Kicinski } 867ba6dd679SJakub Kicinski NEXT_ARG(); 8683767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 8693767a94bSStanislav Fomichev NEXT_ARG(); 8703767a94bSStanislav Fomichev 8713767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 8723767a94bSStanislav Fomichev goto err_free_reuse_maps; 8733767a94bSStanislav Fomichev 8743767a94bSStanislav Fomichev pinmaps = GET_ARG(); 875ba6dd679SJakub Kicinski } else { 8763ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 877ba6dd679SJakub Kicinski *argv); 8783ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 879ba6dd679SJakub Kicinski } 880ba6dd679SJakub Kicinski } 881ba6dd679SJakub Kicinski 882c034a177SJohn Fastabend obj = __bpf_object__open_xattr(&attr, bpf_flags); 883c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 884c8406848SJakub Kicinski p_err("failed to open object file"); 8853ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 88649a086c2SRoman Gushchin } 88749a086c2SRoman Gushchin 88877380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 88977380998SStanislav Fomichev enum bpf_prog_type prog_type = attr.prog_type; 890c8406848SJakub Kicinski 891c8406848SJakub Kicinski if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 89277380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 893c8406848SJakub Kicinski 89477380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 895c8406848SJakub Kicinski &expected_attach_type); 896c76e4c22STaeung Song if (err < 0) 897c8406848SJakub Kicinski goto err_close_obj; 898c8406848SJakub Kicinski } 89977380998SStanislav Fomichev 90077380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 90177380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 90277380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 90377380998SStanislav Fomichev } 904c8406848SJakub Kicinski 9053ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 9063ff5a4dcSJakub Kicinski map_replace_compar); 9073ff5a4dcSJakub Kicinski 9083ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 9093ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 9103ff5a4dcSJakub Kicinski */ 9113ff5a4dcSJakub Kicinski j = 0; 9123ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 9133ff5a4dcSJakub Kicinski i = 0; 914f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 9153ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 9163ff5a4dcSJakub Kicinski map_replace[j].idx = i; 9173ff5a4dcSJakub Kicinski break; 9183ff5a4dcSJakub Kicinski } 9193ff5a4dcSJakub Kicinski i++; 9203ff5a4dcSJakub Kicinski } 9213ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 9223ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 9233ff5a4dcSJakub Kicinski goto err_close_obj; 9243ff5a4dcSJakub Kicinski } 9253ff5a4dcSJakub Kicinski j++; 9263ff5a4dcSJakub Kicinski } 9273ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 9283ff5a4dcSJakub Kicinski if (j) 9293ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 9303ff5a4dcSJakub Kicinski map_replace_compar); 9313ff5a4dcSJakub Kicinski 9323ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 9333ff5a4dcSJakub Kicinski j = 0; 9343ff5a4dcSJakub Kicinski idx = 0; 935f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 936c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 937c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 938c8406848SJakub Kicinski 9393ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 9403ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 9413ff5a4dcSJakub Kicinski if (err) { 9423ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 9433ff5a4dcSJakub Kicinski goto err_close_obj; 9443ff5a4dcSJakub Kicinski } 9453ff5a4dcSJakub Kicinski 9463ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 9473ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 9483ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 9493ff5a4dcSJakub Kicinski idx); 9503ff5a4dcSJakub Kicinski goto err_close_obj; 9513ff5a4dcSJakub Kicinski } 9523ff5a4dcSJakub Kicinski } 9533ff5a4dcSJakub Kicinski 9543ff5a4dcSJakub Kicinski idx++; 9553ff5a4dcSJakub Kicinski } 9563ff5a4dcSJakub Kicinski if (j < old_map_fds) { 9573ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 9583ff5a4dcSJakub Kicinski goto err_close_obj; 9593ff5a4dcSJakub Kicinski } 9603ff5a4dcSJakub Kicinski 9618302b9bdSQuentin Monnet set_max_rlimit(); 9628302b9bdSQuentin Monnet 963c8406848SJakub Kicinski err = bpf_object__load(obj); 964c8406848SJakub Kicinski if (err) { 965c8406848SJakub Kicinski p_err("failed to load object file"); 966c8406848SJakub Kicinski goto err_close_obj; 967c8406848SJakub Kicinski } 968c8406848SJakub Kicinski 96977380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 97077380998SStanislav Fomichev if (err) 971bfee71fbSJakub Kicinski goto err_close_obj; 97249a086c2SRoman Gushchin 97377380998SStanislav Fomichev if (first_prog_only) { 97477380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 97577380998SStanislav Fomichev if (!prog) { 97677380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 97777380998SStanislav Fomichev goto err_close_obj; 97877380998SStanislav Fomichev } 97977380998SStanislav Fomichev 98077380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 98177380998SStanislav Fomichev if (err) { 98277380998SStanislav Fomichev p_err("failed to pin program %s", 98377380998SStanislav Fomichev bpf_program__title(prog, false)); 98477380998SStanislav Fomichev goto err_close_obj; 98577380998SStanislav Fomichev } 98677380998SStanislav Fomichev } else { 98777380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 98877380998SStanislav Fomichev if (err) { 98977380998SStanislav Fomichev p_err("failed to pin all programs"); 99077380998SStanislav Fomichev goto err_close_obj; 99177380998SStanislav Fomichev } 99277380998SStanislav Fomichev } 99377380998SStanislav Fomichev 9943767a94bSStanislav Fomichev if (pinmaps) { 9953767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 9963767a94bSStanislav Fomichev if (err) { 9973767a94bSStanislav Fomichev p_err("failed to pin all maps"); 9983767a94bSStanislav Fomichev goto err_unpin; 9993767a94bSStanislav Fomichev } 10003767a94bSStanislav Fomichev } 10013767a94bSStanislav Fomichev 100249a086c2SRoman Gushchin if (json_output) 100349a086c2SRoman Gushchin jsonw_null(json_wtr); 100449a086c2SRoman Gushchin 1005bfee71fbSJakub Kicinski bpf_object__close(obj); 10063ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 10073ff5a4dcSJakub Kicinski close(map_replace[i].fd); 10083ff5a4dcSJakub Kicinski free(map_replace); 1009bfee71fbSJakub Kicinski 101049a086c2SRoman Gushchin return 0; 1011bfee71fbSJakub Kicinski 10123767a94bSStanislav Fomichev err_unpin: 10133767a94bSStanislav Fomichev if (first_prog_only) 10143767a94bSStanislav Fomichev unlink(pinfile); 10153767a94bSStanislav Fomichev else 10163767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1017bfee71fbSJakub Kicinski err_close_obj: 1018bfee71fbSJakub Kicinski bpf_object__close(obj); 10193ff5a4dcSJakub Kicinski err_free_reuse_maps: 10203ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 10213ff5a4dcSJakub Kicinski close(map_replace[i].fd); 10223ff5a4dcSJakub Kicinski free(map_replace); 1023bfee71fbSJakub Kicinski return -1; 102449a086c2SRoman Gushchin } 102549a086c2SRoman Gushchin 102677380998SStanislav Fomichev static int do_load(int argc, char **argv) 102777380998SStanislav Fomichev { 102877380998SStanislav Fomichev return load_with_options(argc, argv, true); 102977380998SStanislav Fomichev } 103077380998SStanislav Fomichev 103177380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 103277380998SStanislav Fomichev { 103377380998SStanislav Fomichev return load_with_options(argc, argv, false); 103477380998SStanislav Fomichev } 103577380998SStanislav Fomichev 103671bb428fSJakub Kicinski static int do_help(int argc, char **argv) 103771bb428fSJakub Kicinski { 1038004b45c0SQuentin Monnet if (json_output) { 1039004b45c0SQuentin Monnet jsonw_null(json_wtr); 1040004b45c0SQuentin Monnet return 0; 1041004b45c0SQuentin Monnet } 1042004b45c0SQuentin Monnet 104371bb428fSJakub Kicinski fprintf(stderr, 10446ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1045b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1046b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 104771bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 104877380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 104977380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 10503767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 10513767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1052092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1053092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 105430da46b5SQuentin Monnet " %s %s tracelog\n" 105571bb428fSJakub Kicinski " %s %s help\n" 105671bb428fSJakub Kicinski "\n" 10573ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 105871bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 105949f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 106049f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 106149f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 106249f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 106399a44befSQuentin Monnet " sk_reuseport | flow_dissector |\n" 106449f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 106549f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 106649f2cba3SJakub Kicinski " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 1067a5d9265eSAlban Crequy " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1068092f0892SStanislav Fomichev " flow_dissector }\n" 10690641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 107071bb428fSJakub Kicinski "", 107171bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1072b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 107330da46b5SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 107471bb428fSJakub Kicinski 107571bb428fSJakub Kicinski return 0; 107671bb428fSJakub Kicinski } 107771bb428fSJakub Kicinski 107871bb428fSJakub Kicinski static const struct cmd cmds[] = { 107971bb428fSJakub Kicinski { "show", do_show }, 10806ebe6dbdSJakub Kicinski { "list", do_show }, 10819f606179SQuentin Monnet { "help", do_help }, 108271bb428fSJakub Kicinski { "dump", do_dump }, 108371bb428fSJakub Kicinski { "pin", do_pin }, 108449a086c2SRoman Gushchin { "load", do_load }, 108577380998SStanislav Fomichev { "loadall", do_loadall }, 1086b7d3826cSJohn Fastabend { "attach", do_attach }, 1087b7d3826cSJohn Fastabend { "detach", do_detach }, 108830da46b5SQuentin Monnet { "tracelog", do_tracelog }, 108971bb428fSJakub Kicinski { 0 } 109071bb428fSJakub Kicinski }; 109171bb428fSJakub Kicinski 109271bb428fSJakub Kicinski int do_prog(int argc, char **argv) 109371bb428fSJakub Kicinski { 109471bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 109571bb428fSJakub Kicinski } 1096