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> 18*ba95c745SQuentin Monnet #include <linux/sizes.h> 19c8406848SJakub Kicinski 2071bb428fSJakub Kicinski #include <bpf.h> 21254471e5SYonghong Song #include <btf.h> 2249a086c2SRoman Gushchin #include <libbpf.h> 2371bb428fSJakub Kicinski 24b6c1cedbSJiong Wang #include "cfg.h" 2571bb428fSJakub Kicinski #include "main.h" 2673bb5b4fSJiong Wang #include "xlated_dumper.h" 2771bb428fSJakub Kicinski 28b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 29b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 30b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 31b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 32092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 33b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 34b7d3826cSJohn Fastabend }; 35b7d3826cSJohn Fastabend 36c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 37b7d3826cSJohn Fastabend { 38b7d3826cSJohn Fastabend enum bpf_attach_type type; 39b7d3826cSJohn Fastabend 40b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 41b7d3826cSJohn Fastabend if (attach_type_strings[type] && 42b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 43b7d3826cSJohn Fastabend return type; 44b7d3826cSJohn Fastabend } 45b7d3826cSJohn Fastabend 46b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 47b7d3826cSJohn Fastabend } 48b7d3826cSJohn Fastabend 4971bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 5071bb428fSJakub Kicinski { 5171bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 5271bb428fSJakub Kicinski time_t wallclock_secs; 5371bb428fSJakub Kicinski struct tm load_tm; 5471bb428fSJakub Kicinski 5571bb428fSJakub Kicinski buf[--size] = '\0'; 5671bb428fSJakub Kicinski 5771bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 5871bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 5971bb428fSJakub Kicinski perror("Can't read clocks"); 6071bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 6171bb428fSJakub Kicinski return; 6271bb428fSJakub Kicinski } 6371bb428fSJakub Kicinski 6471bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 6507480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 6607480cbcSJakub Kicinski 1000000000; 6707480cbcSJakub Kicinski 6871bb428fSJakub Kicinski 6971bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 7071bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 7171bb428fSJakub Kicinski return; 7271bb428fSJakub Kicinski } 7371bb428fSJakub Kicinski 74a3fe1f6fSQuentin Monnet if (json_output) 75a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 76a3fe1f6fSQuentin Monnet else 77a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 7871bb428fSJakub Kicinski } 7971bb428fSJakub Kicinski 8071bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 8171bb428fSJakub Kicinski { 8271bb428fSJakub Kicinski unsigned int id = 0; 8371bb428fSJakub Kicinski int err; 8471bb428fSJakub Kicinski int fd; 8571bb428fSJakub Kicinski 8671bb428fSJakub Kicinski while (true) { 87752bcf80SJiri Olsa struct bpf_prog_info info = {}; 88752bcf80SJiri Olsa __u32 len = sizeof(info); 89752bcf80SJiri Olsa 9071bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 9171bb428fSJakub Kicinski if (err) { 929a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 9371bb428fSJakub Kicinski return -1; 9471bb428fSJakub Kicinski } 9571bb428fSJakub Kicinski 9671bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 9771bb428fSJakub Kicinski if (fd < 0) { 989a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 9971bb428fSJakub Kicinski id, strerror(errno)); 10071bb428fSJakub Kicinski return -1; 10171bb428fSJakub Kicinski } 10271bb428fSJakub Kicinski 10371bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 10471bb428fSJakub Kicinski if (err) { 1059a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 10671bb428fSJakub Kicinski id, strerror(errno)); 10771bb428fSJakub Kicinski close(fd); 10871bb428fSJakub Kicinski return -1; 10971bb428fSJakub Kicinski } 11071bb428fSJakub Kicinski 11171bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 11271bb428fSJakub Kicinski return fd; 11371bb428fSJakub Kicinski 11471bb428fSJakub Kicinski close(fd); 11571bb428fSJakub Kicinski } 11671bb428fSJakub Kicinski } 11771bb428fSJakub Kicinski 11871bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 11971bb428fSJakub Kicinski { 12071bb428fSJakub Kicinski int fd; 12171bb428fSJakub Kicinski 12271bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 12371bb428fSJakub Kicinski unsigned int id; 12471bb428fSJakub Kicinski char *endptr; 12571bb428fSJakub Kicinski 12671bb428fSJakub Kicinski NEXT_ARGP(); 12771bb428fSJakub Kicinski 12871bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 12971bb428fSJakub Kicinski if (*endptr) { 1309a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 13171bb428fSJakub Kicinski return -1; 13271bb428fSJakub Kicinski } 13371bb428fSJakub Kicinski NEXT_ARGP(); 13471bb428fSJakub Kicinski 13571bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 13671bb428fSJakub Kicinski if (fd < 0) 1379a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 13871bb428fSJakub Kicinski return fd; 13971bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 14071bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 14171bb428fSJakub Kicinski 14271bb428fSJakub Kicinski NEXT_ARGP(); 14371bb428fSJakub Kicinski 14471bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 14571bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 14671bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1479a5ab8bfSQuentin Monnet p_err("can't parse tag"); 14871bb428fSJakub Kicinski return -1; 14971bb428fSJakub Kicinski } 15071bb428fSJakub Kicinski NEXT_ARGP(); 15171bb428fSJakub Kicinski 15271bb428fSJakub Kicinski return prog_fd_by_tag(tag); 15371bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 15471bb428fSJakub Kicinski char *path; 15571bb428fSJakub Kicinski 15671bb428fSJakub Kicinski NEXT_ARGP(); 15771bb428fSJakub Kicinski 15871bb428fSJakub Kicinski path = **argv; 15971bb428fSJakub Kicinski NEXT_ARGP(); 16071bb428fSJakub Kicinski 16171bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 16271bb428fSJakub Kicinski } 16371bb428fSJakub Kicinski 1649a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 16571bb428fSJakub Kicinski return -1; 16671bb428fSJakub Kicinski } 16771bb428fSJakub Kicinski 16871bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 16971bb428fSJakub Kicinski { 17071bb428fSJakub Kicinski struct bpf_prog_info info = {}; 17171bb428fSJakub Kicinski __u32 len = sizeof(info); 17271bb428fSJakub Kicinski __u32 map_ids[num_maps]; 17371bb428fSJakub Kicinski unsigned int i; 17471bb428fSJakub Kicinski int err; 17571bb428fSJakub Kicinski 17671bb428fSJakub Kicinski info.nr_map_ids = num_maps; 17771bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 17871bb428fSJakub Kicinski 17971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 18071bb428fSJakub Kicinski if (err || !info.nr_map_ids) 18171bb428fSJakub Kicinski return; 18271bb428fSJakub Kicinski 183743cc665SQuentin Monnet if (json_output) { 184743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 185743cc665SQuentin Monnet jsonw_start_array(json_wtr); 186743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 187743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 188743cc665SQuentin Monnet jsonw_end_array(json_wtr); 189743cc665SQuentin Monnet } else { 19071bb428fSJakub Kicinski printf(" map_ids "); 19171bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 19271bb428fSJakub Kicinski printf("%u%s", map_ids[i], 19371bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 19471bb428fSJakub Kicinski } 19571bb428fSJakub Kicinski } 19671bb428fSJakub Kicinski 197743cc665SQuentin Monnet static void print_prog_json(struct bpf_prog_info *info, int fd) 198743cc665SQuentin Monnet { 199743cc665SQuentin Monnet char *memlock; 200743cc665SQuentin Monnet 201743cc665SQuentin Monnet jsonw_start_object(json_wtr); 202743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 203743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 204743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 205743cc665SQuentin Monnet prog_type_name[info->type]); 20671bb428fSJakub Kicinski else 207743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 20871bb428fSJakub Kicinski 209743cc665SQuentin Monnet if (*info->name) 210743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 21171bb428fSJakub Kicinski 212743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 213743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 214743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 215743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 21671bb428fSJakub Kicinski 2179b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 21888ad472bSAlexei Starovoitov if (info->run_time_ns) { 21988ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 22088ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 22188ad472bSAlexei Starovoitov } 2229b984a20SJiri Olsa 22352262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 22452262210SJakub Kicinski 225743cc665SQuentin Monnet if (info->load_time) { 22671bb428fSJakub Kicinski char buf[32]; 22771bb428fSJakub Kicinski 228743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 22971bb428fSJakub Kicinski 23071bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 231a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 232a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 233743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 23471bb428fSJakub Kicinski } 23571bb428fSJakub Kicinski 236743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 23771bb428fSJakub Kicinski 238743cc665SQuentin Monnet if (info->jited_prog_len) { 239743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 240743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 241743cc665SQuentin Monnet } else { 242743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 243743cc665SQuentin Monnet } 244743cc665SQuentin Monnet 245743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 246743cc665SQuentin Monnet if (memlock) 247743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 248743cc665SQuentin Monnet free(memlock); 249743cc665SQuentin Monnet 250743cc665SQuentin Monnet if (info->nr_map_ids) 251743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 252743cc665SQuentin Monnet 253569b0c77SPrashant Bhole if (info->btf_id) 254569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 255569b0c77SPrashant Bhole 2564990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 2574990f1f4SPrashant Bhole struct pinned_obj *obj; 2584990f1f4SPrashant Bhole 2594990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 2604990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 2614990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 2624990f1f4SPrashant Bhole if (obj->id == info->id) 2634990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 2644990f1f4SPrashant Bhole } 2654990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 2664990f1f4SPrashant Bhole } 2674990f1f4SPrashant Bhole 268743cc665SQuentin Monnet jsonw_end_object(json_wtr); 269743cc665SQuentin Monnet } 270743cc665SQuentin Monnet 271743cc665SQuentin Monnet static void print_prog_plain(struct bpf_prog_info *info, int fd) 272743cc665SQuentin Monnet { 273743cc665SQuentin Monnet char *memlock; 274743cc665SQuentin Monnet 275743cc665SQuentin Monnet printf("%u: ", info->id); 276743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 277743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 278743cc665SQuentin Monnet else 279743cc665SQuentin Monnet printf("type %u ", info->type); 280743cc665SQuentin Monnet 281743cc665SQuentin Monnet if (*info->name) 282743cc665SQuentin Monnet printf("name %s ", info->name); 283743cc665SQuentin Monnet 284743cc665SQuentin Monnet printf("tag "); 285743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 28652262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 2879b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 28888ad472bSAlexei Starovoitov if (info->run_time_ns) 28988ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 29088ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 291743cc665SQuentin Monnet printf("\n"); 292743cc665SQuentin Monnet 293743cc665SQuentin Monnet if (info->load_time) { 294743cc665SQuentin Monnet char buf[32]; 295743cc665SQuentin Monnet 296743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 297743cc665SQuentin Monnet 298743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 299743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 300743cc665SQuentin Monnet } 301743cc665SQuentin Monnet 302743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 303743cc665SQuentin Monnet 304743cc665SQuentin Monnet if (info->jited_prog_len) 305743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 30671bb428fSJakub Kicinski else 30771bb428fSJakub Kicinski printf(" not jited"); 30871bb428fSJakub Kicinski 30971bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 31071bb428fSJakub Kicinski if (memlock) 31171bb428fSJakub Kicinski printf(" memlock %sB", memlock); 31271bb428fSJakub Kicinski free(memlock); 31371bb428fSJakub Kicinski 314743cc665SQuentin Monnet if (info->nr_map_ids) 315743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 31671bb428fSJakub Kicinski 3174990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3184990f1f4SPrashant Bhole struct pinned_obj *obj; 3194990f1f4SPrashant Bhole 3204990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3214990f1f4SPrashant Bhole if (obj->id == info->id) 322a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 3234990f1f4SPrashant Bhole } 3244990f1f4SPrashant Bhole } 3254990f1f4SPrashant Bhole 326569b0c77SPrashant Bhole if (info->btf_id) 327031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 328569b0c77SPrashant Bhole 32971bb428fSJakub Kicinski printf("\n"); 330743cc665SQuentin Monnet } 331743cc665SQuentin Monnet 332743cc665SQuentin Monnet static int show_prog(int fd) 333743cc665SQuentin Monnet { 334743cc665SQuentin Monnet struct bpf_prog_info info = {}; 335743cc665SQuentin Monnet __u32 len = sizeof(info); 336743cc665SQuentin Monnet int err; 337743cc665SQuentin Monnet 338743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 339743cc665SQuentin Monnet if (err) { 3409a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 341743cc665SQuentin Monnet return -1; 342743cc665SQuentin Monnet } 343743cc665SQuentin Monnet 344743cc665SQuentin Monnet if (json_output) 345743cc665SQuentin Monnet print_prog_json(&info, fd); 346743cc665SQuentin Monnet else 347743cc665SQuentin Monnet print_prog_plain(&info, fd); 34871bb428fSJakub Kicinski 34971bb428fSJakub Kicinski return 0; 35071bb428fSJakub Kicinski } 35171bb428fSJakub Kicinski 35271bb428fSJakub Kicinski static int do_show(int argc, char **argv) 353743cc665SQuentin Monnet { 354743cc665SQuentin Monnet __u32 id = 0; 35571bb428fSJakub Kicinski int err; 35671bb428fSJakub Kicinski int fd; 35771bb428fSJakub Kicinski 358c541b734SPrashant Bhole if (show_pinned) 3594990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 3604990f1f4SPrashant Bhole 36171bb428fSJakub Kicinski if (argc == 2) { 36271bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 36371bb428fSJakub Kicinski if (fd < 0) 36471bb428fSJakub Kicinski return -1; 36571bb428fSJakub Kicinski 36671bb428fSJakub Kicinski return show_prog(fd); 36771bb428fSJakub Kicinski } 36871bb428fSJakub Kicinski 36971bb428fSJakub Kicinski if (argc) 37071bb428fSJakub Kicinski return BAD_ARG(); 37171bb428fSJakub Kicinski 372743cc665SQuentin Monnet if (json_output) 373743cc665SQuentin Monnet jsonw_start_array(json_wtr); 37471bb428fSJakub Kicinski while (true) { 37571bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 37671bb428fSJakub Kicinski if (err) { 3771739c26dSQuentin Monnet if (errno == ENOENT) { 3781739c26dSQuentin Monnet err = 0; 37971bb428fSJakub Kicinski break; 3801739c26dSQuentin Monnet } 3819a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 3829a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 383743cc665SQuentin Monnet err = -1; 384743cc665SQuentin Monnet break; 38571bb428fSJakub Kicinski } 38671bb428fSJakub Kicinski 38771bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 38871bb428fSJakub Kicinski if (fd < 0) { 3898207c6ddSJakub Kicinski if (errno == ENOENT) 3908207c6ddSJakub Kicinski continue; 3919a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 39271bb428fSJakub Kicinski id, strerror(errno)); 393743cc665SQuentin Monnet err = -1; 394743cc665SQuentin Monnet break; 39571bb428fSJakub Kicinski } 39671bb428fSJakub Kicinski 39771bb428fSJakub Kicinski err = show_prog(fd); 39871bb428fSJakub Kicinski close(fd); 39971bb428fSJakub Kicinski if (err) 400743cc665SQuentin Monnet break; 40171bb428fSJakub Kicinski } 40271bb428fSJakub Kicinski 403743cc665SQuentin Monnet if (json_output) 404743cc665SQuentin Monnet jsonw_end_array(json_wtr); 405743cc665SQuentin Monnet 406743cc665SQuentin Monnet return err; 40771bb428fSJakub Kicinski } 40871bb428fSJakub Kicinski 40971bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 41071bb428fSJakub Kicinski { 411cae73f23SSong Liu struct bpf_prog_info_linear *info_linear; 412b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 413cae73f23SSong Liu enum {DUMP_JITED, DUMP_XLATED} mode; 4143ddeac67SJakub Kicinski const char *disasm_opt = NULL; 415cae73f23SSong Liu struct bpf_prog_info *info; 4167105e828SDaniel Borkmann struct dump_data dd = {}; 417cae73f23SSong Liu void *func_info = NULL; 418254471e5SYonghong Song struct btf *btf = NULL; 41971bb428fSJakub Kicinski char *filepath = NULL; 42071bb428fSJakub Kicinski bool opcodes = false; 421b6c1cedbSJiong Wang bool visual = false; 422254471e5SYonghong Song char func_sig[1024]; 42371bb428fSJakub Kicinski unsigned char *buf; 424b053b439SMartin KaFai Lau bool linum = false; 425cae73f23SSong Liu __u32 member_len; 426cae73f23SSong Liu __u64 arrays; 42771bb428fSJakub Kicinski ssize_t n; 42871bb428fSJakub Kicinski int fd; 42971bb428fSJakub Kicinski 43071bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 43129a9c10eSStanislav Fomichev if (disasm_init()) 43229a9c10eSStanislav Fomichev return -1; 433cae73f23SSong Liu mode = DUMP_JITED; 43471bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 435cae73f23SSong Liu mode = DUMP_XLATED; 43671bb428fSJakub Kicinski } else { 4379a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 43871bb428fSJakub Kicinski return -1; 43971bb428fSJakub Kicinski } 44071bb428fSJakub Kicinski NEXT_ARG(); 44171bb428fSJakub Kicinski 44271bb428fSJakub Kicinski if (argc < 2) 44371bb428fSJakub Kicinski usage(); 44471bb428fSJakub Kicinski 44571bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 44671bb428fSJakub Kicinski if (fd < 0) 44771bb428fSJakub Kicinski return -1; 44871bb428fSJakub Kicinski 44971bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 45071bb428fSJakub Kicinski NEXT_ARG(); 45171bb428fSJakub Kicinski if (!argc) { 4529a5ab8bfSQuentin Monnet p_err("expected file path"); 45371bb428fSJakub Kicinski return -1; 45471bb428fSJakub Kicinski } 45571bb428fSJakub Kicinski 45671bb428fSJakub Kicinski filepath = *argv; 45771bb428fSJakub Kicinski NEXT_ARG(); 45871bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 45971bb428fSJakub Kicinski opcodes = true; 46071bb428fSJakub Kicinski NEXT_ARG(); 461b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 462b6c1cedbSJiong Wang visual = true; 463b6c1cedbSJiong Wang NEXT_ARG(); 464b053b439SMartin KaFai Lau } else if (is_prefix(*argv, "linum")) { 465b053b439SMartin KaFai Lau linum = true; 466b053b439SMartin KaFai Lau NEXT_ARG(); 46771bb428fSJakub Kicinski } 46871bb428fSJakub Kicinski 46971bb428fSJakub Kicinski if (argc) { 47071bb428fSJakub Kicinski usage(); 47171bb428fSJakub Kicinski return -1; 47271bb428fSJakub Kicinski } 47371bb428fSJakub Kicinski 474cae73f23SSong Liu if (mode == DUMP_JITED) 475cae73f23SSong Liu arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 476cae73f23SSong Liu else 477cae73f23SSong Liu arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 478cae73f23SSong Liu 479cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 480cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 481cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 482cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 483cae73f23SSong Liu arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 484cae73f23SSong Liu 485cae73f23SSong Liu info_linear = bpf_program__get_prog_info_linear(fd, arrays); 486cae73f23SSong Liu close(fd); 487cae73f23SSong Liu if (IS_ERR_OR_NULL(info_linear)) { 4889a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 48971bb428fSJakub Kicinski return -1; 49071bb428fSJakub Kicinski } 49171bb428fSJakub Kicinski 492cae73f23SSong Liu info = &info_linear->info; 493cae73f23SSong Liu if (mode == DUMP_JITED) { 494cae73f23SSong Liu if (info->jited_prog_len == 0) { 4959a5ab8bfSQuentin Monnet p_info("no instructions returned"); 496f84192eeSSandipan Das goto err_free; 497f84192eeSSandipan Das } 498cae73f23SSong Liu buf = (unsigned char *)(info->jited_prog_insns); 499cae73f23SSong Liu member_len = info->jited_prog_len; 500cae73f23SSong Liu } else { /* DUMP_XLATED */ 501cae73f23SSong Liu if (info->xlated_prog_len == 0) { 5027105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 5037105e828SDaniel Borkmann goto err_free; 5047105e828SDaniel Borkmann } 505cae73f23SSong Liu buf = (unsigned char *)info->xlated_prog_insns; 506cae73f23SSong Liu member_len = info->xlated_prog_len; 507cae73f23SSong Liu } 5087105e828SDaniel Borkmann 509cae73f23SSong Liu if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 510254471e5SYonghong Song p_err("failed to get btf"); 511254471e5SYonghong Song goto err_free; 512254471e5SYonghong Song } 513254471e5SYonghong Song 514cae73f23SSong Liu func_info = (void *)info->func_info; 515cae73f23SSong Liu 516cae73f23SSong Liu if (info->nr_line_info) { 517cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 518b053b439SMartin KaFai Lau if (!prog_linfo) 51910a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 520b053b439SMartin KaFai Lau } 521b053b439SMartin KaFai Lau 52271bb428fSJakub Kicinski if (filepath) { 52371bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 52471bb428fSJakub Kicinski if (fd < 0) { 5259a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 52671bb428fSJakub Kicinski strerror(errno)); 52771bb428fSJakub Kicinski goto err_free; 52871bb428fSJakub Kicinski } 52971bb428fSJakub Kicinski 530cae73f23SSong Liu n = write(fd, buf, member_len); 53171bb428fSJakub Kicinski close(fd); 532cae73f23SSong Liu if (n != member_len) { 5339a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 53471bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 53571bb428fSJakub Kicinski goto err_free; 53671bb428fSJakub Kicinski } 53752c84d36SQuentin Monnet 53852c84d36SQuentin Monnet if (json_output) 53952c84d36SQuentin Monnet jsonw_null(json_wtr); 540cae73f23SSong Liu } else if (mode == DUMP_JITED) { 541e6593596SJiong Wang const char *name = NULL; 542e6593596SJiong Wang 543cae73f23SSong Liu if (info->ifindex) { 544cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 545cae73f23SSong Liu info->netns_dev, 546cae73f23SSong Liu info->netns_ino, 5473ddeac67SJakub Kicinski &disasm_opt); 548e6593596SJiong Wang if (!name) 549e6593596SJiong Wang goto err_free; 550e6593596SJiong Wang } 551e6593596SJiong Wang 552cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 553f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 554254471e5SYonghong Song struct bpf_func_info *record; 555f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 556f7f62c71SSandipan Das unsigned char *img = buf; 557f7f62c71SSandipan Das __u64 *ksyms = NULL; 558f7f62c71SSandipan Das __u32 *lens; 559f7f62c71SSandipan Das __u32 i; 560cae73f23SSong Liu if (info->nr_jited_ksyms) { 561f7f62c71SSandipan Das kernel_syms_load(&dd); 562cae73f23SSong Liu ksyms = (__u64 *) info->jited_ksyms; 563f7f62c71SSandipan Das } 564f7f62c71SSandipan Das 565f7f62c71SSandipan Das if (json_output) 566f7f62c71SSandipan Das jsonw_start_array(json_wtr); 567f7f62c71SSandipan Das 568cae73f23SSong Liu lens = (__u32 *) info->jited_func_lens; 569cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 570f7f62c71SSandipan Das if (ksyms) { 571f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 572f7f62c71SSandipan Das if (sym) 573f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 574f7f62c71SSandipan Das else 575f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 576f7f62c71SSandipan Das } else { 577f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 578f7f62c71SSandipan Das } 579f7f62c71SSandipan Das 580254471e5SYonghong Song if (func_info) { 581cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 582254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 583254471e5SYonghong Song func_sig, 584254471e5SYonghong Song sizeof(func_sig)); 585254471e5SYonghong Song } 586254471e5SYonghong Song 587f7f62c71SSandipan Das if (json_output) { 588f7f62c71SSandipan Das jsonw_start_object(json_wtr); 589254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 590254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 591254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 592254471e5SYonghong Song } 593f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 594f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 595f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 596f7f62c71SSandipan Das } else { 597254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 598254471e5SYonghong Song printf("%s:\n", func_sig); 599f7f62c71SSandipan Das printf("%s:\n", sym_name); 600f7f62c71SSandipan Das } 601f7f62c71SSandipan Das 602b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 603b053b439SMartin KaFai Lau name, disasm_opt, btf, 604b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 605b053b439SMartin KaFai Lau linum); 606b053b439SMartin KaFai Lau 607f7f62c71SSandipan Das img += lens[i]; 608f7f62c71SSandipan Das 609f7f62c71SSandipan Das if (json_output) 610f7f62c71SSandipan Das jsonw_end_object(json_wtr); 611f7f62c71SSandipan Das else 612f7f62c71SSandipan Das printf("\n"); 613f7f62c71SSandipan Das } 614f7f62c71SSandipan Das 615f7f62c71SSandipan Das if (json_output) 616f7f62c71SSandipan Das jsonw_end_array(json_wtr); 617f7f62c71SSandipan Das } else { 618cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 619b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 620f7f62c71SSandipan Das } 621b6c1cedbSJiong Wang } else if (visual) { 622b6c1cedbSJiong Wang if (json_output) 623b6c1cedbSJiong Wang jsonw_null(json_wtr); 624b6c1cedbSJiong Wang else 625cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 6267105e828SDaniel Borkmann } else { 6277105e828SDaniel Borkmann kernel_syms_load(&dd); 628cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 629cae73f23SSong Liu dd.jited_ksyms = (__u64 *) info->jited_ksyms; 630254471e5SYonghong Song dd.btf = btf; 631254471e5SYonghong Song dd.func_info = func_info; 632cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 633b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 634f84192eeSSandipan Das 635f05e2c32SQuentin Monnet if (json_output) 636cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 637b053b439SMartin KaFai Lau linum); 638f05e2c32SQuentin Monnet else 639cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 640b053b439SMartin KaFai Lau linum); 6417105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6427105e828SDaniel Borkmann } 64371bb428fSJakub Kicinski 644cae73f23SSong Liu free(info_linear); 64571bb428fSJakub Kicinski return 0; 64671bb428fSJakub Kicinski 64771bb428fSJakub Kicinski err_free: 648cae73f23SSong Liu free(info_linear); 64971bb428fSJakub Kicinski return -1; 65071bb428fSJakub Kicinski } 65171bb428fSJakub Kicinski 65271bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 65371bb428fSJakub Kicinski { 654004b45c0SQuentin Monnet int err; 655004b45c0SQuentin Monnet 656004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 657004b45c0SQuentin Monnet if (!err && json_output) 658004b45c0SQuentin Monnet jsonw_null(json_wtr); 659004b45c0SQuentin Monnet return err; 66071bb428fSJakub Kicinski } 66171bb428fSJakub Kicinski 6623ff5a4dcSJakub Kicinski struct map_replace { 6633ff5a4dcSJakub Kicinski int idx; 6643ff5a4dcSJakub Kicinski int fd; 6653ff5a4dcSJakub Kicinski char *name; 6663ff5a4dcSJakub Kicinski }; 6673ff5a4dcSJakub Kicinski 668c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 6693ff5a4dcSJakub Kicinski { 6703ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 6713ff5a4dcSJakub Kicinski 6723ff5a4dcSJakub Kicinski return a->idx - b->idx; 6733ff5a4dcSJakub Kicinski } 6743ff5a4dcSJakub Kicinski 675092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 676092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 677092f0892SStanislav Fomichev int *mapfd) 678092f0892SStanislav Fomichev { 679092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 680092f0892SStanislav Fomichev return -EINVAL; 681092f0892SStanislav Fomichev 682092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 683092f0892SStanislav Fomichev if (*progfd < 0) 684092f0892SStanislav Fomichev return *progfd; 685092f0892SStanislav Fomichev 686092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 687092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 688092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 689092f0892SStanislav Fomichev return -EINVAL; 690092f0892SStanislav Fomichev } 691092f0892SStanislav Fomichev 692092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 693092f0892SStanislav Fomichev *mapfd = -1; 694092f0892SStanislav Fomichev return 0; 695092f0892SStanislav Fomichev } 696092f0892SStanislav Fomichev 697092f0892SStanislav Fomichev NEXT_ARG(); 698092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 699092f0892SStanislav Fomichev return -EINVAL; 700092f0892SStanislav Fomichev 701092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 702092f0892SStanislav Fomichev if (*mapfd < 0) 703092f0892SStanislav Fomichev return *mapfd; 704092f0892SStanislav Fomichev 705092f0892SStanislav Fomichev return 0; 706092f0892SStanislav Fomichev } 707092f0892SStanislav Fomichev 708b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 709b7d3826cSJohn Fastabend { 710b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 711092f0892SStanislav Fomichev int err, progfd; 712092f0892SStanislav Fomichev int mapfd; 713b7d3826cSJohn Fastabend 714092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 715092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 716092f0892SStanislav Fomichev if (err) 717092f0892SStanislav Fomichev return err; 718b7d3826cSJohn Fastabend 719b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 720b7d3826cSJohn Fastabend if (err) { 721b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 722b7d3826cSJohn Fastabend return -EINVAL; 723b7d3826cSJohn Fastabend } 724b7d3826cSJohn Fastabend 725b7d3826cSJohn Fastabend if (json_output) 726b7d3826cSJohn Fastabend jsonw_null(json_wtr); 727b7d3826cSJohn Fastabend return 0; 728b7d3826cSJohn Fastabend } 729b7d3826cSJohn Fastabend 730b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 731b7d3826cSJohn Fastabend { 732b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 733092f0892SStanislav Fomichev int err, progfd; 734092f0892SStanislav Fomichev int mapfd; 735b7d3826cSJohn Fastabend 736092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 737092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 738092f0892SStanislav Fomichev if (err) 739092f0892SStanislav Fomichev return err; 740b7d3826cSJohn Fastabend 741b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 742b7d3826cSJohn Fastabend if (err) { 743b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 744b7d3826cSJohn Fastabend return -EINVAL; 745b7d3826cSJohn Fastabend } 746b7d3826cSJohn Fastabend 747b7d3826cSJohn Fastabend if (json_output) 748b7d3826cSJohn Fastabend jsonw_null(json_wtr); 749b7d3826cSJohn Fastabend return 0; 750b7d3826cSJohn Fastabend } 75177380998SStanislav Fomichev 752*ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 753*ba95c745SQuentin Monnet { 754*ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 755*ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 756*ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 757*ba95c745SQuentin Monnet return -1; 758*ba95c745SQuentin Monnet } 759*ba95c745SQuentin Monnet 760*ba95c745SQuentin Monnet return 0; 761*ba95c745SQuentin Monnet } 762*ba95c745SQuentin Monnet 763*ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 764*ba95c745SQuentin Monnet { 765*ba95c745SQuentin Monnet size_t block_size = 256; 766*ba95c745SQuentin Monnet size_t buf_size = block_size; 767*ba95c745SQuentin Monnet size_t nb_read = 0; 768*ba95c745SQuentin Monnet void *tmp; 769*ba95c745SQuentin Monnet FILE *f; 770*ba95c745SQuentin Monnet 771*ba95c745SQuentin Monnet if (!fname) { 772*ba95c745SQuentin Monnet *data_ptr = NULL; 773*ba95c745SQuentin Monnet *size = 0; 774*ba95c745SQuentin Monnet return 0; 775*ba95c745SQuentin Monnet } 776*ba95c745SQuentin Monnet 777*ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 778*ba95c745SQuentin Monnet f = stdin; 779*ba95c745SQuentin Monnet else 780*ba95c745SQuentin Monnet f = fopen(fname, "r"); 781*ba95c745SQuentin Monnet if (!f) { 782*ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 783*ba95c745SQuentin Monnet return -1; 784*ba95c745SQuentin Monnet } 785*ba95c745SQuentin Monnet 786*ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 787*ba95c745SQuentin Monnet if (!*data_ptr) { 788*ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 789*ba95c745SQuentin Monnet strerror(errno)); 790*ba95c745SQuentin Monnet goto err_fclose; 791*ba95c745SQuentin Monnet } 792*ba95c745SQuentin Monnet 793*ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 794*ba95c745SQuentin Monnet if (feof(f)) 795*ba95c745SQuentin Monnet break; 796*ba95c745SQuentin Monnet if (ferror(f)) { 797*ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 798*ba95c745SQuentin Monnet fname, strerror(errno)); 799*ba95c745SQuentin Monnet goto err_free; 800*ba95c745SQuentin Monnet } 801*ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 802*ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 803*ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 804*ba95c745SQuentin Monnet UINT32_MAX); 805*ba95c745SQuentin Monnet goto err_free; 806*ba95c745SQuentin Monnet } 807*ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 808*ba95c745SQuentin Monnet buf_size *= 2; 809*ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 810*ba95c745SQuentin Monnet if (!tmp) { 811*ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 812*ba95c745SQuentin Monnet strerror(errno)); 813*ba95c745SQuentin Monnet goto err_free; 814*ba95c745SQuentin Monnet } 815*ba95c745SQuentin Monnet *data_ptr = tmp; 816*ba95c745SQuentin Monnet } 817*ba95c745SQuentin Monnet } 818*ba95c745SQuentin Monnet if (f != stdin) 819*ba95c745SQuentin Monnet fclose(f); 820*ba95c745SQuentin Monnet 821*ba95c745SQuentin Monnet *size = nb_read; 822*ba95c745SQuentin Monnet return 0; 823*ba95c745SQuentin Monnet 824*ba95c745SQuentin Monnet err_free: 825*ba95c745SQuentin Monnet free(*data_ptr); 826*ba95c745SQuentin Monnet *data_ptr = NULL; 827*ba95c745SQuentin Monnet err_fclose: 828*ba95c745SQuentin Monnet if (f != stdin) 829*ba95c745SQuentin Monnet fclose(f); 830*ba95c745SQuentin Monnet return -1; 831*ba95c745SQuentin Monnet } 832*ba95c745SQuentin Monnet 833*ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 834*ba95c745SQuentin Monnet { 835*ba95c745SQuentin Monnet size_t i, j; 836*ba95c745SQuentin Monnet char c; 837*ba95c745SQuentin Monnet 838*ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 839*ba95c745SQuentin Monnet /* Row offset */ 840*ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 841*ba95c745SQuentin Monnet 842*ba95c745SQuentin Monnet /* Hexadecimal values */ 843*ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 844*ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 845*ba95c745SQuentin Monnet j % 2 ? " " : ""); 846*ba95c745SQuentin Monnet for (; j < i + 16; j++) 847*ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 848*ba95c745SQuentin Monnet 849*ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 850*ba95c745SQuentin Monnet fprintf(f, "| "); 851*ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 852*ba95c745SQuentin Monnet c = *(char *)(data + j); 853*ba95c745SQuentin Monnet if (c < ' ' || c > '~') 854*ba95c745SQuentin Monnet c = '.'; 855*ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 856*ba95c745SQuentin Monnet } 857*ba95c745SQuentin Monnet 858*ba95c745SQuentin Monnet fprintf(f, "\n"); 859*ba95c745SQuentin Monnet } 860*ba95c745SQuentin Monnet } 861*ba95c745SQuentin Monnet 862*ba95c745SQuentin Monnet static int 863*ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 864*ba95c745SQuentin Monnet const char *json_key) 865*ba95c745SQuentin Monnet { 866*ba95c745SQuentin Monnet size_t nb_written; 867*ba95c745SQuentin Monnet FILE *f; 868*ba95c745SQuentin Monnet 869*ba95c745SQuentin Monnet if (!fname) 870*ba95c745SQuentin Monnet return 0; 871*ba95c745SQuentin Monnet 872*ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 873*ba95c745SQuentin Monnet f = stdout; 874*ba95c745SQuentin Monnet if (json_output) { 875*ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 876*ba95c745SQuentin Monnet print_data_json(data, size); 877*ba95c745SQuentin Monnet } else { 878*ba95c745SQuentin Monnet hex_print(data, size, f); 879*ba95c745SQuentin Monnet } 880*ba95c745SQuentin Monnet return 0; 881*ba95c745SQuentin Monnet } 882*ba95c745SQuentin Monnet 883*ba95c745SQuentin Monnet f = fopen(fname, "w"); 884*ba95c745SQuentin Monnet if (!f) { 885*ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 886*ba95c745SQuentin Monnet return -1; 887*ba95c745SQuentin Monnet } 888*ba95c745SQuentin Monnet 889*ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 890*ba95c745SQuentin Monnet fclose(f); 891*ba95c745SQuentin Monnet if (nb_written != size) { 892*ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 893*ba95c745SQuentin Monnet return -1; 894*ba95c745SQuentin Monnet } 895*ba95c745SQuentin Monnet 896*ba95c745SQuentin Monnet return 0; 897*ba95c745SQuentin Monnet } 898*ba95c745SQuentin Monnet 899*ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 900*ba95c745SQuentin Monnet { 901*ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 902*ba95c745SQuentin Monnet if (!*data_ptr) { 903*ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 904*ba95c745SQuentin Monnet strerror(errno)); 905*ba95c745SQuentin Monnet return -1; 906*ba95c745SQuentin Monnet } 907*ba95c745SQuentin Monnet 908*ba95c745SQuentin Monnet return 0; 909*ba95c745SQuentin Monnet } 910*ba95c745SQuentin Monnet 911*ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 912*ba95c745SQuentin Monnet { 913*ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 914*ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 915*ba95c745SQuentin Monnet struct bpf_prog_test_run_attr test_attr = {0}; 916*ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 917*ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 918*ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 919*ba95c745SQuentin Monnet unsigned int repeat = 1; 920*ba95c745SQuentin Monnet int fd, err; 921*ba95c745SQuentin Monnet 922*ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 923*ba95c745SQuentin Monnet return -1; 924*ba95c745SQuentin Monnet 925*ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 926*ba95c745SQuentin Monnet if (fd < 0) 927*ba95c745SQuentin Monnet return -1; 928*ba95c745SQuentin Monnet 929*ba95c745SQuentin Monnet while (argc) { 930*ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 931*ba95c745SQuentin Monnet "data_size_out", NULL)) 932*ba95c745SQuentin Monnet return -1; 933*ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 934*ba95c745SQuentin Monnet "ctx_size_out", NULL)) 935*ba95c745SQuentin Monnet return -1; 936*ba95c745SQuentin Monnet 937*ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 938*ba95c745SQuentin Monnet NEXT_ARG(); 939*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 940*ba95c745SQuentin Monnet return -1; 941*ba95c745SQuentin Monnet 942*ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 943*ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 944*ba95c745SQuentin Monnet return -1; 945*ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 946*ba95c745SQuentin Monnet NEXT_ARG(); 947*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 948*ba95c745SQuentin Monnet return -1; 949*ba95c745SQuentin Monnet 950*ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 951*ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 952*ba95c745SQuentin Monnet char *endptr; 953*ba95c745SQuentin Monnet 954*ba95c745SQuentin Monnet NEXT_ARG(); 955*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 956*ba95c745SQuentin Monnet return -1; 957*ba95c745SQuentin Monnet 958*ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 959*ba95c745SQuentin Monnet if (*endptr) { 960*ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 961*ba95c745SQuentin Monnet *argv); 962*ba95c745SQuentin Monnet return -1; 963*ba95c745SQuentin Monnet } 964*ba95c745SQuentin Monnet NEXT_ARG(); 965*ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 966*ba95c745SQuentin Monnet NEXT_ARG(); 967*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 968*ba95c745SQuentin Monnet return -1; 969*ba95c745SQuentin Monnet 970*ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 971*ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 972*ba95c745SQuentin Monnet return -1; 973*ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 974*ba95c745SQuentin Monnet NEXT_ARG(); 975*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 976*ba95c745SQuentin Monnet return -1; 977*ba95c745SQuentin Monnet 978*ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 979*ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 980*ba95c745SQuentin Monnet char *endptr; 981*ba95c745SQuentin Monnet 982*ba95c745SQuentin Monnet NEXT_ARG(); 983*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 984*ba95c745SQuentin Monnet return -1; 985*ba95c745SQuentin Monnet 986*ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 987*ba95c745SQuentin Monnet if (*endptr) { 988*ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 989*ba95c745SQuentin Monnet *argv); 990*ba95c745SQuentin Monnet return -1; 991*ba95c745SQuentin Monnet } 992*ba95c745SQuentin Monnet NEXT_ARG(); 993*ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 994*ba95c745SQuentin Monnet char *endptr; 995*ba95c745SQuentin Monnet 996*ba95c745SQuentin Monnet NEXT_ARG(); 997*ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 998*ba95c745SQuentin Monnet return -1; 999*ba95c745SQuentin Monnet 1000*ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1001*ba95c745SQuentin Monnet if (*endptr) { 1002*ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1003*ba95c745SQuentin Monnet *argv); 1004*ba95c745SQuentin Monnet return -1; 1005*ba95c745SQuentin Monnet } 1006*ba95c745SQuentin Monnet NEXT_ARG(); 1007*ba95c745SQuentin Monnet } else { 1008*ba95c745SQuentin Monnet p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1009*ba95c745SQuentin Monnet *argv); 1010*ba95c745SQuentin Monnet return -1; 1011*ba95c745SQuentin Monnet } 1012*ba95c745SQuentin Monnet } 1013*ba95c745SQuentin Monnet 1014*ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1015*ba95c745SQuentin Monnet if (err) 1016*ba95c745SQuentin Monnet return -1; 1017*ba95c745SQuentin Monnet 1018*ba95c745SQuentin Monnet if (data_in) { 1019*ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1020*ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1021*ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1022*ba95c745SQuentin Monnet if (err) 1023*ba95c745SQuentin Monnet goto free_data_in; 1024*ba95c745SQuentin Monnet } 1025*ba95c745SQuentin Monnet 1026*ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1027*ba95c745SQuentin Monnet if (err) 1028*ba95c745SQuentin Monnet goto free_data_out; 1029*ba95c745SQuentin Monnet 1030*ba95c745SQuentin Monnet if (ctx_in) { 1031*ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1032*ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1033*ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1034*ba95c745SQuentin Monnet if (err) 1035*ba95c745SQuentin Monnet goto free_ctx_in; 1036*ba95c745SQuentin Monnet } 1037*ba95c745SQuentin Monnet 1038*ba95c745SQuentin Monnet test_attr.prog_fd = fd; 1039*ba95c745SQuentin Monnet test_attr.repeat = repeat; 1040*ba95c745SQuentin Monnet test_attr.data_in = data_in; 1041*ba95c745SQuentin Monnet test_attr.data_out = data_out; 1042*ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1043*ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1044*ba95c745SQuentin Monnet 1045*ba95c745SQuentin Monnet err = bpf_prog_test_run_xattr(&test_attr); 1046*ba95c745SQuentin Monnet if (err) { 1047*ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1048*ba95c745SQuentin Monnet goto free_ctx_out; 1049*ba95c745SQuentin Monnet } 1050*ba95c745SQuentin Monnet 1051*ba95c745SQuentin Monnet err = 0; 1052*ba95c745SQuentin Monnet 1053*ba95c745SQuentin Monnet if (json_output) 1054*ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1055*ba95c745SQuentin Monnet 1056*ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1057*ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1058*ba95c745SQuentin Monnet */ 1059*ba95c745SQuentin Monnet if (test_attr.data_size_out) 1060*ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1061*ba95c745SQuentin Monnet test_attr.data_size_out, 1062*ba95c745SQuentin Monnet data_fname_out, "data_out"); 1063*ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1064*ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1065*ba95c745SQuentin Monnet test_attr.ctx_size_out, 1066*ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1067*ba95c745SQuentin Monnet 1068*ba95c745SQuentin Monnet if (json_output) { 1069*ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1070*ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1071*ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1072*ba95c745SQuentin Monnet } else { 1073*ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1074*ba95c745SQuentin Monnet test_attr.retval, 1075*ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1076*ba95c745SQuentin Monnet } 1077*ba95c745SQuentin Monnet 1078*ba95c745SQuentin Monnet free_ctx_out: 1079*ba95c745SQuentin Monnet free(ctx_out); 1080*ba95c745SQuentin Monnet free_ctx_in: 1081*ba95c745SQuentin Monnet free(ctx_in); 1082*ba95c745SQuentin Monnet free_data_out: 1083*ba95c745SQuentin Monnet free(data_out); 1084*ba95c745SQuentin Monnet free_data_in: 1085*ba95c745SQuentin Monnet free(data_in); 1086*ba95c745SQuentin Monnet 1087*ba95c745SQuentin Monnet return err; 1088*ba95c745SQuentin Monnet } 1089*ba95c745SQuentin Monnet 109077380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 109149a086c2SRoman Gushchin { 109255d77807SQuentin Monnet struct bpf_object_load_attr load_attr = { 0 }; 109355d77807SQuentin Monnet struct bpf_object_open_attr open_attr = { 1094ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 1095ba6dd679SJakub Kicinski }; 109655d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 10973ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 109877380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 10993ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 11003767a94bSStanislav Fomichev const char *pinmaps = NULL; 110149a086c2SRoman Gushchin struct bpf_object *obj; 1102c8406848SJakub Kicinski struct bpf_map *map; 1103c8406848SJakub Kicinski const char *pinfile; 11043ff5a4dcSJakub Kicinski unsigned int i, j; 1105c8406848SJakub Kicinski __u32 ifindex = 0; 11063ff5a4dcSJakub Kicinski int idx, err; 110749a086c2SRoman Gushchin 11088d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 11098d1fc3deSJakub Kicinski return -1; 111055d77807SQuentin Monnet open_attr.file = GET_ARG(); 11118d1fc3deSJakub Kicinski pinfile = GET_ARG(); 111249a086c2SRoman Gushchin 1113ba6dd679SJakub Kicinski while (argc) { 111449f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 111549f2cba3SJakub Kicinski char *type; 111649f2cba3SJakub Kicinski 111749f2cba3SJakub Kicinski NEXT_ARG(); 111849f2cba3SJakub Kicinski 111955d77807SQuentin Monnet if (open_attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 112049f2cba3SJakub Kicinski p_err("program type already specified"); 11213ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 112249f2cba3SJakub Kicinski } 112349f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 11243ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 112549f2cba3SJakub Kicinski 112649f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 112749f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 112849f2cba3SJakub Kicinski if (!type) { 112949f2cba3SJakub Kicinski p_err("mem alloc failed"); 11303ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 113149f2cba3SJakub Kicinski } 113249f2cba3SJakub Kicinski *type = 0; 113349f2cba3SJakub Kicinski strcat(type, *argv); 113449f2cba3SJakub Kicinski strcat(type, "/"); 113549f2cba3SJakub Kicinski 113655d77807SQuentin Monnet err = libbpf_prog_type_by_name(type, 113755d77807SQuentin Monnet &open_attr.prog_type, 1138c8406848SJakub Kicinski &expected_attach_type); 113949f2cba3SJakub Kicinski free(type); 1140c76e4c22STaeung Song if (err < 0) 11413ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1142c76e4c22STaeung Song 114349f2cba3SJakub Kicinski NEXT_ARG(); 11443ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1145dde7011aSJakub Kicinski void *new_map_replace; 11463ff5a4dcSJakub Kicinski char *endptr, *name; 11473ff5a4dcSJakub Kicinski int fd; 11483ff5a4dcSJakub Kicinski 11493ff5a4dcSJakub Kicinski NEXT_ARG(); 11503ff5a4dcSJakub Kicinski 11513ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 11523ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 11533ff5a4dcSJakub Kicinski 11543ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 11553ff5a4dcSJakub Kicinski NEXT_ARG(); 11563ff5a4dcSJakub Kicinski 11573ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 11583ff5a4dcSJakub Kicinski if (*endptr) { 11593ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 11603ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 11613ff5a4dcSJakub Kicinski } 11623ff5a4dcSJakub Kicinski name = NULL; 11633ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 11643ff5a4dcSJakub Kicinski NEXT_ARG(); 11653ff5a4dcSJakub Kicinski 11663ff5a4dcSJakub Kicinski name = *argv; 11673ff5a4dcSJakub Kicinski idx = -1; 11683ff5a4dcSJakub Kicinski } else { 11693ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 11703ff5a4dcSJakub Kicinski *argv); 11713ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 11723ff5a4dcSJakub Kicinski } 11733ff5a4dcSJakub Kicinski NEXT_ARG(); 11743ff5a4dcSJakub Kicinski 11753ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 11763ff5a4dcSJakub Kicinski if (fd < 0) 11773ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 11783ff5a4dcSJakub Kicinski 1179dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 1180dde7011aSJakub Kicinski old_map_fds + 1, 11813ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1182dde7011aSJakub Kicinski if (!new_map_replace) { 11833ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 11843ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 11853ff5a4dcSJakub Kicinski } 1186dde7011aSJakub Kicinski map_replace = new_map_replace; 1187dde7011aSJakub Kicinski 11883ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 11893ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 11903ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 11913ff5a4dcSJakub Kicinski old_map_fds++; 119249f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1193ba6dd679SJakub Kicinski NEXT_ARG(); 1194ba6dd679SJakub Kicinski 1195c8406848SJakub Kicinski if (ifindex) { 1196ba6dd679SJakub Kicinski p_err("offload device already specified"); 11973ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1198ba6dd679SJakub Kicinski } 1199ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 12003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1201ba6dd679SJakub Kicinski 1202c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1203c8406848SJakub Kicinski if (!ifindex) { 1204ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1205ba6dd679SJakub Kicinski *argv, strerror(errno)); 12063ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1207ba6dd679SJakub Kicinski } 1208ba6dd679SJakub Kicinski NEXT_ARG(); 12093767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 12103767a94bSStanislav Fomichev NEXT_ARG(); 12113767a94bSStanislav Fomichev 12123767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 12133767a94bSStanislav Fomichev goto err_free_reuse_maps; 12143767a94bSStanislav Fomichev 12153767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1216ba6dd679SJakub Kicinski } else { 12173ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1218ba6dd679SJakub Kicinski *argv); 12193ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1220ba6dd679SJakub Kicinski } 1221ba6dd679SJakub Kicinski } 1222ba6dd679SJakub Kicinski 1223ac4e0e05SYonghong Song set_max_rlimit(); 1224ac4e0e05SYonghong Song 122555d77807SQuentin Monnet obj = __bpf_object__open_xattr(&open_attr, bpf_flags); 1226c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 1227c8406848SJakub Kicinski p_err("failed to open object file"); 12283ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 122949a086c2SRoman Gushchin } 123049a086c2SRoman Gushchin 123177380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 123255d77807SQuentin Monnet enum bpf_prog_type prog_type = open_attr.prog_type; 1233c8406848SJakub Kicinski 123455d77807SQuentin Monnet if (open_attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 123577380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1236c8406848SJakub Kicinski 123777380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 1238c8406848SJakub Kicinski &expected_attach_type); 1239c76e4c22STaeung Song if (err < 0) 1240c8406848SJakub Kicinski goto err_close_obj; 1241c8406848SJakub Kicinski } 124277380998SStanislav Fomichev 124377380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 124477380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 124577380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 124677380998SStanislav Fomichev } 1247c8406848SJakub Kicinski 12483ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 12493ff5a4dcSJakub Kicinski map_replace_compar); 12503ff5a4dcSJakub Kicinski 12513ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 12523ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 12533ff5a4dcSJakub Kicinski */ 12543ff5a4dcSJakub Kicinski j = 0; 12553ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 12563ff5a4dcSJakub Kicinski i = 0; 1257f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 12583ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 12593ff5a4dcSJakub Kicinski map_replace[j].idx = i; 12603ff5a4dcSJakub Kicinski break; 12613ff5a4dcSJakub Kicinski } 12623ff5a4dcSJakub Kicinski i++; 12633ff5a4dcSJakub Kicinski } 12643ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 12653ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 12663ff5a4dcSJakub Kicinski goto err_close_obj; 12673ff5a4dcSJakub Kicinski } 12683ff5a4dcSJakub Kicinski j++; 12693ff5a4dcSJakub Kicinski } 12703ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 12713ff5a4dcSJakub Kicinski if (j) 12723ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 12733ff5a4dcSJakub Kicinski map_replace_compar); 12743ff5a4dcSJakub Kicinski 12753ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 12763ff5a4dcSJakub Kicinski j = 0; 12773ff5a4dcSJakub Kicinski idx = 0; 1278f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 1279c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1280c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1281c8406848SJakub Kicinski 12823ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 12833ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 12843ff5a4dcSJakub Kicinski if (err) { 12853ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 12863ff5a4dcSJakub Kicinski goto err_close_obj; 12873ff5a4dcSJakub Kicinski } 12883ff5a4dcSJakub Kicinski 12893ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 12903ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 12913ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 12923ff5a4dcSJakub Kicinski idx); 12933ff5a4dcSJakub Kicinski goto err_close_obj; 12943ff5a4dcSJakub Kicinski } 12953ff5a4dcSJakub Kicinski } 12963ff5a4dcSJakub Kicinski 12973ff5a4dcSJakub Kicinski idx++; 12983ff5a4dcSJakub Kicinski } 12993ff5a4dcSJakub Kicinski if (j < old_map_fds) { 13003ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 13013ff5a4dcSJakub Kicinski goto err_close_obj; 13023ff5a4dcSJakub Kicinski } 13033ff5a4dcSJakub Kicinski 130455d77807SQuentin Monnet load_attr.obj = obj; 130555d77807SQuentin Monnet if (verifier_logs) 130655d77807SQuentin Monnet /* log_level1 + log_level2 + stats, but not stable UAPI */ 130755d77807SQuentin Monnet load_attr.log_level = 1 + 2 + 4; 130855d77807SQuentin Monnet 130955d77807SQuentin Monnet err = bpf_object__load_xattr(&load_attr); 1310c8406848SJakub Kicinski if (err) { 1311c8406848SJakub Kicinski p_err("failed to load object file"); 1312c8406848SJakub Kicinski goto err_close_obj; 1313c8406848SJakub Kicinski } 1314c8406848SJakub Kicinski 131577380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 131677380998SStanislav Fomichev if (err) 1317bfee71fbSJakub Kicinski goto err_close_obj; 131849a086c2SRoman Gushchin 131977380998SStanislav Fomichev if (first_prog_only) { 132077380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 132177380998SStanislav Fomichev if (!prog) { 132277380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 132377380998SStanislav Fomichev goto err_close_obj; 132477380998SStanislav Fomichev } 132577380998SStanislav Fomichev 132677380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 132777380998SStanislav Fomichev if (err) { 132877380998SStanislav Fomichev p_err("failed to pin program %s", 132977380998SStanislav Fomichev bpf_program__title(prog, false)); 133077380998SStanislav Fomichev goto err_close_obj; 133177380998SStanislav Fomichev } 133277380998SStanislav Fomichev } else { 133377380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 133477380998SStanislav Fomichev if (err) { 133577380998SStanislav Fomichev p_err("failed to pin all programs"); 133677380998SStanislav Fomichev goto err_close_obj; 133777380998SStanislav Fomichev } 133877380998SStanislav Fomichev } 133977380998SStanislav Fomichev 13403767a94bSStanislav Fomichev if (pinmaps) { 13413767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 13423767a94bSStanislav Fomichev if (err) { 13433767a94bSStanislav Fomichev p_err("failed to pin all maps"); 13443767a94bSStanislav Fomichev goto err_unpin; 13453767a94bSStanislav Fomichev } 13463767a94bSStanislav Fomichev } 13473767a94bSStanislav Fomichev 134849a086c2SRoman Gushchin if (json_output) 134949a086c2SRoman Gushchin jsonw_null(json_wtr); 135049a086c2SRoman Gushchin 1351bfee71fbSJakub Kicinski bpf_object__close(obj); 13523ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 13533ff5a4dcSJakub Kicinski close(map_replace[i].fd); 13543ff5a4dcSJakub Kicinski free(map_replace); 1355bfee71fbSJakub Kicinski 135649a086c2SRoman Gushchin return 0; 1357bfee71fbSJakub Kicinski 13583767a94bSStanislav Fomichev err_unpin: 13593767a94bSStanislav Fomichev if (first_prog_only) 13603767a94bSStanislav Fomichev unlink(pinfile); 13613767a94bSStanislav Fomichev else 13623767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1363bfee71fbSJakub Kicinski err_close_obj: 1364bfee71fbSJakub Kicinski bpf_object__close(obj); 13653ff5a4dcSJakub Kicinski err_free_reuse_maps: 13663ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 13673ff5a4dcSJakub Kicinski close(map_replace[i].fd); 13683ff5a4dcSJakub Kicinski free(map_replace); 1369bfee71fbSJakub Kicinski return -1; 137049a086c2SRoman Gushchin } 137149a086c2SRoman Gushchin 137277380998SStanislav Fomichev static int do_load(int argc, char **argv) 137377380998SStanislav Fomichev { 137477380998SStanislav Fomichev return load_with_options(argc, argv, true); 137577380998SStanislav Fomichev } 137677380998SStanislav Fomichev 137777380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 137877380998SStanislav Fomichev { 137977380998SStanislav Fomichev return load_with_options(argc, argv, false); 138077380998SStanislav Fomichev } 138177380998SStanislav Fomichev 138271bb428fSJakub Kicinski static int do_help(int argc, char **argv) 138371bb428fSJakub Kicinski { 1384004b45c0SQuentin Monnet if (json_output) { 1385004b45c0SQuentin Monnet jsonw_null(json_wtr); 1386004b45c0SQuentin Monnet return 0; 1387004b45c0SQuentin Monnet } 1388004b45c0SQuentin Monnet 138971bb428fSJakub Kicinski fprintf(stderr, 13906ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1391b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1392b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 139371bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 139477380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 139577380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 13963767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 13973767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1398092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1399092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1400*ba95c745SQuentin Monnet " %s %s run PROG \\\n" 1401*ba95c745SQuentin Monnet " data_in FILE \\\n" 1402*ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 1403*ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1404*ba95c745SQuentin Monnet " [repeat N]\n" 140530da46b5SQuentin Monnet " %s %s tracelog\n" 140671bb428fSJakub Kicinski " %s %s help\n" 140771bb428fSJakub Kicinski "\n" 14083ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 140971bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 141049f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 141149f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 141249f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 141349f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1414f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 141549f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 141649f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1417000aa125SDaniel Borkmann " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1418f6d08d9dSStanislav Fomichev " cgroup/recvmsg6 | cgroup/getsockopt |\n" 1419f6d08d9dSStanislav Fomichev " cgroup/setsockopt }\n" 1420a5d9265eSAlban Crequy " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1421092f0892SStanislav Fomichev " flow_dissector }\n" 14220641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 142371bb428fSJakub Kicinski "", 142471bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1425b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1426*ba95c745SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1427*ba95c745SQuentin Monnet bin_name, argv[-2]); 142871bb428fSJakub Kicinski 142971bb428fSJakub Kicinski return 0; 143071bb428fSJakub Kicinski } 143171bb428fSJakub Kicinski 143271bb428fSJakub Kicinski static const struct cmd cmds[] = { 143371bb428fSJakub Kicinski { "show", do_show }, 14346ebe6dbdSJakub Kicinski { "list", do_show }, 14359f606179SQuentin Monnet { "help", do_help }, 143671bb428fSJakub Kicinski { "dump", do_dump }, 143771bb428fSJakub Kicinski { "pin", do_pin }, 143849a086c2SRoman Gushchin { "load", do_load }, 143977380998SStanislav Fomichev { "loadall", do_loadall }, 1440b7d3826cSJohn Fastabend { "attach", do_attach }, 1441b7d3826cSJohn Fastabend { "detach", do_detach }, 144230da46b5SQuentin Monnet { "tracelog", do_tracelog }, 1443*ba95c745SQuentin Monnet { "run", do_run }, 144471bb428fSJakub Kicinski { 0 } 144571bb428fSJakub Kicinski }; 144671bb428fSJakub Kicinski 144771bb428fSJakub Kicinski int do_prog(int argc, char **argv) 144871bb428fSJakub Kicinski { 144971bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 145071bb428fSJakub Kicinski } 1451