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 3471bb428fSJakub Kicinski #include <errno.h> 3571bb428fSJakub Kicinski #include <fcntl.h> 36c9c35995SJakub Kicinski #include <stdarg.h> 3771bb428fSJakub Kicinski #include <stdio.h> 3871bb428fSJakub Kicinski #include <stdlib.h> 3971bb428fSJakub Kicinski #include <string.h> 4071bb428fSJakub Kicinski #include <time.h> 4171bb428fSJakub Kicinski #include <unistd.h> 42ba6dd679SJakub Kicinski #include <net/if.h> 4371bb428fSJakub Kicinski #include <sys/types.h> 4471bb428fSJakub Kicinski #include <sys/stat.h> 4571bb428fSJakub Kicinski 46*c8406848SJakub Kicinski #include <linux/err.h> 47*c8406848SJakub Kicinski 4871bb428fSJakub Kicinski #include <bpf.h> 4949a086c2SRoman Gushchin #include <libbpf.h> 5071bb428fSJakub Kicinski 51b6c1cedbSJiong Wang #include "cfg.h" 5271bb428fSJakub Kicinski #include "main.h" 5373bb5b4fSJiong Wang #include "xlated_dumper.h" 5471bb428fSJakub Kicinski 5571bb428fSJakub Kicinski static const char * const prog_type_name[] = { 5671bb428fSJakub Kicinski [BPF_PROG_TYPE_UNSPEC] = "unspec", 5771bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 5871bb428fSJakub Kicinski [BPF_PROG_TYPE_KPROBE] = "kprobe", 5971bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 6071bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 6171bb428fSJakub Kicinski [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 6271bb428fSJakub Kicinski [BPF_PROG_TYPE_XDP] = "xdp", 6371bb428fSJakub Kicinski [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 6471bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 6571bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 6671bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 6771bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 6871bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 6971bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 7071bb428fSJakub Kicinski [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 7145e5e121SRoman Gushchin [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 72393de512SAndrey Ignatov [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 73393de512SAndrey Ignatov [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 74393de512SAndrey Ignatov [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 756bdd533cSSean Young [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 7671bb428fSJakub Kicinski }; 7771bb428fSJakub Kicinski 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 printf("\n"); 3394990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3404990f1f4SPrashant Bhole if (obj->id == info->id) 3414990f1f4SPrashant Bhole printf("\tpinned %s\n", obj->path); 3424990f1f4SPrashant Bhole } 3434990f1f4SPrashant Bhole } 3444990f1f4SPrashant Bhole 34571bb428fSJakub Kicinski printf("\n"); 346743cc665SQuentin Monnet } 347743cc665SQuentin Monnet 348743cc665SQuentin Monnet static int show_prog(int fd) 349743cc665SQuentin Monnet { 350743cc665SQuentin Monnet struct bpf_prog_info info = {}; 351743cc665SQuentin Monnet __u32 len = sizeof(info); 352743cc665SQuentin Monnet int err; 353743cc665SQuentin Monnet 354743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 355743cc665SQuentin Monnet if (err) { 3569a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 357743cc665SQuentin Monnet return -1; 358743cc665SQuentin Monnet } 359743cc665SQuentin Monnet 360743cc665SQuentin Monnet if (json_output) 361743cc665SQuentin Monnet print_prog_json(&info, fd); 362743cc665SQuentin Monnet else 363743cc665SQuentin Monnet print_prog_plain(&info, fd); 36471bb428fSJakub Kicinski 36571bb428fSJakub Kicinski return 0; 36671bb428fSJakub Kicinski } 36771bb428fSJakub Kicinski 36871bb428fSJakub Kicinski static int do_show(int argc, char **argv) 369743cc665SQuentin Monnet { 370743cc665SQuentin Monnet __u32 id = 0; 37171bb428fSJakub Kicinski int err; 37271bb428fSJakub Kicinski int fd; 37371bb428fSJakub Kicinski 374c541b734SPrashant Bhole if (show_pinned) 3754990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 3764990f1f4SPrashant Bhole 37771bb428fSJakub Kicinski if (argc == 2) { 37871bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 37971bb428fSJakub Kicinski if (fd < 0) 38071bb428fSJakub Kicinski return -1; 38171bb428fSJakub Kicinski 38271bb428fSJakub Kicinski return show_prog(fd); 38371bb428fSJakub Kicinski } 38471bb428fSJakub Kicinski 38571bb428fSJakub Kicinski if (argc) 38671bb428fSJakub Kicinski return BAD_ARG(); 38771bb428fSJakub Kicinski 388743cc665SQuentin Monnet if (json_output) 389743cc665SQuentin Monnet jsonw_start_array(json_wtr); 39071bb428fSJakub Kicinski while (true) { 39171bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 39271bb428fSJakub Kicinski if (err) { 3931739c26dSQuentin Monnet if (errno == ENOENT) { 3941739c26dSQuentin Monnet err = 0; 39571bb428fSJakub Kicinski break; 3961739c26dSQuentin Monnet } 3979a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 3989a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 399743cc665SQuentin Monnet err = -1; 400743cc665SQuentin Monnet break; 40171bb428fSJakub Kicinski } 40271bb428fSJakub Kicinski 40371bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 40471bb428fSJakub Kicinski if (fd < 0) { 4058207c6ddSJakub Kicinski if (errno == ENOENT) 4068207c6ddSJakub Kicinski continue; 4079a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 40871bb428fSJakub Kicinski id, strerror(errno)); 409743cc665SQuentin Monnet err = -1; 410743cc665SQuentin Monnet break; 41171bb428fSJakub Kicinski } 41271bb428fSJakub Kicinski 41371bb428fSJakub Kicinski err = show_prog(fd); 41471bb428fSJakub Kicinski close(fd); 41571bb428fSJakub Kicinski if (err) 416743cc665SQuentin Monnet break; 41771bb428fSJakub Kicinski } 41871bb428fSJakub Kicinski 419743cc665SQuentin Monnet if (json_output) 420743cc665SQuentin Monnet jsonw_end_array(json_wtr); 421743cc665SQuentin Monnet 422743cc665SQuentin Monnet return err; 42371bb428fSJakub Kicinski } 42471bb428fSJakub Kicinski 42571bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 42671bb428fSJakub Kicinski { 427f84192eeSSandipan Das unsigned long *func_ksyms = NULL; 42871bb428fSJakub Kicinski struct bpf_prog_info info = {}; 429f7f62c71SSandipan Das unsigned int *func_lens = NULL; 430f84192eeSSandipan Das unsigned int nr_func_ksyms; 431f7f62c71SSandipan Das unsigned int nr_func_lens; 4327105e828SDaniel Borkmann struct dump_data dd = {}; 43371bb428fSJakub Kicinski __u32 len = sizeof(info); 43471bb428fSJakub Kicinski unsigned int buf_size; 43571bb428fSJakub Kicinski char *filepath = NULL; 43671bb428fSJakub Kicinski bool opcodes = false; 437b6c1cedbSJiong Wang bool visual = false; 43871bb428fSJakub Kicinski unsigned char *buf; 43971bb428fSJakub Kicinski __u32 *member_len; 44071bb428fSJakub Kicinski __u64 *member_ptr; 44171bb428fSJakub Kicinski ssize_t n; 44271bb428fSJakub Kicinski int err; 44371bb428fSJakub Kicinski int fd; 44471bb428fSJakub Kicinski 44571bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 44671bb428fSJakub Kicinski member_len = &info.jited_prog_len; 44771bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 44871bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 44971bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 45071bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 45171bb428fSJakub Kicinski } else { 4529a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 45371bb428fSJakub Kicinski return -1; 45471bb428fSJakub Kicinski } 45571bb428fSJakub Kicinski NEXT_ARG(); 45671bb428fSJakub Kicinski 45771bb428fSJakub Kicinski if (argc < 2) 45871bb428fSJakub Kicinski usage(); 45971bb428fSJakub Kicinski 46071bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 46171bb428fSJakub Kicinski if (fd < 0) 46271bb428fSJakub Kicinski return -1; 46371bb428fSJakub Kicinski 46471bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 46571bb428fSJakub Kicinski NEXT_ARG(); 46671bb428fSJakub Kicinski if (!argc) { 4679a5ab8bfSQuentin Monnet p_err("expected file path"); 46871bb428fSJakub Kicinski return -1; 46971bb428fSJakub Kicinski } 47071bb428fSJakub Kicinski 47171bb428fSJakub Kicinski filepath = *argv; 47271bb428fSJakub Kicinski NEXT_ARG(); 47371bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 47471bb428fSJakub Kicinski opcodes = true; 47571bb428fSJakub Kicinski NEXT_ARG(); 476b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 477b6c1cedbSJiong Wang visual = true; 478b6c1cedbSJiong Wang NEXT_ARG(); 47971bb428fSJakub Kicinski } 48071bb428fSJakub Kicinski 48171bb428fSJakub Kicinski if (argc) { 48271bb428fSJakub Kicinski usage(); 48371bb428fSJakub Kicinski return -1; 48471bb428fSJakub Kicinski } 48571bb428fSJakub Kicinski 48671bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 48771bb428fSJakub Kicinski if (err) { 4889a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 48971bb428fSJakub Kicinski return -1; 49071bb428fSJakub Kicinski } 49171bb428fSJakub Kicinski 49271bb428fSJakub Kicinski if (!*member_len) { 4939a5ab8bfSQuentin Monnet p_info("no instructions returned"); 49471bb428fSJakub Kicinski close(fd); 49571bb428fSJakub Kicinski return 0; 49671bb428fSJakub Kicinski } 49771bb428fSJakub Kicinski 49871bb428fSJakub Kicinski buf_size = *member_len; 49971bb428fSJakub Kicinski 50071bb428fSJakub Kicinski buf = malloc(buf_size); 50171bb428fSJakub Kicinski if (!buf) { 5029a5ab8bfSQuentin Monnet p_err("mem alloc failed"); 50371bb428fSJakub Kicinski close(fd); 50471bb428fSJakub Kicinski return -1; 50571bb428fSJakub Kicinski } 50671bb428fSJakub Kicinski 507f84192eeSSandipan Das nr_func_ksyms = info.nr_jited_ksyms; 508f84192eeSSandipan Das if (nr_func_ksyms) { 509f84192eeSSandipan Das func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 510f84192eeSSandipan Das if (!func_ksyms) { 511f84192eeSSandipan Das p_err("mem alloc failed"); 512f84192eeSSandipan Das close(fd); 513f84192eeSSandipan Das goto err_free; 514f84192eeSSandipan Das } 515f84192eeSSandipan Das } 516f84192eeSSandipan Das 517f7f62c71SSandipan Das nr_func_lens = info.nr_jited_func_lens; 518f7f62c71SSandipan Das if (nr_func_lens) { 519f7f62c71SSandipan Das func_lens = malloc(nr_func_lens * sizeof(__u32)); 520f7f62c71SSandipan Das if (!func_lens) { 521f7f62c71SSandipan Das p_err("mem alloc failed"); 522f7f62c71SSandipan Das close(fd); 523f7f62c71SSandipan Das goto err_free; 524f7f62c71SSandipan Das } 525f7f62c71SSandipan Das } 526f7f62c71SSandipan Das 52771bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 52871bb428fSJakub Kicinski 52971bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 53071bb428fSJakub Kicinski *member_len = buf_size; 531f84192eeSSandipan Das info.jited_ksyms = ptr_to_u64(func_ksyms); 532f84192eeSSandipan Das info.nr_jited_ksyms = nr_func_ksyms; 533f7f62c71SSandipan Das info.jited_func_lens = ptr_to_u64(func_lens); 534f7f62c71SSandipan Das info.nr_jited_func_lens = nr_func_lens; 53571bb428fSJakub Kicinski 53671bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 53771bb428fSJakub Kicinski close(fd); 53871bb428fSJakub Kicinski if (err) { 5399a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 54071bb428fSJakub Kicinski goto err_free; 54171bb428fSJakub Kicinski } 54271bb428fSJakub Kicinski 54371bb428fSJakub Kicinski if (*member_len > buf_size) { 5449a5ab8bfSQuentin Monnet p_err("too many instructions returned"); 54571bb428fSJakub Kicinski goto err_free; 54671bb428fSJakub Kicinski } 54771bb428fSJakub Kicinski 548f84192eeSSandipan Das if (info.nr_jited_ksyms > nr_func_ksyms) { 549f84192eeSSandipan Das p_err("too many addresses returned"); 550f84192eeSSandipan Das goto err_free; 551f84192eeSSandipan Das } 552f84192eeSSandipan Das 553f7f62c71SSandipan Das if (info.nr_jited_func_lens > nr_func_lens) { 554f7f62c71SSandipan Das p_err("too many values returned"); 555f7f62c71SSandipan Das goto err_free; 556f7f62c71SSandipan Das } 557f7f62c71SSandipan Das 5587105e828SDaniel Borkmann if ((member_len == &info.jited_prog_len && 5597105e828SDaniel Borkmann info.jited_prog_insns == 0) || 5607105e828SDaniel Borkmann (member_len == &info.xlated_prog_len && 5617105e828SDaniel Borkmann info.xlated_prog_insns == 0)) { 5627105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 5637105e828SDaniel Borkmann goto err_free; 5647105e828SDaniel Borkmann } 5657105e828SDaniel Borkmann 56671bb428fSJakub Kicinski if (filepath) { 56771bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 56871bb428fSJakub Kicinski if (fd < 0) { 5699a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 57071bb428fSJakub Kicinski strerror(errno)); 57171bb428fSJakub Kicinski goto err_free; 57271bb428fSJakub Kicinski } 57371bb428fSJakub Kicinski 57471bb428fSJakub Kicinski n = write(fd, buf, *member_len); 57571bb428fSJakub Kicinski close(fd); 57671bb428fSJakub Kicinski if (n != *member_len) { 5779a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 57871bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 57971bb428fSJakub Kicinski goto err_free; 58071bb428fSJakub Kicinski } 58152c84d36SQuentin Monnet 58252c84d36SQuentin Monnet if (json_output) 58352c84d36SQuentin Monnet jsonw_null(json_wtr); 5843197239dSJiong Wang } else if (member_len == &info.jited_prog_len) { 585e6593596SJiong Wang const char *name = NULL; 586e6593596SJiong Wang 587e6593596SJiong Wang if (info.ifindex) { 588e6593596SJiong Wang name = ifindex_to_bfd_name_ns(info.ifindex, 589e6593596SJiong Wang info.netns_dev, 590e6593596SJiong Wang info.netns_ino); 591e6593596SJiong Wang if (!name) 592e6593596SJiong Wang goto err_free; 593e6593596SJiong Wang } 594e6593596SJiong Wang 595f7f62c71SSandipan Das if (info.nr_jited_func_lens && info.jited_func_lens) { 596f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 597f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 598f7f62c71SSandipan Das unsigned char *img = buf; 599f7f62c71SSandipan Das __u64 *ksyms = NULL; 600f7f62c71SSandipan Das __u32 *lens; 601f7f62c71SSandipan Das __u32 i; 602f7f62c71SSandipan Das 603f7f62c71SSandipan Das if (info.nr_jited_ksyms) { 604f7f62c71SSandipan Das kernel_syms_load(&dd); 605f7f62c71SSandipan Das ksyms = (__u64 *) info.jited_ksyms; 606f7f62c71SSandipan Das } 607f7f62c71SSandipan Das 608f7f62c71SSandipan Das if (json_output) 609f7f62c71SSandipan Das jsonw_start_array(json_wtr); 610f7f62c71SSandipan Das 611f7f62c71SSandipan Das lens = (__u32 *) info.jited_func_lens; 612f7f62c71SSandipan Das for (i = 0; i < info.nr_jited_func_lens; i++) { 613f7f62c71SSandipan Das if (ksyms) { 614f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 615f7f62c71SSandipan Das if (sym) 616f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 617f7f62c71SSandipan Das else 618f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 619f7f62c71SSandipan Das } else { 620f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 621f7f62c71SSandipan Das } 622f7f62c71SSandipan Das 623f7f62c71SSandipan Das if (json_output) { 624f7f62c71SSandipan Das jsonw_start_object(json_wtr); 625f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 626f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 627f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 628f7f62c71SSandipan Das } else { 629f7f62c71SSandipan Das printf("%s:\n", sym_name); 630f7f62c71SSandipan Das } 631f7f62c71SSandipan Das 632f7f62c71SSandipan Das disasm_print_insn(img, lens[i], opcodes, name); 633f7f62c71SSandipan Das img += lens[i]; 634f7f62c71SSandipan Das 635f7f62c71SSandipan Das if (json_output) 636f7f62c71SSandipan Das jsonw_end_object(json_wtr); 637f7f62c71SSandipan Das else 638f7f62c71SSandipan Das printf("\n"); 639f7f62c71SSandipan Das } 640f7f62c71SSandipan Das 641f7f62c71SSandipan Das if (json_output) 642f7f62c71SSandipan Das jsonw_end_array(json_wtr); 643f7f62c71SSandipan Das } else { 644e6593596SJiong Wang disasm_print_insn(buf, *member_len, opcodes, name); 645f7f62c71SSandipan Das } 646b6c1cedbSJiong Wang } else if (visual) { 647b6c1cedbSJiong Wang if (json_output) 648b6c1cedbSJiong Wang jsonw_null(json_wtr); 649b6c1cedbSJiong Wang else 650b6c1cedbSJiong Wang dump_xlated_cfg(buf, *member_len); 6517105e828SDaniel Borkmann } else { 6527105e828SDaniel Borkmann kernel_syms_load(&dd); 653f84192eeSSandipan Das dd.nr_jited_ksyms = info.nr_jited_ksyms; 654f84192eeSSandipan Das dd.jited_ksyms = (__u64 *) info.jited_ksyms; 655f84192eeSSandipan Das 656f05e2c32SQuentin Monnet if (json_output) 6577105e828SDaniel Borkmann dump_xlated_json(&dd, buf, *member_len, opcodes); 658f05e2c32SQuentin Monnet else 6597105e828SDaniel Borkmann dump_xlated_plain(&dd, buf, *member_len, opcodes); 6607105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6617105e828SDaniel Borkmann } 66271bb428fSJakub Kicinski 66371bb428fSJakub Kicinski free(buf); 664f84192eeSSandipan Das free(func_ksyms); 665f7f62c71SSandipan Das free(func_lens); 66671bb428fSJakub Kicinski return 0; 66771bb428fSJakub Kicinski 66871bb428fSJakub Kicinski err_free: 66971bb428fSJakub Kicinski free(buf); 670f84192eeSSandipan Das free(func_ksyms); 671f7f62c71SSandipan Das free(func_lens); 67271bb428fSJakub Kicinski return -1; 67371bb428fSJakub Kicinski } 67471bb428fSJakub Kicinski 67571bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 67671bb428fSJakub Kicinski { 677004b45c0SQuentin Monnet int err; 678004b45c0SQuentin Monnet 679004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 680004b45c0SQuentin Monnet if (!err && json_output) 681004b45c0SQuentin Monnet jsonw_null(json_wtr); 682004b45c0SQuentin Monnet return err; 68371bb428fSJakub Kicinski } 68471bb428fSJakub Kicinski 68549a086c2SRoman Gushchin static int do_load(int argc, char **argv) 68649a086c2SRoman Gushchin { 687*c8406848SJakub Kicinski enum bpf_attach_type expected_attach_type; 688*c8406848SJakub Kicinski struct bpf_object_open_attr attr = { 689ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 690ba6dd679SJakub Kicinski }; 691*c8406848SJakub Kicinski struct bpf_program *prog; 69249a086c2SRoman Gushchin struct bpf_object *obj; 693*c8406848SJakub Kicinski struct bpf_map *map; 694*c8406848SJakub Kicinski const char *pinfile; 695*c8406848SJakub Kicinski __u32 ifindex = 0; 69649f2cba3SJakub Kicinski int err; 69749a086c2SRoman Gushchin 6988d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 6998d1fc3deSJakub Kicinski return -1; 700*c8406848SJakub Kicinski attr.file = GET_ARG(); 7018d1fc3deSJakub Kicinski pinfile = GET_ARG(); 70249a086c2SRoman Gushchin 703ba6dd679SJakub Kicinski while (argc) { 70449f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 70549f2cba3SJakub Kicinski char *type; 70649f2cba3SJakub Kicinski 70749f2cba3SJakub Kicinski NEXT_ARG(); 70849f2cba3SJakub Kicinski 70949f2cba3SJakub Kicinski if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 71049f2cba3SJakub Kicinski p_err("program type already specified"); 71149f2cba3SJakub Kicinski return -1; 71249f2cba3SJakub Kicinski } 71349f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 71449f2cba3SJakub Kicinski return -1; 71549f2cba3SJakub Kicinski 71649f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 71749f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 71849f2cba3SJakub Kicinski if (!type) { 71949f2cba3SJakub Kicinski p_err("mem alloc failed"); 72049f2cba3SJakub Kicinski return -1; 72149f2cba3SJakub Kicinski } 72249f2cba3SJakub Kicinski *type = 0; 72349f2cba3SJakub Kicinski strcat(type, *argv); 72449f2cba3SJakub Kicinski strcat(type, "/"); 72549f2cba3SJakub Kicinski 72649f2cba3SJakub Kicinski err = libbpf_prog_type_by_name(type, &attr.prog_type, 727*c8406848SJakub Kicinski &expected_attach_type); 72849f2cba3SJakub Kicinski free(type); 72949f2cba3SJakub Kicinski if (err < 0) { 73049f2cba3SJakub Kicinski p_err("unknown program type '%s'", *argv); 73149f2cba3SJakub Kicinski return err; 73249f2cba3SJakub Kicinski } 73349f2cba3SJakub Kicinski NEXT_ARG(); 73449f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 735ba6dd679SJakub Kicinski NEXT_ARG(); 736ba6dd679SJakub Kicinski 737*c8406848SJakub Kicinski if (ifindex) { 738ba6dd679SJakub Kicinski p_err("offload device already specified"); 739ba6dd679SJakub Kicinski return -1; 740ba6dd679SJakub Kicinski } 741ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 742ba6dd679SJakub Kicinski return -1; 743ba6dd679SJakub Kicinski 744*c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 745*c8406848SJakub Kicinski if (!ifindex) { 746ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 747ba6dd679SJakub Kicinski *argv, strerror(errno)); 748ba6dd679SJakub Kicinski return -1; 749ba6dd679SJakub Kicinski } 750ba6dd679SJakub Kicinski NEXT_ARG(); 751ba6dd679SJakub Kicinski } else { 75249f2cba3SJakub Kicinski p_err("expected no more arguments, 'type' or 'dev', got: '%s'?", 753ba6dd679SJakub Kicinski *argv); 754ba6dd679SJakub Kicinski return -1; 755ba6dd679SJakub Kicinski } 756ba6dd679SJakub Kicinski } 757ba6dd679SJakub Kicinski 758*c8406848SJakub Kicinski obj = bpf_object__open_xattr(&attr); 759*c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 760*c8406848SJakub Kicinski p_err("failed to open object file"); 76149a086c2SRoman Gushchin return -1; 76249a086c2SRoman Gushchin } 76349a086c2SRoman Gushchin 764*c8406848SJakub Kicinski prog = bpf_program__next(NULL, obj); 765*c8406848SJakub Kicinski if (!prog) { 766*c8406848SJakub Kicinski p_err("object file doesn't contain any bpf program"); 767*c8406848SJakub Kicinski goto err_close_obj; 768*c8406848SJakub Kicinski } 769*c8406848SJakub Kicinski 770*c8406848SJakub Kicinski bpf_program__set_ifindex(prog, ifindex); 771*c8406848SJakub Kicinski if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 772*c8406848SJakub Kicinski const char *sec_name = bpf_program__title(prog, false); 773*c8406848SJakub Kicinski 774*c8406848SJakub Kicinski err = libbpf_prog_type_by_name(sec_name, &attr.prog_type, 775*c8406848SJakub Kicinski &expected_attach_type); 776*c8406848SJakub Kicinski if (err < 0) { 777*c8406848SJakub Kicinski p_err("failed to guess program type based on section name %s\n", 778*c8406848SJakub Kicinski sec_name); 779*c8406848SJakub Kicinski goto err_close_obj; 780*c8406848SJakub Kicinski } 781*c8406848SJakub Kicinski } 782*c8406848SJakub Kicinski bpf_program__set_type(prog, attr.prog_type); 783*c8406848SJakub Kicinski bpf_program__set_expected_attach_type(prog, expected_attach_type); 784*c8406848SJakub Kicinski 785*c8406848SJakub Kicinski bpf_map__for_each(map, obj) 786*c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 787*c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 788*c8406848SJakub Kicinski 789*c8406848SJakub Kicinski err = bpf_object__load(obj); 790*c8406848SJakub Kicinski if (err) { 791*c8406848SJakub Kicinski p_err("failed to load object file"); 792*c8406848SJakub Kicinski goto err_close_obj; 793*c8406848SJakub Kicinski } 794*c8406848SJakub Kicinski 795*c8406848SJakub Kicinski if (do_pin_fd(bpf_program__fd(prog), pinfile)) 796bfee71fbSJakub Kicinski goto err_close_obj; 79749a086c2SRoman Gushchin 79849a086c2SRoman Gushchin if (json_output) 79949a086c2SRoman Gushchin jsonw_null(json_wtr); 80049a086c2SRoman Gushchin 801bfee71fbSJakub Kicinski bpf_object__close(obj); 802bfee71fbSJakub Kicinski 80349a086c2SRoman Gushchin return 0; 804bfee71fbSJakub Kicinski 805bfee71fbSJakub Kicinski err_close_obj: 806bfee71fbSJakub Kicinski bpf_object__close(obj); 807bfee71fbSJakub Kicinski return -1; 80849a086c2SRoman Gushchin } 80949a086c2SRoman Gushchin 81071bb428fSJakub Kicinski static int do_help(int argc, char **argv) 81171bb428fSJakub Kicinski { 812004b45c0SQuentin Monnet if (json_output) { 813004b45c0SQuentin Monnet jsonw_null(json_wtr); 814004b45c0SQuentin Monnet return 0; 815004b45c0SQuentin Monnet } 816004b45c0SQuentin Monnet 81771bb428fSJakub Kicinski fprintf(stderr, 8186ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 819b6c1cedbSJiong Wang " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 8208dfbc6d1SQuentin Monnet " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 82171bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 82249f2cba3SJakub Kicinski " %s %s load OBJ FILE [type TYPE] [dev NAME]\n" 82371bb428fSJakub Kicinski " %s %s help\n" 82471bb428fSJakub Kicinski "\n" 82571bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 82649f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 82749f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 82849f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 82949f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 83049f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 83149f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 83249f2cba3SJakub Kicinski " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 8330641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 83471bb428fSJakub Kicinski "", 83571bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 83649a086c2SRoman Gushchin bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 83771bb428fSJakub Kicinski 83871bb428fSJakub Kicinski return 0; 83971bb428fSJakub Kicinski } 84071bb428fSJakub Kicinski 84171bb428fSJakub Kicinski static const struct cmd cmds[] = { 84271bb428fSJakub Kicinski { "show", do_show }, 8436ebe6dbdSJakub Kicinski { "list", do_show }, 8449f606179SQuentin Monnet { "help", do_help }, 84571bb428fSJakub Kicinski { "dump", do_dump }, 84671bb428fSJakub Kicinski { "pin", do_pin }, 84749a086c2SRoman Gushchin { "load", do_load }, 84871bb428fSJakub Kicinski { 0 } 84971bb428fSJakub Kicinski }; 85071bb428fSJakub Kicinski 85171bb428fSJakub Kicinski int do_prog(int argc, char **argv) 85271bb428fSJakub Kicinski { 85371bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 85471bb428fSJakub Kicinski } 855