171bb428fSJakub Kicinski /* 271e07ddcSJakub Kicinski * Copyright (C) 2017-2018 Netronome Systems, Inc. 371bb428fSJakub Kicinski * 471bb428fSJakub Kicinski * This software is dual licensed under the GNU General License Version 2, 571bb428fSJakub Kicinski * June 1991 as shown in the file COPYING in the top-level directory of this 671bb428fSJakub Kicinski * source tree or the BSD 2-Clause License provided below. You have the 771bb428fSJakub Kicinski * option to license this software under the complete terms of either license. 871bb428fSJakub Kicinski * 971bb428fSJakub Kicinski * The BSD 2-Clause License: 1071bb428fSJakub Kicinski * 1171bb428fSJakub Kicinski * Redistribution and use in source and binary forms, with or 1271bb428fSJakub Kicinski * without modification, are permitted provided that the following 1371bb428fSJakub Kicinski * conditions are met: 1471bb428fSJakub Kicinski * 1571bb428fSJakub Kicinski * 1. Redistributions of source code must retain the above 1671bb428fSJakub Kicinski * copyright notice, this list of conditions and the following 1771bb428fSJakub Kicinski * disclaimer. 1871bb428fSJakub Kicinski * 1971bb428fSJakub Kicinski * 2. Redistributions in binary form must reproduce the above 2071bb428fSJakub Kicinski * copyright notice, this list of conditions and the following 2171bb428fSJakub Kicinski * disclaimer in the documentation and/or other materials 2271bb428fSJakub Kicinski * provided with the distribution. 2371bb428fSJakub Kicinski * 2471bb428fSJakub Kicinski * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2571bb428fSJakub Kicinski * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2671bb428fSJakub Kicinski * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2771bb428fSJakub Kicinski * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2871bb428fSJakub Kicinski * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2971bb428fSJakub Kicinski * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3071bb428fSJakub Kicinski * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3171bb428fSJakub Kicinski * SOFTWARE. 3271bb428fSJakub Kicinski */ 3371bb428fSJakub Kicinski 343ff5a4dcSJakub Kicinski #define _GNU_SOURCE 3571bb428fSJakub Kicinski #include <errno.h> 3671bb428fSJakub Kicinski #include <fcntl.h> 37c9c35995SJakub Kicinski #include <stdarg.h> 3871bb428fSJakub Kicinski #include <stdio.h> 3971bb428fSJakub Kicinski #include <stdlib.h> 4071bb428fSJakub Kicinski #include <string.h> 4171bb428fSJakub Kicinski #include <time.h> 4271bb428fSJakub Kicinski #include <unistd.h> 43ba6dd679SJakub Kicinski #include <net/if.h> 4471bb428fSJakub Kicinski #include <sys/types.h> 4571bb428fSJakub Kicinski #include <sys/stat.h> 4671bb428fSJakub Kicinski 47c8406848SJakub Kicinski #include <linux/err.h> 48c8406848SJakub Kicinski 4971bb428fSJakub Kicinski #include <bpf.h> 50254471e5SYonghong Song #include <btf.h> 5149a086c2SRoman Gushchin #include <libbpf.h> 5271bb428fSJakub Kicinski 53b6c1cedbSJiong Wang #include "cfg.h" 5471bb428fSJakub Kicinski #include "main.h" 5573bb5b4fSJiong Wang #include "xlated_dumper.h" 5671bb428fSJakub Kicinski 57b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 58b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 59b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 60b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 61092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 62b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 63b7d3826cSJohn Fastabend }; 64b7d3826cSJohn Fastabend 65b7d3826cSJohn Fastabend enum bpf_attach_type parse_attach_type(const char *str) 66b7d3826cSJohn Fastabend { 67b7d3826cSJohn Fastabend enum bpf_attach_type type; 68b7d3826cSJohn Fastabend 69b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 70b7d3826cSJohn Fastabend if (attach_type_strings[type] && 71b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 72b7d3826cSJohn Fastabend return type; 73b7d3826cSJohn Fastabend } 74b7d3826cSJohn Fastabend 75b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 76b7d3826cSJohn Fastabend } 77b7d3826cSJohn Fastabend 7871bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 7971bb428fSJakub Kicinski { 8071bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 8171bb428fSJakub Kicinski time_t wallclock_secs; 8271bb428fSJakub Kicinski struct tm load_tm; 8371bb428fSJakub Kicinski 8471bb428fSJakub Kicinski buf[--size] = '\0'; 8571bb428fSJakub Kicinski 8671bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 8771bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 8871bb428fSJakub Kicinski perror("Can't read clocks"); 8971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 9071bb428fSJakub Kicinski return; 9171bb428fSJakub Kicinski } 9271bb428fSJakub Kicinski 9371bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 9407480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 9507480cbcSJakub Kicinski 1000000000; 9607480cbcSJakub Kicinski 9771bb428fSJakub Kicinski 9871bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 9971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 10071bb428fSJakub Kicinski return; 10171bb428fSJakub Kicinski } 10271bb428fSJakub Kicinski 103a3fe1f6fSQuentin Monnet if (json_output) 104a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 105a3fe1f6fSQuentin Monnet else 106a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 10771bb428fSJakub Kicinski } 10871bb428fSJakub Kicinski 10971bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 11071bb428fSJakub Kicinski { 11171bb428fSJakub Kicinski struct bpf_prog_info info = {}; 11271bb428fSJakub Kicinski __u32 len = sizeof(info); 11371bb428fSJakub Kicinski unsigned int id = 0; 11471bb428fSJakub Kicinski int err; 11571bb428fSJakub Kicinski int fd; 11671bb428fSJakub Kicinski 11771bb428fSJakub Kicinski while (true) { 11871bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 11971bb428fSJakub Kicinski if (err) { 1209a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 12171bb428fSJakub Kicinski return -1; 12271bb428fSJakub Kicinski } 12371bb428fSJakub Kicinski 12471bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 12571bb428fSJakub Kicinski if (fd < 0) { 1269a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 12771bb428fSJakub Kicinski id, strerror(errno)); 12871bb428fSJakub Kicinski return -1; 12971bb428fSJakub Kicinski } 13071bb428fSJakub Kicinski 13171bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 13271bb428fSJakub Kicinski if (err) { 1339a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 13471bb428fSJakub Kicinski id, strerror(errno)); 13571bb428fSJakub Kicinski close(fd); 13671bb428fSJakub Kicinski return -1; 13771bb428fSJakub Kicinski } 13871bb428fSJakub Kicinski 13971bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 14071bb428fSJakub Kicinski return fd; 14171bb428fSJakub Kicinski 14271bb428fSJakub Kicinski close(fd); 14371bb428fSJakub Kicinski } 14471bb428fSJakub Kicinski } 14571bb428fSJakub Kicinski 14671bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 14771bb428fSJakub Kicinski { 14871bb428fSJakub Kicinski int fd; 14971bb428fSJakub Kicinski 15071bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 15171bb428fSJakub Kicinski unsigned int id; 15271bb428fSJakub Kicinski char *endptr; 15371bb428fSJakub Kicinski 15471bb428fSJakub Kicinski NEXT_ARGP(); 15571bb428fSJakub Kicinski 15671bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 15771bb428fSJakub Kicinski if (*endptr) { 1589a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 15971bb428fSJakub Kicinski return -1; 16071bb428fSJakub Kicinski } 16171bb428fSJakub Kicinski NEXT_ARGP(); 16271bb428fSJakub Kicinski 16371bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 16471bb428fSJakub Kicinski if (fd < 0) 1659a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 16671bb428fSJakub Kicinski return fd; 16771bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 16871bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 16971bb428fSJakub Kicinski 17071bb428fSJakub Kicinski NEXT_ARGP(); 17171bb428fSJakub Kicinski 17271bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 17371bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 17471bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1759a5ab8bfSQuentin Monnet p_err("can't parse tag"); 17671bb428fSJakub Kicinski return -1; 17771bb428fSJakub Kicinski } 17871bb428fSJakub Kicinski NEXT_ARGP(); 17971bb428fSJakub Kicinski 18071bb428fSJakub Kicinski return prog_fd_by_tag(tag); 18171bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 18271bb428fSJakub Kicinski char *path; 18371bb428fSJakub Kicinski 18471bb428fSJakub Kicinski NEXT_ARGP(); 18571bb428fSJakub Kicinski 18671bb428fSJakub Kicinski path = **argv; 18771bb428fSJakub Kicinski NEXT_ARGP(); 18871bb428fSJakub Kicinski 18971bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 19071bb428fSJakub Kicinski } 19171bb428fSJakub Kicinski 1929a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 19371bb428fSJakub Kicinski return -1; 19471bb428fSJakub Kicinski } 19571bb428fSJakub Kicinski 19671bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 19771bb428fSJakub Kicinski { 19871bb428fSJakub Kicinski struct bpf_prog_info info = {}; 19971bb428fSJakub Kicinski __u32 len = sizeof(info); 20071bb428fSJakub Kicinski __u32 map_ids[num_maps]; 20171bb428fSJakub Kicinski unsigned int i; 20271bb428fSJakub Kicinski int err; 20371bb428fSJakub Kicinski 20471bb428fSJakub Kicinski info.nr_map_ids = num_maps; 20571bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 20671bb428fSJakub Kicinski 20771bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 20871bb428fSJakub Kicinski if (err || !info.nr_map_ids) 20971bb428fSJakub Kicinski return; 21071bb428fSJakub Kicinski 211743cc665SQuentin Monnet if (json_output) { 212743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 213743cc665SQuentin Monnet jsonw_start_array(json_wtr); 214743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 215743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 216743cc665SQuentin Monnet jsonw_end_array(json_wtr); 217743cc665SQuentin Monnet } else { 21871bb428fSJakub Kicinski printf(" map_ids "); 21971bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 22071bb428fSJakub Kicinski printf("%u%s", map_ids[i], 22171bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 22271bb428fSJakub Kicinski } 22371bb428fSJakub Kicinski } 22471bb428fSJakub Kicinski 225743cc665SQuentin Monnet static void print_prog_json(struct bpf_prog_info *info, int fd) 226743cc665SQuentin Monnet { 227743cc665SQuentin Monnet char *memlock; 228743cc665SQuentin Monnet 229743cc665SQuentin Monnet jsonw_start_object(json_wtr); 230743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 231743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 232743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 233743cc665SQuentin Monnet prog_type_name[info->type]); 23471bb428fSJakub Kicinski else 235743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 23671bb428fSJakub Kicinski 237743cc665SQuentin Monnet if (*info->name) 238743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 23971bb428fSJakub Kicinski 240743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 241743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 242743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 243743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 24471bb428fSJakub Kicinski 2459b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 2469b984a20SJiri Olsa 24752262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 24852262210SJakub Kicinski 249743cc665SQuentin Monnet if (info->load_time) { 25071bb428fSJakub Kicinski char buf[32]; 25171bb428fSJakub Kicinski 252743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 25371bb428fSJakub Kicinski 25471bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 255a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 256a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 257743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 25871bb428fSJakub Kicinski } 25971bb428fSJakub Kicinski 260743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 26171bb428fSJakub Kicinski 262743cc665SQuentin Monnet if (info->jited_prog_len) { 263743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 264743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 265743cc665SQuentin Monnet } else { 266743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 267743cc665SQuentin Monnet } 268743cc665SQuentin Monnet 269743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 270743cc665SQuentin Monnet if (memlock) 271743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 272743cc665SQuentin Monnet free(memlock); 273743cc665SQuentin Monnet 274743cc665SQuentin Monnet if (info->nr_map_ids) 275743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 276743cc665SQuentin Monnet 2774990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 2784990f1f4SPrashant Bhole struct pinned_obj *obj; 2794990f1f4SPrashant Bhole 2804990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 2814990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 2824990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 2834990f1f4SPrashant Bhole if (obj->id == info->id) 2844990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 2854990f1f4SPrashant Bhole } 2864990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 2874990f1f4SPrashant Bhole } 2884990f1f4SPrashant Bhole 289743cc665SQuentin Monnet jsonw_end_object(json_wtr); 290743cc665SQuentin Monnet } 291743cc665SQuentin Monnet 292743cc665SQuentin Monnet static void print_prog_plain(struct bpf_prog_info *info, int fd) 293743cc665SQuentin Monnet { 294743cc665SQuentin Monnet char *memlock; 295743cc665SQuentin Monnet 296743cc665SQuentin Monnet printf("%u: ", info->id); 297743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 298743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 299743cc665SQuentin Monnet else 300743cc665SQuentin Monnet printf("type %u ", info->type); 301743cc665SQuentin Monnet 302743cc665SQuentin Monnet if (*info->name) 303743cc665SQuentin Monnet printf("name %s ", info->name); 304743cc665SQuentin Monnet 305743cc665SQuentin Monnet printf("tag "); 306743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 30752262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 3089b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 309743cc665SQuentin Monnet printf("\n"); 310743cc665SQuentin Monnet 311743cc665SQuentin Monnet if (info->load_time) { 312743cc665SQuentin Monnet char buf[32]; 313743cc665SQuentin Monnet 314743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 315743cc665SQuentin Monnet 316743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 317743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 318743cc665SQuentin Monnet } 319743cc665SQuentin Monnet 320743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 321743cc665SQuentin Monnet 322743cc665SQuentin Monnet if (info->jited_prog_len) 323743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 32471bb428fSJakub Kicinski else 32571bb428fSJakub Kicinski printf(" not jited"); 32671bb428fSJakub Kicinski 32771bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 32871bb428fSJakub Kicinski if (memlock) 32971bb428fSJakub Kicinski printf(" memlock %sB", memlock); 33071bb428fSJakub Kicinski free(memlock); 33171bb428fSJakub Kicinski 332743cc665SQuentin Monnet if (info->nr_map_ids) 333743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 33471bb428fSJakub Kicinski 3354990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3364990f1f4SPrashant Bhole struct pinned_obj *obj; 3374990f1f4SPrashant Bhole 3384990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3394990f1f4SPrashant Bhole if (obj->id == info->id) 340a8bfd2bcSQuentin Monnet printf("\n\tpinned %s", obj->path); 3414990f1f4SPrashant Bhole } 3424990f1f4SPrashant Bhole } 3434990f1f4SPrashant Bhole 34471bb428fSJakub Kicinski printf("\n"); 345743cc665SQuentin Monnet } 346743cc665SQuentin Monnet 347743cc665SQuentin Monnet static int show_prog(int fd) 348743cc665SQuentin Monnet { 349743cc665SQuentin Monnet struct bpf_prog_info info = {}; 350743cc665SQuentin Monnet __u32 len = sizeof(info); 351743cc665SQuentin Monnet int err; 352743cc665SQuentin Monnet 353743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 354743cc665SQuentin Monnet if (err) { 3559a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 356743cc665SQuentin Monnet return -1; 357743cc665SQuentin Monnet } 358743cc665SQuentin Monnet 359743cc665SQuentin Monnet if (json_output) 360743cc665SQuentin Monnet print_prog_json(&info, fd); 361743cc665SQuentin Monnet else 362743cc665SQuentin Monnet print_prog_plain(&info, fd); 36371bb428fSJakub Kicinski 36471bb428fSJakub Kicinski return 0; 36571bb428fSJakub Kicinski } 36671bb428fSJakub Kicinski 36771bb428fSJakub Kicinski static int do_show(int argc, char **argv) 368743cc665SQuentin Monnet { 369743cc665SQuentin Monnet __u32 id = 0; 37071bb428fSJakub Kicinski int err; 37171bb428fSJakub Kicinski int fd; 37271bb428fSJakub Kicinski 373c541b734SPrashant Bhole if (show_pinned) 3744990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 3754990f1f4SPrashant Bhole 37671bb428fSJakub Kicinski if (argc == 2) { 37771bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 37871bb428fSJakub Kicinski if (fd < 0) 37971bb428fSJakub Kicinski return -1; 38071bb428fSJakub Kicinski 38171bb428fSJakub Kicinski return show_prog(fd); 38271bb428fSJakub Kicinski } 38371bb428fSJakub Kicinski 38471bb428fSJakub Kicinski if (argc) 38571bb428fSJakub Kicinski return BAD_ARG(); 38671bb428fSJakub Kicinski 387743cc665SQuentin Monnet if (json_output) 388743cc665SQuentin Monnet jsonw_start_array(json_wtr); 38971bb428fSJakub Kicinski while (true) { 39071bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 39171bb428fSJakub Kicinski if (err) { 3921739c26dSQuentin Monnet if (errno == ENOENT) { 3931739c26dSQuentin Monnet err = 0; 39471bb428fSJakub Kicinski break; 3951739c26dSQuentin Monnet } 3969a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 3979a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 398743cc665SQuentin Monnet err = -1; 399743cc665SQuentin Monnet break; 40071bb428fSJakub Kicinski } 40171bb428fSJakub Kicinski 40271bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 40371bb428fSJakub Kicinski if (fd < 0) { 4048207c6ddSJakub Kicinski if (errno == ENOENT) 4058207c6ddSJakub Kicinski continue; 4069a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 40771bb428fSJakub Kicinski id, strerror(errno)); 408743cc665SQuentin Monnet err = -1; 409743cc665SQuentin Monnet break; 41071bb428fSJakub Kicinski } 41171bb428fSJakub Kicinski 41271bb428fSJakub Kicinski err = show_prog(fd); 41371bb428fSJakub Kicinski close(fd); 41471bb428fSJakub Kicinski if (err) 415743cc665SQuentin Monnet break; 41671bb428fSJakub Kicinski } 41771bb428fSJakub Kicinski 418743cc665SQuentin Monnet if (json_output) 419743cc665SQuentin Monnet jsonw_end_array(json_wtr); 420743cc665SQuentin Monnet 421743cc665SQuentin Monnet return err; 42271bb428fSJakub Kicinski } 42371bb428fSJakub Kicinski 42471bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 42571bb428fSJakub Kicinski { 426*b053b439SMartin KaFai Lau unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size; 427*b053b439SMartin KaFai Lau void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL; 428*b053b439SMartin KaFai Lau unsigned int finfo_cnt, linfo_cnt = 0, jited_linfo_cnt = 0; 429*b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 430f84192eeSSandipan Das unsigned long *func_ksyms = NULL; 43171bb428fSJakub Kicinski struct bpf_prog_info info = {}; 432f7f62c71SSandipan Das unsigned int *func_lens = NULL; 4333ddeac67SJakub Kicinski const char *disasm_opt = NULL; 434f84192eeSSandipan Das unsigned int nr_func_ksyms; 435f7f62c71SSandipan Das unsigned int nr_func_lens; 4367105e828SDaniel Borkmann struct dump_data dd = {}; 43771bb428fSJakub Kicinski __u32 len = sizeof(info); 438254471e5SYonghong Song struct btf *btf = NULL; 43971bb428fSJakub Kicinski unsigned int buf_size; 44071bb428fSJakub Kicinski char *filepath = NULL; 44171bb428fSJakub Kicinski bool opcodes = false; 442b6c1cedbSJiong Wang bool visual = false; 443254471e5SYonghong Song char func_sig[1024]; 44471bb428fSJakub Kicinski unsigned char *buf; 445*b053b439SMartin KaFai Lau bool linum = false; 44671bb428fSJakub Kicinski __u32 *member_len; 44771bb428fSJakub Kicinski __u64 *member_ptr; 44871bb428fSJakub Kicinski ssize_t n; 44971bb428fSJakub Kicinski int err; 45071bb428fSJakub Kicinski int fd; 45171bb428fSJakub Kicinski 45271bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 45329a9c10eSStanislav Fomichev if (disasm_init()) 45429a9c10eSStanislav Fomichev return -1; 45529a9c10eSStanislav Fomichev 45671bb428fSJakub Kicinski member_len = &info.jited_prog_len; 45771bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 45871bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 45971bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 46071bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 46171bb428fSJakub Kicinski } else { 4629a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 46371bb428fSJakub Kicinski return -1; 46471bb428fSJakub Kicinski } 46571bb428fSJakub Kicinski NEXT_ARG(); 46671bb428fSJakub Kicinski 46771bb428fSJakub Kicinski if (argc < 2) 46871bb428fSJakub Kicinski usage(); 46971bb428fSJakub Kicinski 47071bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 47171bb428fSJakub Kicinski if (fd < 0) 47271bb428fSJakub Kicinski return -1; 47371bb428fSJakub Kicinski 47471bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 47571bb428fSJakub Kicinski NEXT_ARG(); 47671bb428fSJakub Kicinski if (!argc) { 4779a5ab8bfSQuentin Monnet p_err("expected file path"); 47871bb428fSJakub Kicinski return -1; 47971bb428fSJakub Kicinski } 48071bb428fSJakub Kicinski 48171bb428fSJakub Kicinski filepath = *argv; 48271bb428fSJakub Kicinski NEXT_ARG(); 48371bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 48471bb428fSJakub Kicinski opcodes = true; 48571bb428fSJakub Kicinski NEXT_ARG(); 486b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 487b6c1cedbSJiong Wang visual = true; 488b6c1cedbSJiong Wang NEXT_ARG(); 489*b053b439SMartin KaFai Lau } else if (is_prefix(*argv, "linum")) { 490*b053b439SMartin KaFai Lau linum = true; 491*b053b439SMartin KaFai Lau NEXT_ARG(); 49271bb428fSJakub Kicinski } 49371bb428fSJakub Kicinski 49471bb428fSJakub Kicinski if (argc) { 49571bb428fSJakub Kicinski usage(); 49671bb428fSJakub Kicinski return -1; 49771bb428fSJakub Kicinski } 49871bb428fSJakub Kicinski 49971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 50071bb428fSJakub Kicinski if (err) { 5019a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 50271bb428fSJakub Kicinski return -1; 50371bb428fSJakub Kicinski } 50471bb428fSJakub Kicinski 50571bb428fSJakub Kicinski if (!*member_len) { 5069a5ab8bfSQuentin Monnet p_info("no instructions returned"); 50771bb428fSJakub Kicinski close(fd); 50871bb428fSJakub Kicinski return 0; 50971bb428fSJakub Kicinski } 51071bb428fSJakub Kicinski 51171bb428fSJakub Kicinski buf_size = *member_len; 51271bb428fSJakub Kicinski 51371bb428fSJakub Kicinski buf = malloc(buf_size); 51471bb428fSJakub Kicinski if (!buf) { 5159a5ab8bfSQuentin Monnet p_err("mem alloc failed"); 51671bb428fSJakub Kicinski close(fd); 51771bb428fSJakub Kicinski return -1; 51871bb428fSJakub Kicinski } 51971bb428fSJakub Kicinski 520f84192eeSSandipan Das nr_func_ksyms = info.nr_jited_ksyms; 521f84192eeSSandipan Das if (nr_func_ksyms) { 522f84192eeSSandipan Das func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 523f84192eeSSandipan Das if (!func_ksyms) { 524f84192eeSSandipan Das p_err("mem alloc failed"); 525f84192eeSSandipan Das close(fd); 526f84192eeSSandipan Das goto err_free; 527f84192eeSSandipan Das } 528f84192eeSSandipan Das } 529f84192eeSSandipan Das 530f7f62c71SSandipan Das nr_func_lens = info.nr_jited_func_lens; 531f7f62c71SSandipan Das if (nr_func_lens) { 532f7f62c71SSandipan Das func_lens = malloc(nr_func_lens * sizeof(__u32)); 533f7f62c71SSandipan Das if (!func_lens) { 534f7f62c71SSandipan Das p_err("mem alloc failed"); 535f7f62c71SSandipan Das close(fd); 536f7f62c71SSandipan Das goto err_free; 537f7f62c71SSandipan Das } 538f7f62c71SSandipan Das } 539f7f62c71SSandipan Das 540254471e5SYonghong Song finfo_cnt = info.func_info_cnt; 541254471e5SYonghong Song finfo_rec_size = info.func_info_rec_size; 542254471e5SYonghong Song if (finfo_cnt && finfo_rec_size) { 543254471e5SYonghong Song func_info = malloc(finfo_cnt * finfo_rec_size); 544254471e5SYonghong Song if (!func_info) { 545254471e5SYonghong Song p_err("mem alloc failed"); 546254471e5SYonghong Song close(fd); 547254471e5SYonghong Song goto err_free; 548254471e5SYonghong Song } 549254471e5SYonghong Song } 550254471e5SYonghong Song 551*b053b439SMartin KaFai Lau linfo_rec_size = info.line_info_rec_size; 552*b053b439SMartin KaFai Lau if (info.line_info_cnt && linfo_rec_size && info.btf_id) { 553*b053b439SMartin KaFai Lau linfo_cnt = info.line_info_cnt; 554*b053b439SMartin KaFai Lau linfo = malloc(linfo_cnt * linfo_rec_size); 555*b053b439SMartin KaFai Lau if (!linfo) { 556*b053b439SMartin KaFai Lau p_err("mem alloc failed"); 557*b053b439SMartin KaFai Lau close(fd); 558*b053b439SMartin KaFai Lau goto err_free; 559*b053b439SMartin KaFai Lau } 560*b053b439SMartin KaFai Lau } 561*b053b439SMartin KaFai Lau 562*b053b439SMartin KaFai Lau jited_linfo_rec_size = info.jited_line_info_rec_size; 563*b053b439SMartin KaFai Lau if (info.jited_line_info_cnt && 564*b053b439SMartin KaFai Lau jited_linfo_rec_size && 565*b053b439SMartin KaFai Lau info.nr_jited_ksyms && 566*b053b439SMartin KaFai Lau info.nr_jited_func_lens && 567*b053b439SMartin KaFai Lau info.btf_id) { 568*b053b439SMartin KaFai Lau jited_linfo_cnt = info.jited_line_info_cnt; 569*b053b439SMartin KaFai Lau jited_linfo = malloc(jited_linfo_cnt * jited_linfo_rec_size); 570*b053b439SMartin KaFai Lau if (!jited_linfo) { 571*b053b439SMartin KaFai Lau p_err("mem alloc failed"); 572*b053b439SMartin KaFai Lau close(fd); 573*b053b439SMartin KaFai Lau goto err_free; 574*b053b439SMartin KaFai Lau } 575*b053b439SMartin KaFai Lau } 576*b053b439SMartin KaFai Lau 57771bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 57871bb428fSJakub Kicinski 57971bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 58071bb428fSJakub Kicinski *member_len = buf_size; 581f84192eeSSandipan Das info.jited_ksyms = ptr_to_u64(func_ksyms); 582f84192eeSSandipan Das info.nr_jited_ksyms = nr_func_ksyms; 583f7f62c71SSandipan Das info.jited_func_lens = ptr_to_u64(func_lens); 584f7f62c71SSandipan Das info.nr_jited_func_lens = nr_func_lens; 585254471e5SYonghong Song info.func_info_cnt = finfo_cnt; 586254471e5SYonghong Song info.func_info_rec_size = finfo_rec_size; 587254471e5SYonghong Song info.func_info = ptr_to_u64(func_info); 588*b053b439SMartin KaFai Lau info.line_info_cnt = linfo_cnt; 589*b053b439SMartin KaFai Lau info.line_info_rec_size = linfo_rec_size; 590*b053b439SMartin KaFai Lau info.line_info = ptr_to_u64(linfo); 591*b053b439SMartin KaFai Lau info.jited_line_info_cnt = jited_linfo_cnt; 592*b053b439SMartin KaFai Lau info.jited_line_info_rec_size = jited_linfo_rec_size; 593*b053b439SMartin KaFai Lau info.jited_line_info = ptr_to_u64(jited_linfo); 594*b053b439SMartin KaFai Lau 59571bb428fSJakub Kicinski 59671bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 59771bb428fSJakub Kicinski close(fd); 59871bb428fSJakub Kicinski if (err) { 5999a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 60071bb428fSJakub Kicinski goto err_free; 60171bb428fSJakub Kicinski } 60271bb428fSJakub Kicinski 60371bb428fSJakub Kicinski if (*member_len > buf_size) { 6049a5ab8bfSQuentin Monnet p_err("too many instructions returned"); 60571bb428fSJakub Kicinski goto err_free; 60671bb428fSJakub Kicinski } 60771bb428fSJakub Kicinski 608f84192eeSSandipan Das if (info.nr_jited_ksyms > nr_func_ksyms) { 609f84192eeSSandipan Das p_err("too many addresses returned"); 610f84192eeSSandipan Das goto err_free; 611f84192eeSSandipan Das } 612f84192eeSSandipan Das 613f7f62c71SSandipan Das if (info.nr_jited_func_lens > nr_func_lens) { 614f7f62c71SSandipan Das p_err("too many values returned"); 615f7f62c71SSandipan Das goto err_free; 616f7f62c71SSandipan Das } 617f7f62c71SSandipan Das 618254471e5SYonghong Song if (info.func_info_cnt != finfo_cnt) { 619254471e5SYonghong Song p_err("incorrect func_info_cnt %d vs. expected %d", 620254471e5SYonghong Song info.func_info_cnt, finfo_cnt); 621254471e5SYonghong Song goto err_free; 622254471e5SYonghong Song } 623254471e5SYonghong Song 624254471e5SYonghong Song if (info.func_info_rec_size != finfo_rec_size) { 625254471e5SYonghong Song p_err("incorrect func_info_rec_size %d vs. expected %d", 626254471e5SYonghong Song info.func_info_rec_size, finfo_rec_size); 627254471e5SYonghong Song goto err_free; 628254471e5SYonghong Song } 629254471e5SYonghong Song 63084ecc1f9SMartin KaFai Lau if (func_info && !info.func_info) { 63184ecc1f9SMartin KaFai Lau /* kernel.kptr_restrict is set. No func_info available. */ 63284ecc1f9SMartin KaFai Lau free(func_info); 63384ecc1f9SMartin KaFai Lau func_info = NULL; 63484ecc1f9SMartin KaFai Lau finfo_cnt = 0; 63584ecc1f9SMartin KaFai Lau } 63684ecc1f9SMartin KaFai Lau 637*b053b439SMartin KaFai Lau if (linfo && info.line_info_cnt != linfo_cnt) { 638*b053b439SMartin KaFai Lau p_err("incorrect line_info_cnt %u vs. expected %u", 639*b053b439SMartin KaFai Lau info.line_info_cnt, linfo_cnt); 640*b053b439SMartin KaFai Lau goto err_free; 641*b053b439SMartin KaFai Lau } 642*b053b439SMartin KaFai Lau 643*b053b439SMartin KaFai Lau if (info.line_info_rec_size != linfo_rec_size) { 644*b053b439SMartin KaFai Lau p_err("incorrect line_info_rec_size %u vs. expected %u", 645*b053b439SMartin KaFai Lau info.line_info_rec_size, linfo_rec_size); 646*b053b439SMartin KaFai Lau goto err_free; 647*b053b439SMartin KaFai Lau } 648*b053b439SMartin KaFai Lau 649*b053b439SMartin KaFai Lau if (jited_linfo && info.jited_line_info_cnt != jited_linfo_cnt) { 650*b053b439SMartin KaFai Lau p_err("incorrect jited_line_info_cnt %u vs. expected %u", 651*b053b439SMartin KaFai Lau info.jited_line_info_cnt, jited_linfo_cnt); 652*b053b439SMartin KaFai Lau goto err_free; 653*b053b439SMartin KaFai Lau } 654*b053b439SMartin KaFai Lau 655*b053b439SMartin KaFai Lau if (info.jited_line_info_rec_size != jited_linfo_rec_size) { 656*b053b439SMartin KaFai Lau p_err("incorrect jited_line_info_rec_size %u vs. expected %u", 657*b053b439SMartin KaFai Lau info.jited_line_info_rec_size, jited_linfo_rec_size); 658*b053b439SMartin KaFai Lau goto err_free; 659*b053b439SMartin KaFai Lau } 660*b053b439SMartin KaFai Lau 6617105e828SDaniel Borkmann if ((member_len == &info.jited_prog_len && 6627105e828SDaniel Borkmann info.jited_prog_insns == 0) || 6637105e828SDaniel Borkmann (member_len == &info.xlated_prog_len && 6647105e828SDaniel Borkmann info.xlated_prog_insns == 0)) { 6657105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 6667105e828SDaniel Borkmann goto err_free; 6677105e828SDaniel Borkmann } 6687105e828SDaniel Borkmann 6691d2f44caSMartin KaFai Lau if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) { 670254471e5SYonghong Song p_err("failed to get btf"); 671254471e5SYonghong Song goto err_free; 672254471e5SYonghong Song } 673254471e5SYonghong Song 674*b053b439SMartin KaFai Lau if (linfo_cnt) { 675*b053b439SMartin KaFai Lau prog_linfo = bpf_prog_linfo__new(&info); 676*b053b439SMartin KaFai Lau if (!prog_linfo) 677*b053b439SMartin KaFai Lau p_err("error in processing bpf_line_info. continue without it."); 678*b053b439SMartin KaFai Lau } 679*b053b439SMartin KaFai Lau 68071bb428fSJakub Kicinski if (filepath) { 68171bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 68271bb428fSJakub Kicinski if (fd < 0) { 6839a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 68471bb428fSJakub Kicinski strerror(errno)); 68571bb428fSJakub Kicinski goto err_free; 68671bb428fSJakub Kicinski } 68771bb428fSJakub Kicinski 68871bb428fSJakub Kicinski n = write(fd, buf, *member_len); 68971bb428fSJakub Kicinski close(fd); 69071bb428fSJakub Kicinski if (n != *member_len) { 6919a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 69271bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 69371bb428fSJakub Kicinski goto err_free; 69471bb428fSJakub Kicinski } 69552c84d36SQuentin Monnet 69652c84d36SQuentin Monnet if (json_output) 69752c84d36SQuentin Monnet jsonw_null(json_wtr); 6983197239dSJiong Wang } else if (member_len == &info.jited_prog_len) { 699e6593596SJiong Wang const char *name = NULL; 700e6593596SJiong Wang 701e6593596SJiong Wang if (info.ifindex) { 7023ddeac67SJakub Kicinski name = ifindex_to_bfd_params(info.ifindex, 703e6593596SJiong Wang info.netns_dev, 7043ddeac67SJakub Kicinski info.netns_ino, 7053ddeac67SJakub Kicinski &disasm_opt); 706e6593596SJiong Wang if (!name) 707e6593596SJiong Wang goto err_free; 708e6593596SJiong Wang } 709e6593596SJiong Wang 710f7f62c71SSandipan Das if (info.nr_jited_func_lens && info.jited_func_lens) { 711f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 712254471e5SYonghong Song struct bpf_func_info *record; 713f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 714f7f62c71SSandipan Das unsigned char *img = buf; 715f7f62c71SSandipan Das __u64 *ksyms = NULL; 716f7f62c71SSandipan Das __u32 *lens; 717f7f62c71SSandipan Das __u32 i; 718f7f62c71SSandipan Das 719f7f62c71SSandipan Das if (info.nr_jited_ksyms) { 720f7f62c71SSandipan Das kernel_syms_load(&dd); 721f7f62c71SSandipan Das ksyms = (__u64 *) info.jited_ksyms; 722f7f62c71SSandipan Das } 723f7f62c71SSandipan Das 724f7f62c71SSandipan Das if (json_output) 725f7f62c71SSandipan Das jsonw_start_array(json_wtr); 726f7f62c71SSandipan Das 727f7f62c71SSandipan Das lens = (__u32 *) info.jited_func_lens; 728f7f62c71SSandipan Das for (i = 0; i < info.nr_jited_func_lens; i++) { 729f7f62c71SSandipan Das if (ksyms) { 730f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 731f7f62c71SSandipan Das if (sym) 732f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 733f7f62c71SSandipan Das else 734f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 735f7f62c71SSandipan Das } else { 736f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 737f7f62c71SSandipan Das } 738f7f62c71SSandipan Das 739254471e5SYonghong Song if (func_info) { 740254471e5SYonghong Song record = func_info + i * finfo_rec_size; 741254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 742254471e5SYonghong Song func_sig, 743254471e5SYonghong Song sizeof(func_sig)); 744254471e5SYonghong Song } 745254471e5SYonghong Song 746f7f62c71SSandipan Das if (json_output) { 747f7f62c71SSandipan Das jsonw_start_object(json_wtr); 748254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 749254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 750254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 751254471e5SYonghong Song } 752f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 753f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 754f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 755f7f62c71SSandipan Das } else { 756254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 757254471e5SYonghong Song printf("%s:\n", func_sig); 758f7f62c71SSandipan Das printf("%s:\n", sym_name); 759f7f62c71SSandipan Das } 760f7f62c71SSandipan Das 761*b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 762*b053b439SMartin KaFai Lau name, disasm_opt, btf, 763*b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 764*b053b439SMartin KaFai Lau linum); 765*b053b439SMartin KaFai Lau 766f7f62c71SSandipan Das img += lens[i]; 767f7f62c71SSandipan Das 768f7f62c71SSandipan Das if (json_output) 769f7f62c71SSandipan Das jsonw_end_object(json_wtr); 770f7f62c71SSandipan Das else 771f7f62c71SSandipan Das printf("\n"); 772f7f62c71SSandipan Das } 773f7f62c71SSandipan Das 774f7f62c71SSandipan Das if (json_output) 775f7f62c71SSandipan Das jsonw_end_array(json_wtr); 776f7f62c71SSandipan Das } else { 7773ddeac67SJakub Kicinski disasm_print_insn(buf, *member_len, opcodes, name, 778*b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 779f7f62c71SSandipan Das } 780b6c1cedbSJiong Wang } else if (visual) { 781b6c1cedbSJiong Wang if (json_output) 782b6c1cedbSJiong Wang jsonw_null(json_wtr); 783b6c1cedbSJiong Wang else 784b6c1cedbSJiong Wang dump_xlated_cfg(buf, *member_len); 7857105e828SDaniel Borkmann } else { 7867105e828SDaniel Borkmann kernel_syms_load(&dd); 787f84192eeSSandipan Das dd.nr_jited_ksyms = info.nr_jited_ksyms; 788f84192eeSSandipan Das dd.jited_ksyms = (__u64 *) info.jited_ksyms; 789254471e5SYonghong Song dd.btf = btf; 790254471e5SYonghong Song dd.func_info = func_info; 791254471e5SYonghong Song dd.finfo_rec_size = finfo_rec_size; 792*b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 793f84192eeSSandipan Das 794f05e2c32SQuentin Monnet if (json_output) 795*b053b439SMartin KaFai Lau dump_xlated_json(&dd, buf, *member_len, opcodes, 796*b053b439SMartin KaFai Lau linum); 797f05e2c32SQuentin Monnet else 798*b053b439SMartin KaFai Lau dump_xlated_plain(&dd, buf, *member_len, opcodes, 799*b053b439SMartin KaFai Lau linum); 8007105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8017105e828SDaniel Borkmann } 80271bb428fSJakub Kicinski 80371bb428fSJakub Kicinski free(buf); 804f84192eeSSandipan Das free(func_ksyms); 805f7f62c71SSandipan Das free(func_lens); 806254471e5SYonghong Song free(func_info); 807*b053b439SMartin KaFai Lau free(linfo); 808*b053b439SMartin KaFai Lau free(jited_linfo); 809*b053b439SMartin KaFai Lau bpf_prog_linfo__free(prog_linfo); 81071bb428fSJakub Kicinski return 0; 81171bb428fSJakub Kicinski 81271bb428fSJakub Kicinski err_free: 81371bb428fSJakub Kicinski free(buf); 814f84192eeSSandipan Das free(func_ksyms); 815f7f62c71SSandipan Das free(func_lens); 816254471e5SYonghong Song free(func_info); 817*b053b439SMartin KaFai Lau free(linfo); 818*b053b439SMartin KaFai Lau free(jited_linfo); 819*b053b439SMartin KaFai Lau bpf_prog_linfo__free(prog_linfo); 82071bb428fSJakub Kicinski return -1; 82171bb428fSJakub Kicinski } 82271bb428fSJakub Kicinski 82371bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 82471bb428fSJakub Kicinski { 825004b45c0SQuentin Monnet int err; 826004b45c0SQuentin Monnet 827004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 828004b45c0SQuentin Monnet if (!err && json_output) 829004b45c0SQuentin Monnet jsonw_null(json_wtr); 830004b45c0SQuentin Monnet return err; 83171bb428fSJakub Kicinski } 83271bb428fSJakub Kicinski 8333ff5a4dcSJakub Kicinski struct map_replace { 8343ff5a4dcSJakub Kicinski int idx; 8353ff5a4dcSJakub Kicinski int fd; 8363ff5a4dcSJakub Kicinski char *name; 8373ff5a4dcSJakub Kicinski }; 8383ff5a4dcSJakub Kicinski 8393ff5a4dcSJakub Kicinski int map_replace_compar(const void *p1, const void *p2) 8403ff5a4dcSJakub Kicinski { 8413ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 8423ff5a4dcSJakub Kicinski 8433ff5a4dcSJakub Kicinski return a->idx - b->idx; 8443ff5a4dcSJakub Kicinski } 8453ff5a4dcSJakub Kicinski 846092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 847092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 848092f0892SStanislav Fomichev int *mapfd) 849092f0892SStanislav Fomichev { 850092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 851092f0892SStanislav Fomichev return -EINVAL; 852092f0892SStanislav Fomichev 853092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 854092f0892SStanislav Fomichev if (*progfd < 0) 855092f0892SStanislav Fomichev return *progfd; 856092f0892SStanislav Fomichev 857092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 858092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 859092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 860092f0892SStanislav Fomichev return -EINVAL; 861092f0892SStanislav Fomichev } 862092f0892SStanislav Fomichev 863092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 864092f0892SStanislav Fomichev *mapfd = -1; 865092f0892SStanislav Fomichev return 0; 866092f0892SStanislav Fomichev } 867092f0892SStanislav Fomichev 868092f0892SStanislav Fomichev NEXT_ARG(); 869092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 870092f0892SStanislav Fomichev return -EINVAL; 871092f0892SStanislav Fomichev 872092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 873092f0892SStanislav Fomichev if (*mapfd < 0) 874092f0892SStanislav Fomichev return *mapfd; 875092f0892SStanislav Fomichev 876092f0892SStanislav Fomichev return 0; 877092f0892SStanislav Fomichev } 878092f0892SStanislav Fomichev 879b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 880b7d3826cSJohn Fastabend { 881b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 882092f0892SStanislav Fomichev int err, progfd; 883092f0892SStanislav Fomichev int mapfd; 884b7d3826cSJohn Fastabend 885092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 886092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 887092f0892SStanislav Fomichev if (err) 888092f0892SStanislav Fomichev return err; 889b7d3826cSJohn Fastabend 890b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 891b7d3826cSJohn Fastabend if (err) { 892b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 893b7d3826cSJohn Fastabend return -EINVAL; 894b7d3826cSJohn Fastabend } 895b7d3826cSJohn Fastabend 896b7d3826cSJohn Fastabend if (json_output) 897b7d3826cSJohn Fastabend jsonw_null(json_wtr); 898b7d3826cSJohn Fastabend return 0; 899b7d3826cSJohn Fastabend } 900b7d3826cSJohn Fastabend 901b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 902b7d3826cSJohn Fastabend { 903b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 904092f0892SStanislav Fomichev int err, progfd; 905092f0892SStanislav Fomichev int mapfd; 906b7d3826cSJohn Fastabend 907092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 908092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 909092f0892SStanislav Fomichev if (err) 910092f0892SStanislav Fomichev return err; 911b7d3826cSJohn Fastabend 912b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 913b7d3826cSJohn Fastabend if (err) { 914b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 915b7d3826cSJohn Fastabend return -EINVAL; 916b7d3826cSJohn Fastabend } 917b7d3826cSJohn Fastabend 918b7d3826cSJohn Fastabend if (json_output) 919b7d3826cSJohn Fastabend jsonw_null(json_wtr); 920b7d3826cSJohn Fastabend return 0; 921b7d3826cSJohn Fastabend } 92277380998SStanislav Fomichev 92377380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 92449a086c2SRoman Gushchin { 925c8406848SJakub Kicinski enum bpf_attach_type expected_attach_type; 926c8406848SJakub Kicinski struct bpf_object_open_attr attr = { 927ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 928ba6dd679SJakub Kicinski }; 9293ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 93077380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 9313ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 9323767a94bSStanislav Fomichev const char *pinmaps = NULL; 93349a086c2SRoman Gushchin struct bpf_object *obj; 934c8406848SJakub Kicinski struct bpf_map *map; 935c8406848SJakub Kicinski const char *pinfile; 9363ff5a4dcSJakub Kicinski unsigned int i, j; 937c8406848SJakub Kicinski __u32 ifindex = 0; 9383ff5a4dcSJakub Kicinski int idx, err; 93949a086c2SRoman Gushchin 9408d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 9418d1fc3deSJakub Kicinski return -1; 942c8406848SJakub Kicinski attr.file = GET_ARG(); 9438d1fc3deSJakub Kicinski pinfile = GET_ARG(); 94449a086c2SRoman Gushchin 945ba6dd679SJakub Kicinski while (argc) { 94649f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 94749f2cba3SJakub Kicinski char *type; 94849f2cba3SJakub Kicinski 94949f2cba3SJakub Kicinski NEXT_ARG(); 95049f2cba3SJakub Kicinski 95149f2cba3SJakub Kicinski if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 95249f2cba3SJakub Kicinski p_err("program type already specified"); 9533ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 95449f2cba3SJakub Kicinski } 95549f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 9563ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 95749f2cba3SJakub Kicinski 95849f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 95949f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 96049f2cba3SJakub Kicinski if (!type) { 96149f2cba3SJakub Kicinski p_err("mem alloc failed"); 9623ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 96349f2cba3SJakub Kicinski } 96449f2cba3SJakub Kicinski *type = 0; 96549f2cba3SJakub Kicinski strcat(type, *argv); 96649f2cba3SJakub Kicinski strcat(type, "/"); 96749f2cba3SJakub Kicinski 96849f2cba3SJakub Kicinski err = libbpf_prog_type_by_name(type, &attr.prog_type, 969c8406848SJakub Kicinski &expected_attach_type); 97049f2cba3SJakub Kicinski free(type); 97149f2cba3SJakub Kicinski if (err < 0) { 97249f2cba3SJakub Kicinski p_err("unknown program type '%s'", *argv); 9733ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 97449f2cba3SJakub Kicinski } 97549f2cba3SJakub Kicinski NEXT_ARG(); 9763ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 977dde7011aSJakub Kicinski void *new_map_replace; 9783ff5a4dcSJakub Kicinski char *endptr, *name; 9793ff5a4dcSJakub Kicinski int fd; 9803ff5a4dcSJakub Kicinski 9813ff5a4dcSJakub Kicinski NEXT_ARG(); 9823ff5a4dcSJakub Kicinski 9833ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 9843ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9853ff5a4dcSJakub Kicinski 9863ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 9873ff5a4dcSJakub Kicinski NEXT_ARG(); 9883ff5a4dcSJakub Kicinski 9893ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 9903ff5a4dcSJakub Kicinski if (*endptr) { 9913ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 9923ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9933ff5a4dcSJakub Kicinski } 9943ff5a4dcSJakub Kicinski name = NULL; 9953ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 9963ff5a4dcSJakub Kicinski NEXT_ARG(); 9973ff5a4dcSJakub Kicinski 9983ff5a4dcSJakub Kicinski name = *argv; 9993ff5a4dcSJakub Kicinski idx = -1; 10003ff5a4dcSJakub Kicinski } else { 10013ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 10023ff5a4dcSJakub Kicinski *argv); 10033ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 10043ff5a4dcSJakub Kicinski } 10053ff5a4dcSJakub Kicinski NEXT_ARG(); 10063ff5a4dcSJakub Kicinski 10073ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 10083ff5a4dcSJakub Kicinski if (fd < 0) 10093ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 10103ff5a4dcSJakub Kicinski 1011dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 1012dde7011aSJakub Kicinski old_map_fds + 1, 10133ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1014dde7011aSJakub Kicinski if (!new_map_replace) { 10153ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 10163ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 10173ff5a4dcSJakub Kicinski } 1018dde7011aSJakub Kicinski map_replace = new_map_replace; 1019dde7011aSJakub Kicinski 10203ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 10213ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 10223ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 10233ff5a4dcSJakub Kicinski old_map_fds++; 102449f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1025ba6dd679SJakub Kicinski NEXT_ARG(); 1026ba6dd679SJakub Kicinski 1027c8406848SJakub Kicinski if (ifindex) { 1028ba6dd679SJakub Kicinski p_err("offload device already specified"); 10293ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1030ba6dd679SJakub Kicinski } 1031ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 10323ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1033ba6dd679SJakub Kicinski 1034c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1035c8406848SJakub Kicinski if (!ifindex) { 1036ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1037ba6dd679SJakub Kicinski *argv, strerror(errno)); 10383ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1039ba6dd679SJakub Kicinski } 1040ba6dd679SJakub Kicinski NEXT_ARG(); 10413767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 10423767a94bSStanislav Fomichev NEXT_ARG(); 10433767a94bSStanislav Fomichev 10443767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 10453767a94bSStanislav Fomichev goto err_free_reuse_maps; 10463767a94bSStanislav Fomichev 10473767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1048ba6dd679SJakub Kicinski } else { 10493ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1050ba6dd679SJakub Kicinski *argv); 10513ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1052ba6dd679SJakub Kicinski } 1053ba6dd679SJakub Kicinski } 1054ba6dd679SJakub Kicinski 1055c034a177SJohn Fastabend obj = __bpf_object__open_xattr(&attr, bpf_flags); 1056c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 1057c8406848SJakub Kicinski p_err("failed to open object file"); 10583ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 105949a086c2SRoman Gushchin } 106049a086c2SRoman Gushchin 106177380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 106277380998SStanislav Fomichev enum bpf_prog_type prog_type = attr.prog_type; 1063c8406848SJakub Kicinski 1064c8406848SJakub Kicinski if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 106577380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1066c8406848SJakub Kicinski 106777380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 1068c8406848SJakub Kicinski &expected_attach_type); 1069c8406848SJakub Kicinski if (err < 0) { 1070c8406848SJakub Kicinski p_err("failed to guess program type based on section name %s\n", 1071c8406848SJakub Kicinski sec_name); 1072c8406848SJakub Kicinski goto err_close_obj; 1073c8406848SJakub Kicinski } 1074c8406848SJakub Kicinski } 107577380998SStanislav Fomichev 107677380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 107777380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 107877380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 107977380998SStanislav Fomichev } 1080c8406848SJakub Kicinski 10813ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 10823ff5a4dcSJakub Kicinski map_replace_compar); 10833ff5a4dcSJakub Kicinski 10843ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 10853ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 10863ff5a4dcSJakub Kicinski */ 10873ff5a4dcSJakub Kicinski j = 0; 10883ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 10893ff5a4dcSJakub Kicinski i = 0; 10903ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 10913ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 10923ff5a4dcSJakub Kicinski map_replace[j].idx = i; 10933ff5a4dcSJakub Kicinski break; 10943ff5a4dcSJakub Kicinski } 10953ff5a4dcSJakub Kicinski i++; 10963ff5a4dcSJakub Kicinski } 10973ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 10983ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 10993ff5a4dcSJakub Kicinski goto err_close_obj; 11003ff5a4dcSJakub Kicinski } 11013ff5a4dcSJakub Kicinski j++; 11023ff5a4dcSJakub Kicinski } 11033ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 11043ff5a4dcSJakub Kicinski if (j) 11053ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 11063ff5a4dcSJakub Kicinski map_replace_compar); 11073ff5a4dcSJakub Kicinski 11083ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 11093ff5a4dcSJakub Kicinski j = 0; 11103ff5a4dcSJakub Kicinski idx = 0; 11113ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 1112c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1113c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1114c8406848SJakub Kicinski 11153ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 11163ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 11173ff5a4dcSJakub Kicinski if (err) { 11183ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 11193ff5a4dcSJakub Kicinski goto err_close_obj; 11203ff5a4dcSJakub Kicinski } 11213ff5a4dcSJakub Kicinski 11223ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 11233ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 11243ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 11253ff5a4dcSJakub Kicinski idx); 11263ff5a4dcSJakub Kicinski goto err_close_obj; 11273ff5a4dcSJakub Kicinski } 11283ff5a4dcSJakub Kicinski } 11293ff5a4dcSJakub Kicinski 11303ff5a4dcSJakub Kicinski idx++; 11313ff5a4dcSJakub Kicinski } 11323ff5a4dcSJakub Kicinski if (j < old_map_fds) { 11333ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 11343ff5a4dcSJakub Kicinski goto err_close_obj; 11353ff5a4dcSJakub Kicinski } 11363ff5a4dcSJakub Kicinski 11378302b9bdSQuentin Monnet set_max_rlimit(); 11388302b9bdSQuentin Monnet 1139c8406848SJakub Kicinski err = bpf_object__load(obj); 1140c8406848SJakub Kicinski if (err) { 1141c8406848SJakub Kicinski p_err("failed to load object file"); 1142c8406848SJakub Kicinski goto err_close_obj; 1143c8406848SJakub Kicinski } 1144c8406848SJakub Kicinski 114577380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 114677380998SStanislav Fomichev if (err) 1147bfee71fbSJakub Kicinski goto err_close_obj; 114849a086c2SRoman Gushchin 114977380998SStanislav Fomichev if (first_prog_only) { 115077380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 115177380998SStanislav Fomichev if (!prog) { 115277380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 115377380998SStanislav Fomichev goto err_close_obj; 115477380998SStanislav Fomichev } 115577380998SStanislav Fomichev 115677380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 115777380998SStanislav Fomichev if (err) { 115877380998SStanislav Fomichev p_err("failed to pin program %s", 115977380998SStanislav Fomichev bpf_program__title(prog, false)); 116077380998SStanislav Fomichev goto err_close_obj; 116177380998SStanislav Fomichev } 116277380998SStanislav Fomichev } else { 116377380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 116477380998SStanislav Fomichev if (err) { 116577380998SStanislav Fomichev p_err("failed to pin all programs"); 116677380998SStanislav Fomichev goto err_close_obj; 116777380998SStanislav Fomichev } 116877380998SStanislav Fomichev } 116977380998SStanislav Fomichev 11703767a94bSStanislav Fomichev if (pinmaps) { 11713767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 11723767a94bSStanislav Fomichev if (err) { 11733767a94bSStanislav Fomichev p_err("failed to pin all maps"); 11743767a94bSStanislav Fomichev goto err_unpin; 11753767a94bSStanislav Fomichev } 11763767a94bSStanislav Fomichev } 11773767a94bSStanislav Fomichev 117849a086c2SRoman Gushchin if (json_output) 117949a086c2SRoman Gushchin jsonw_null(json_wtr); 118049a086c2SRoman Gushchin 1181bfee71fbSJakub Kicinski bpf_object__close(obj); 11823ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 11833ff5a4dcSJakub Kicinski close(map_replace[i].fd); 11843ff5a4dcSJakub Kicinski free(map_replace); 1185bfee71fbSJakub Kicinski 118649a086c2SRoman Gushchin return 0; 1187bfee71fbSJakub Kicinski 11883767a94bSStanislav Fomichev err_unpin: 11893767a94bSStanislav Fomichev if (first_prog_only) 11903767a94bSStanislav Fomichev unlink(pinfile); 11913767a94bSStanislav Fomichev else 11923767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1193bfee71fbSJakub Kicinski err_close_obj: 1194bfee71fbSJakub Kicinski bpf_object__close(obj); 11953ff5a4dcSJakub Kicinski err_free_reuse_maps: 11963ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 11973ff5a4dcSJakub Kicinski close(map_replace[i].fd); 11983ff5a4dcSJakub Kicinski free(map_replace); 1199bfee71fbSJakub Kicinski return -1; 120049a086c2SRoman Gushchin } 120149a086c2SRoman Gushchin 120277380998SStanislav Fomichev static int do_load(int argc, char **argv) 120377380998SStanislav Fomichev { 120477380998SStanislav Fomichev return load_with_options(argc, argv, true); 120577380998SStanislav Fomichev } 120677380998SStanislav Fomichev 120777380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 120877380998SStanislav Fomichev { 120977380998SStanislav Fomichev return load_with_options(argc, argv, false); 121077380998SStanislav Fomichev } 121177380998SStanislav Fomichev 121271bb428fSJakub Kicinski static int do_help(int argc, char **argv) 121371bb428fSJakub Kicinski { 1214004b45c0SQuentin Monnet if (json_output) { 1215004b45c0SQuentin Monnet jsonw_null(json_wtr); 1216004b45c0SQuentin Monnet return 0; 1217004b45c0SQuentin Monnet } 1218004b45c0SQuentin Monnet 121971bb428fSJakub Kicinski fprintf(stderr, 12206ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1221*b053b439SMartin KaFai Lau " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1222*b053b439SMartin KaFai Lau " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 122371bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 122477380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 122577380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 12263767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 12273767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1228092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1229092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 123030da46b5SQuentin Monnet " %s %s tracelog\n" 123171bb428fSJakub Kicinski " %s %s help\n" 123271bb428fSJakub Kicinski "\n" 12333ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 123471bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 123549f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 123649f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 123749f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 123849f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 123999a44befSQuentin Monnet " sk_reuseport | flow_dissector |\n" 124049f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 124149f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 124249f2cba3SJakub Kicinski " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 1243092f0892SStanislav Fomichev " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse |\n" 1244092f0892SStanislav Fomichev " flow_dissector }\n" 12450641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 124671bb428fSJakub Kicinski "", 124771bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1248b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 124930da46b5SQuentin Monnet bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 125071bb428fSJakub Kicinski 125171bb428fSJakub Kicinski return 0; 125271bb428fSJakub Kicinski } 125371bb428fSJakub Kicinski 125471bb428fSJakub Kicinski static const struct cmd cmds[] = { 125571bb428fSJakub Kicinski { "show", do_show }, 12566ebe6dbdSJakub Kicinski { "list", do_show }, 12579f606179SQuentin Monnet { "help", do_help }, 125871bb428fSJakub Kicinski { "dump", do_dump }, 125971bb428fSJakub Kicinski { "pin", do_pin }, 126049a086c2SRoman Gushchin { "load", do_load }, 126177380998SStanislav Fomichev { "loadall", do_loadall }, 1262b7d3826cSJohn Fastabend { "attach", do_attach }, 1263b7d3826cSJohn Fastabend { "detach", do_detach }, 126430da46b5SQuentin Monnet { "tracelog", do_tracelog }, 126571bb428fSJakub Kicinski { 0 } 126671bb428fSJakub Kicinski }; 126771bb428fSJakub Kicinski 126871bb428fSJakub Kicinski int do_prog(int argc, char **argv) 126971bb428fSJakub Kicinski { 127071bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 127171bb428fSJakub Kicinski } 1272