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> 5049a086c2SRoman Gushchin #include <libbpf.h> 5171bb428fSJakub Kicinski 52b6c1cedbSJiong Wang #include "cfg.h" 5371bb428fSJakub Kicinski #include "main.h" 5473bb5b4fSJiong Wang #include "xlated_dumper.h" 5571bb428fSJakub Kicinski 5671bb428fSJakub Kicinski static const char * const prog_type_name[] = { 5771bb428fSJakub Kicinski [BPF_PROG_TYPE_UNSPEC] = "unspec", 5871bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 5971bb428fSJakub Kicinski [BPF_PROG_TYPE_KPROBE] = "kprobe", 6071bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 6171bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 6271bb428fSJakub Kicinski [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 6371bb428fSJakub Kicinski [BPF_PROG_TYPE_XDP] = "xdp", 6471bb428fSJakub Kicinski [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 6571bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 6671bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 6771bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 6871bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 6971bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 7071bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 7171bb428fSJakub Kicinski [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 7245e5e121SRoman Gushchin [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 73393de512SAndrey Ignatov [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 74393de512SAndrey Ignatov [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 75393de512SAndrey Ignatov [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 766bdd533cSSean Young [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 77*c22fbae7SPetar Penkov [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", 7871bb428fSJakub Kicinski }; 7971bb428fSJakub Kicinski 8071bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 8171bb428fSJakub Kicinski { 8271bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 8371bb428fSJakub Kicinski time_t wallclock_secs; 8471bb428fSJakub Kicinski struct tm load_tm; 8571bb428fSJakub Kicinski 8671bb428fSJakub Kicinski buf[--size] = '\0'; 8771bb428fSJakub Kicinski 8871bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 8971bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 9071bb428fSJakub Kicinski perror("Can't read clocks"); 9171bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 9271bb428fSJakub Kicinski return; 9371bb428fSJakub Kicinski } 9471bb428fSJakub Kicinski 9571bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 9607480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 9707480cbcSJakub Kicinski 1000000000; 9807480cbcSJakub Kicinski 9971bb428fSJakub Kicinski 10071bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 10171bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 10271bb428fSJakub Kicinski return; 10371bb428fSJakub Kicinski } 10471bb428fSJakub Kicinski 105a3fe1f6fSQuentin Monnet if (json_output) 106a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 107a3fe1f6fSQuentin Monnet else 108a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 10971bb428fSJakub Kicinski } 11071bb428fSJakub Kicinski 11171bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 11271bb428fSJakub Kicinski { 11371bb428fSJakub Kicinski struct bpf_prog_info info = {}; 11471bb428fSJakub Kicinski __u32 len = sizeof(info); 11571bb428fSJakub Kicinski unsigned int id = 0; 11671bb428fSJakub Kicinski int err; 11771bb428fSJakub Kicinski int fd; 11871bb428fSJakub Kicinski 11971bb428fSJakub Kicinski while (true) { 12071bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 12171bb428fSJakub Kicinski if (err) { 1229a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 12371bb428fSJakub Kicinski return -1; 12471bb428fSJakub Kicinski } 12571bb428fSJakub Kicinski 12671bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 12771bb428fSJakub Kicinski if (fd < 0) { 1289a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 12971bb428fSJakub Kicinski id, strerror(errno)); 13071bb428fSJakub Kicinski return -1; 13171bb428fSJakub Kicinski } 13271bb428fSJakub Kicinski 13371bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 13471bb428fSJakub Kicinski if (err) { 1359a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 13671bb428fSJakub Kicinski id, strerror(errno)); 13771bb428fSJakub Kicinski close(fd); 13871bb428fSJakub Kicinski return -1; 13971bb428fSJakub Kicinski } 14071bb428fSJakub Kicinski 14171bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 14271bb428fSJakub Kicinski return fd; 14371bb428fSJakub Kicinski 14471bb428fSJakub Kicinski close(fd); 14571bb428fSJakub Kicinski } 14671bb428fSJakub Kicinski } 14771bb428fSJakub Kicinski 14871bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 14971bb428fSJakub Kicinski { 15071bb428fSJakub Kicinski int fd; 15171bb428fSJakub Kicinski 15271bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 15371bb428fSJakub Kicinski unsigned int id; 15471bb428fSJakub Kicinski char *endptr; 15571bb428fSJakub Kicinski 15671bb428fSJakub Kicinski NEXT_ARGP(); 15771bb428fSJakub Kicinski 15871bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 15971bb428fSJakub Kicinski if (*endptr) { 1609a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 16171bb428fSJakub Kicinski return -1; 16271bb428fSJakub Kicinski } 16371bb428fSJakub Kicinski NEXT_ARGP(); 16471bb428fSJakub Kicinski 16571bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 16671bb428fSJakub Kicinski if (fd < 0) 1679a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 16871bb428fSJakub Kicinski return fd; 16971bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 17071bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 17171bb428fSJakub Kicinski 17271bb428fSJakub Kicinski NEXT_ARGP(); 17371bb428fSJakub Kicinski 17471bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 17571bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 17671bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1779a5ab8bfSQuentin Monnet p_err("can't parse tag"); 17871bb428fSJakub Kicinski return -1; 17971bb428fSJakub Kicinski } 18071bb428fSJakub Kicinski NEXT_ARGP(); 18171bb428fSJakub Kicinski 18271bb428fSJakub Kicinski return prog_fd_by_tag(tag); 18371bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 18471bb428fSJakub Kicinski char *path; 18571bb428fSJakub Kicinski 18671bb428fSJakub Kicinski NEXT_ARGP(); 18771bb428fSJakub Kicinski 18871bb428fSJakub Kicinski path = **argv; 18971bb428fSJakub Kicinski NEXT_ARGP(); 19071bb428fSJakub Kicinski 19171bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 19271bb428fSJakub Kicinski } 19371bb428fSJakub Kicinski 1949a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 19571bb428fSJakub Kicinski return -1; 19671bb428fSJakub Kicinski } 19771bb428fSJakub Kicinski 19871bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 19971bb428fSJakub Kicinski { 20071bb428fSJakub Kicinski struct bpf_prog_info info = {}; 20171bb428fSJakub Kicinski __u32 len = sizeof(info); 20271bb428fSJakub Kicinski __u32 map_ids[num_maps]; 20371bb428fSJakub Kicinski unsigned int i; 20471bb428fSJakub Kicinski int err; 20571bb428fSJakub Kicinski 20671bb428fSJakub Kicinski info.nr_map_ids = num_maps; 20771bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 20871bb428fSJakub Kicinski 20971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 21071bb428fSJakub Kicinski if (err || !info.nr_map_ids) 21171bb428fSJakub Kicinski return; 21271bb428fSJakub Kicinski 213743cc665SQuentin Monnet if (json_output) { 214743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 215743cc665SQuentin Monnet jsonw_start_array(json_wtr); 216743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 217743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 218743cc665SQuentin Monnet jsonw_end_array(json_wtr); 219743cc665SQuentin Monnet } else { 22071bb428fSJakub Kicinski printf(" map_ids "); 22171bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 22271bb428fSJakub Kicinski printf("%u%s", map_ids[i], 22371bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 22471bb428fSJakub Kicinski } 22571bb428fSJakub Kicinski } 22671bb428fSJakub Kicinski 227743cc665SQuentin Monnet static void print_prog_json(struct bpf_prog_info *info, int fd) 228743cc665SQuentin Monnet { 229743cc665SQuentin Monnet char *memlock; 230743cc665SQuentin Monnet 231743cc665SQuentin Monnet jsonw_start_object(json_wtr); 232743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 233743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 234743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 235743cc665SQuentin Monnet prog_type_name[info->type]); 23671bb428fSJakub Kicinski else 237743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 23871bb428fSJakub Kicinski 239743cc665SQuentin Monnet if (*info->name) 240743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 24171bb428fSJakub Kicinski 242743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 243743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 244743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 245743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 24671bb428fSJakub Kicinski 2479b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 2489b984a20SJiri Olsa 24952262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 25052262210SJakub Kicinski 251743cc665SQuentin Monnet if (info->load_time) { 25271bb428fSJakub Kicinski char buf[32]; 25371bb428fSJakub Kicinski 254743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 25571bb428fSJakub Kicinski 25671bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 257a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 258a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 259743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 26071bb428fSJakub Kicinski } 26171bb428fSJakub Kicinski 262743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 26371bb428fSJakub Kicinski 264743cc665SQuentin Monnet if (info->jited_prog_len) { 265743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 266743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 267743cc665SQuentin Monnet } else { 268743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 269743cc665SQuentin Monnet } 270743cc665SQuentin Monnet 271743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 272743cc665SQuentin Monnet if (memlock) 273743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 274743cc665SQuentin Monnet free(memlock); 275743cc665SQuentin Monnet 276743cc665SQuentin Monnet if (info->nr_map_ids) 277743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 278743cc665SQuentin Monnet 2794990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 2804990f1f4SPrashant Bhole struct pinned_obj *obj; 2814990f1f4SPrashant Bhole 2824990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 2834990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 2844990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 2854990f1f4SPrashant Bhole if (obj->id == info->id) 2864990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 2874990f1f4SPrashant Bhole } 2884990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 2894990f1f4SPrashant Bhole } 2904990f1f4SPrashant Bhole 291743cc665SQuentin Monnet jsonw_end_object(json_wtr); 292743cc665SQuentin Monnet } 293743cc665SQuentin Monnet 294743cc665SQuentin Monnet static void print_prog_plain(struct bpf_prog_info *info, int fd) 295743cc665SQuentin Monnet { 296743cc665SQuentin Monnet char *memlock; 297743cc665SQuentin Monnet 298743cc665SQuentin Monnet printf("%u: ", info->id); 299743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 300743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 301743cc665SQuentin Monnet else 302743cc665SQuentin Monnet printf("type %u ", info->type); 303743cc665SQuentin Monnet 304743cc665SQuentin Monnet if (*info->name) 305743cc665SQuentin Monnet printf("name %s ", info->name); 306743cc665SQuentin Monnet 307743cc665SQuentin Monnet printf("tag "); 308743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 30952262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 3109b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 311743cc665SQuentin Monnet printf("\n"); 312743cc665SQuentin Monnet 313743cc665SQuentin Monnet if (info->load_time) { 314743cc665SQuentin Monnet char buf[32]; 315743cc665SQuentin Monnet 316743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 317743cc665SQuentin Monnet 318743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 319743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 320743cc665SQuentin Monnet } 321743cc665SQuentin Monnet 322743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 323743cc665SQuentin Monnet 324743cc665SQuentin Monnet if (info->jited_prog_len) 325743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 32671bb428fSJakub Kicinski else 32771bb428fSJakub Kicinski printf(" not jited"); 32871bb428fSJakub Kicinski 32971bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 33071bb428fSJakub Kicinski if (memlock) 33171bb428fSJakub Kicinski printf(" memlock %sB", memlock); 33271bb428fSJakub Kicinski free(memlock); 33371bb428fSJakub Kicinski 334743cc665SQuentin Monnet if (info->nr_map_ids) 335743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 33671bb428fSJakub Kicinski 3374990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3384990f1f4SPrashant Bhole struct pinned_obj *obj; 3394990f1f4SPrashant Bhole 3404990f1f4SPrashant Bhole printf("\n"); 3414990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3424990f1f4SPrashant Bhole if (obj->id == info->id) 3434990f1f4SPrashant Bhole printf("\tpinned %s\n", obj->path); 3444990f1f4SPrashant Bhole } 3454990f1f4SPrashant Bhole } 3464990f1f4SPrashant Bhole 34771bb428fSJakub Kicinski printf("\n"); 348743cc665SQuentin Monnet } 349743cc665SQuentin Monnet 350743cc665SQuentin Monnet static int show_prog(int fd) 351743cc665SQuentin Monnet { 352743cc665SQuentin Monnet struct bpf_prog_info info = {}; 353743cc665SQuentin Monnet __u32 len = sizeof(info); 354743cc665SQuentin Monnet int err; 355743cc665SQuentin Monnet 356743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 357743cc665SQuentin Monnet if (err) { 3589a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 359743cc665SQuentin Monnet return -1; 360743cc665SQuentin Monnet } 361743cc665SQuentin Monnet 362743cc665SQuentin Monnet if (json_output) 363743cc665SQuentin Monnet print_prog_json(&info, fd); 364743cc665SQuentin Monnet else 365743cc665SQuentin Monnet print_prog_plain(&info, fd); 36671bb428fSJakub Kicinski 36771bb428fSJakub Kicinski return 0; 36871bb428fSJakub Kicinski } 36971bb428fSJakub Kicinski 37071bb428fSJakub Kicinski static int do_show(int argc, char **argv) 371743cc665SQuentin Monnet { 372743cc665SQuentin Monnet __u32 id = 0; 37371bb428fSJakub Kicinski int err; 37471bb428fSJakub Kicinski int fd; 37571bb428fSJakub Kicinski 376c541b734SPrashant Bhole if (show_pinned) 3774990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 3784990f1f4SPrashant Bhole 37971bb428fSJakub Kicinski if (argc == 2) { 38071bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 38171bb428fSJakub Kicinski if (fd < 0) 38271bb428fSJakub Kicinski return -1; 38371bb428fSJakub Kicinski 38471bb428fSJakub Kicinski return show_prog(fd); 38571bb428fSJakub Kicinski } 38671bb428fSJakub Kicinski 38771bb428fSJakub Kicinski if (argc) 38871bb428fSJakub Kicinski return BAD_ARG(); 38971bb428fSJakub Kicinski 390743cc665SQuentin Monnet if (json_output) 391743cc665SQuentin Monnet jsonw_start_array(json_wtr); 39271bb428fSJakub Kicinski while (true) { 39371bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 39471bb428fSJakub Kicinski if (err) { 3951739c26dSQuentin Monnet if (errno == ENOENT) { 3961739c26dSQuentin Monnet err = 0; 39771bb428fSJakub Kicinski break; 3981739c26dSQuentin Monnet } 3999a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 4009a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 401743cc665SQuentin Monnet err = -1; 402743cc665SQuentin Monnet break; 40371bb428fSJakub Kicinski } 40471bb428fSJakub Kicinski 40571bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 40671bb428fSJakub Kicinski if (fd < 0) { 4078207c6ddSJakub Kicinski if (errno == ENOENT) 4088207c6ddSJakub Kicinski continue; 4099a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 41071bb428fSJakub Kicinski id, strerror(errno)); 411743cc665SQuentin Monnet err = -1; 412743cc665SQuentin Monnet break; 41371bb428fSJakub Kicinski } 41471bb428fSJakub Kicinski 41571bb428fSJakub Kicinski err = show_prog(fd); 41671bb428fSJakub Kicinski close(fd); 41771bb428fSJakub Kicinski if (err) 418743cc665SQuentin Monnet break; 41971bb428fSJakub Kicinski } 42071bb428fSJakub Kicinski 421743cc665SQuentin Monnet if (json_output) 422743cc665SQuentin Monnet jsonw_end_array(json_wtr); 423743cc665SQuentin Monnet 424743cc665SQuentin Monnet return err; 42571bb428fSJakub Kicinski } 42671bb428fSJakub Kicinski 42771bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 42871bb428fSJakub Kicinski { 429f84192eeSSandipan Das unsigned long *func_ksyms = NULL; 43071bb428fSJakub Kicinski struct bpf_prog_info info = {}; 431f7f62c71SSandipan Das unsigned int *func_lens = NULL; 432f84192eeSSandipan Das unsigned int nr_func_ksyms; 433f7f62c71SSandipan Das unsigned int nr_func_lens; 4347105e828SDaniel Borkmann struct dump_data dd = {}; 43571bb428fSJakub Kicinski __u32 len = sizeof(info); 43671bb428fSJakub Kicinski unsigned int buf_size; 43771bb428fSJakub Kicinski char *filepath = NULL; 43871bb428fSJakub Kicinski bool opcodes = false; 439b6c1cedbSJiong Wang bool visual = false; 44071bb428fSJakub Kicinski unsigned char *buf; 44171bb428fSJakub Kicinski __u32 *member_len; 44271bb428fSJakub Kicinski __u64 *member_ptr; 44371bb428fSJakub Kicinski ssize_t n; 44471bb428fSJakub Kicinski int err; 44571bb428fSJakub Kicinski int fd; 44671bb428fSJakub Kicinski 44771bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 44871bb428fSJakub Kicinski member_len = &info.jited_prog_len; 44971bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 45071bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 45171bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 45271bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 45371bb428fSJakub Kicinski } else { 4549a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 45571bb428fSJakub Kicinski return -1; 45671bb428fSJakub Kicinski } 45771bb428fSJakub Kicinski NEXT_ARG(); 45871bb428fSJakub Kicinski 45971bb428fSJakub Kicinski if (argc < 2) 46071bb428fSJakub Kicinski usage(); 46171bb428fSJakub Kicinski 46271bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 46371bb428fSJakub Kicinski if (fd < 0) 46471bb428fSJakub Kicinski return -1; 46571bb428fSJakub Kicinski 46671bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 46771bb428fSJakub Kicinski NEXT_ARG(); 46871bb428fSJakub Kicinski if (!argc) { 4699a5ab8bfSQuentin Monnet p_err("expected file path"); 47071bb428fSJakub Kicinski return -1; 47171bb428fSJakub Kicinski } 47271bb428fSJakub Kicinski 47371bb428fSJakub Kicinski filepath = *argv; 47471bb428fSJakub Kicinski NEXT_ARG(); 47571bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 47671bb428fSJakub Kicinski opcodes = true; 47771bb428fSJakub Kicinski NEXT_ARG(); 478b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 479b6c1cedbSJiong Wang visual = true; 480b6c1cedbSJiong Wang NEXT_ARG(); 48171bb428fSJakub Kicinski } 48271bb428fSJakub Kicinski 48371bb428fSJakub Kicinski if (argc) { 48471bb428fSJakub Kicinski usage(); 48571bb428fSJakub Kicinski return -1; 48671bb428fSJakub Kicinski } 48771bb428fSJakub Kicinski 48871bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 48971bb428fSJakub Kicinski if (err) { 4909a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 49171bb428fSJakub Kicinski return -1; 49271bb428fSJakub Kicinski } 49371bb428fSJakub Kicinski 49471bb428fSJakub Kicinski if (!*member_len) { 4959a5ab8bfSQuentin Monnet p_info("no instructions returned"); 49671bb428fSJakub Kicinski close(fd); 49771bb428fSJakub Kicinski return 0; 49871bb428fSJakub Kicinski } 49971bb428fSJakub Kicinski 50071bb428fSJakub Kicinski buf_size = *member_len; 50171bb428fSJakub Kicinski 50271bb428fSJakub Kicinski buf = malloc(buf_size); 50371bb428fSJakub Kicinski if (!buf) { 5049a5ab8bfSQuentin Monnet p_err("mem alloc failed"); 50571bb428fSJakub Kicinski close(fd); 50671bb428fSJakub Kicinski return -1; 50771bb428fSJakub Kicinski } 50871bb428fSJakub Kicinski 509f84192eeSSandipan Das nr_func_ksyms = info.nr_jited_ksyms; 510f84192eeSSandipan Das if (nr_func_ksyms) { 511f84192eeSSandipan Das func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 512f84192eeSSandipan Das if (!func_ksyms) { 513f84192eeSSandipan Das p_err("mem alloc failed"); 514f84192eeSSandipan Das close(fd); 515f84192eeSSandipan Das goto err_free; 516f84192eeSSandipan Das } 517f84192eeSSandipan Das } 518f84192eeSSandipan Das 519f7f62c71SSandipan Das nr_func_lens = info.nr_jited_func_lens; 520f7f62c71SSandipan Das if (nr_func_lens) { 521f7f62c71SSandipan Das func_lens = malloc(nr_func_lens * sizeof(__u32)); 522f7f62c71SSandipan Das if (!func_lens) { 523f7f62c71SSandipan Das p_err("mem alloc failed"); 524f7f62c71SSandipan Das close(fd); 525f7f62c71SSandipan Das goto err_free; 526f7f62c71SSandipan Das } 527f7f62c71SSandipan Das } 528f7f62c71SSandipan Das 52971bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 53071bb428fSJakub Kicinski 53171bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 53271bb428fSJakub Kicinski *member_len = buf_size; 533f84192eeSSandipan Das info.jited_ksyms = ptr_to_u64(func_ksyms); 534f84192eeSSandipan Das info.nr_jited_ksyms = nr_func_ksyms; 535f7f62c71SSandipan Das info.jited_func_lens = ptr_to_u64(func_lens); 536f7f62c71SSandipan Das info.nr_jited_func_lens = nr_func_lens; 53771bb428fSJakub Kicinski 53871bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 53971bb428fSJakub Kicinski close(fd); 54071bb428fSJakub Kicinski if (err) { 5419a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 54271bb428fSJakub Kicinski goto err_free; 54371bb428fSJakub Kicinski } 54471bb428fSJakub Kicinski 54571bb428fSJakub Kicinski if (*member_len > buf_size) { 5469a5ab8bfSQuentin Monnet p_err("too many instructions returned"); 54771bb428fSJakub Kicinski goto err_free; 54871bb428fSJakub Kicinski } 54971bb428fSJakub Kicinski 550f84192eeSSandipan Das if (info.nr_jited_ksyms > nr_func_ksyms) { 551f84192eeSSandipan Das p_err("too many addresses returned"); 552f84192eeSSandipan Das goto err_free; 553f84192eeSSandipan Das } 554f84192eeSSandipan Das 555f7f62c71SSandipan Das if (info.nr_jited_func_lens > nr_func_lens) { 556f7f62c71SSandipan Das p_err("too many values returned"); 557f7f62c71SSandipan Das goto err_free; 558f7f62c71SSandipan Das } 559f7f62c71SSandipan Das 5607105e828SDaniel Borkmann if ((member_len == &info.jited_prog_len && 5617105e828SDaniel Borkmann info.jited_prog_insns == 0) || 5627105e828SDaniel Borkmann (member_len == &info.xlated_prog_len && 5637105e828SDaniel Borkmann info.xlated_prog_insns == 0)) { 5647105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 5657105e828SDaniel Borkmann goto err_free; 5667105e828SDaniel Borkmann } 5677105e828SDaniel Borkmann 56871bb428fSJakub Kicinski if (filepath) { 56971bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 57071bb428fSJakub Kicinski if (fd < 0) { 5719a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 57271bb428fSJakub Kicinski strerror(errno)); 57371bb428fSJakub Kicinski goto err_free; 57471bb428fSJakub Kicinski } 57571bb428fSJakub Kicinski 57671bb428fSJakub Kicinski n = write(fd, buf, *member_len); 57771bb428fSJakub Kicinski close(fd); 57871bb428fSJakub Kicinski if (n != *member_len) { 5799a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 58071bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 58171bb428fSJakub Kicinski goto err_free; 58271bb428fSJakub Kicinski } 58352c84d36SQuentin Monnet 58452c84d36SQuentin Monnet if (json_output) 58552c84d36SQuentin Monnet jsonw_null(json_wtr); 5863197239dSJiong Wang } else if (member_len == &info.jited_prog_len) { 587e6593596SJiong Wang const char *name = NULL; 588e6593596SJiong Wang 589e6593596SJiong Wang if (info.ifindex) { 590e6593596SJiong Wang name = ifindex_to_bfd_name_ns(info.ifindex, 591e6593596SJiong Wang info.netns_dev, 592e6593596SJiong Wang info.netns_ino); 593e6593596SJiong Wang if (!name) 594e6593596SJiong Wang goto err_free; 595e6593596SJiong Wang } 596e6593596SJiong Wang 597f7f62c71SSandipan Das if (info.nr_jited_func_lens && info.jited_func_lens) { 598f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 599f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 600f7f62c71SSandipan Das unsigned char *img = buf; 601f7f62c71SSandipan Das __u64 *ksyms = NULL; 602f7f62c71SSandipan Das __u32 *lens; 603f7f62c71SSandipan Das __u32 i; 604f7f62c71SSandipan Das 605f7f62c71SSandipan Das if (info.nr_jited_ksyms) { 606f7f62c71SSandipan Das kernel_syms_load(&dd); 607f7f62c71SSandipan Das ksyms = (__u64 *) info.jited_ksyms; 608f7f62c71SSandipan Das } 609f7f62c71SSandipan Das 610f7f62c71SSandipan Das if (json_output) 611f7f62c71SSandipan Das jsonw_start_array(json_wtr); 612f7f62c71SSandipan Das 613f7f62c71SSandipan Das lens = (__u32 *) info.jited_func_lens; 614f7f62c71SSandipan Das for (i = 0; i < info.nr_jited_func_lens; i++) { 615f7f62c71SSandipan Das if (ksyms) { 616f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 617f7f62c71SSandipan Das if (sym) 618f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 619f7f62c71SSandipan Das else 620f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 621f7f62c71SSandipan Das } else { 622f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 623f7f62c71SSandipan Das } 624f7f62c71SSandipan Das 625f7f62c71SSandipan Das if (json_output) { 626f7f62c71SSandipan Das jsonw_start_object(json_wtr); 627f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 628f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 629f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 630f7f62c71SSandipan Das } else { 631f7f62c71SSandipan Das printf("%s:\n", sym_name); 632f7f62c71SSandipan Das } 633f7f62c71SSandipan Das 634f7f62c71SSandipan Das disasm_print_insn(img, lens[i], opcodes, name); 635f7f62c71SSandipan Das img += lens[i]; 636f7f62c71SSandipan Das 637f7f62c71SSandipan Das if (json_output) 638f7f62c71SSandipan Das jsonw_end_object(json_wtr); 639f7f62c71SSandipan Das else 640f7f62c71SSandipan Das printf("\n"); 641f7f62c71SSandipan Das } 642f7f62c71SSandipan Das 643f7f62c71SSandipan Das if (json_output) 644f7f62c71SSandipan Das jsonw_end_array(json_wtr); 645f7f62c71SSandipan Das } else { 646e6593596SJiong Wang disasm_print_insn(buf, *member_len, opcodes, name); 647f7f62c71SSandipan Das } 648b6c1cedbSJiong Wang } else if (visual) { 649b6c1cedbSJiong Wang if (json_output) 650b6c1cedbSJiong Wang jsonw_null(json_wtr); 651b6c1cedbSJiong Wang else 652b6c1cedbSJiong Wang dump_xlated_cfg(buf, *member_len); 6537105e828SDaniel Borkmann } else { 6547105e828SDaniel Borkmann kernel_syms_load(&dd); 655f84192eeSSandipan Das dd.nr_jited_ksyms = info.nr_jited_ksyms; 656f84192eeSSandipan Das dd.jited_ksyms = (__u64 *) info.jited_ksyms; 657f84192eeSSandipan Das 658f05e2c32SQuentin Monnet if (json_output) 6597105e828SDaniel Borkmann dump_xlated_json(&dd, buf, *member_len, opcodes); 660f05e2c32SQuentin Monnet else 6617105e828SDaniel Borkmann dump_xlated_plain(&dd, buf, *member_len, opcodes); 6627105e828SDaniel Borkmann kernel_syms_destroy(&dd); 6637105e828SDaniel Borkmann } 66471bb428fSJakub Kicinski 66571bb428fSJakub Kicinski free(buf); 666f84192eeSSandipan Das free(func_ksyms); 667f7f62c71SSandipan Das free(func_lens); 66871bb428fSJakub Kicinski return 0; 66971bb428fSJakub Kicinski 67071bb428fSJakub Kicinski err_free: 67171bb428fSJakub Kicinski free(buf); 672f84192eeSSandipan Das free(func_ksyms); 673f7f62c71SSandipan Das free(func_lens); 67471bb428fSJakub Kicinski return -1; 67571bb428fSJakub Kicinski } 67671bb428fSJakub Kicinski 67771bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 67871bb428fSJakub Kicinski { 679004b45c0SQuentin Monnet int err; 680004b45c0SQuentin Monnet 681004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 682004b45c0SQuentin Monnet if (!err && json_output) 683004b45c0SQuentin Monnet jsonw_null(json_wtr); 684004b45c0SQuentin Monnet return err; 68571bb428fSJakub Kicinski } 68671bb428fSJakub Kicinski 6873ff5a4dcSJakub Kicinski struct map_replace { 6883ff5a4dcSJakub Kicinski int idx; 6893ff5a4dcSJakub Kicinski int fd; 6903ff5a4dcSJakub Kicinski char *name; 6913ff5a4dcSJakub Kicinski }; 6923ff5a4dcSJakub Kicinski 6933ff5a4dcSJakub Kicinski int map_replace_compar(const void *p1, const void *p2) 6943ff5a4dcSJakub Kicinski { 6953ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 6963ff5a4dcSJakub Kicinski 6973ff5a4dcSJakub Kicinski return a->idx - b->idx; 6983ff5a4dcSJakub Kicinski } 6993ff5a4dcSJakub Kicinski 70049a086c2SRoman Gushchin static int do_load(int argc, char **argv) 70149a086c2SRoman Gushchin { 702c8406848SJakub Kicinski enum bpf_attach_type expected_attach_type; 703c8406848SJakub Kicinski struct bpf_object_open_attr attr = { 704ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 705ba6dd679SJakub Kicinski }; 7063ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 7073ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 708c8406848SJakub Kicinski struct bpf_program *prog; 70949a086c2SRoman Gushchin struct bpf_object *obj; 710c8406848SJakub Kicinski struct bpf_map *map; 711c8406848SJakub Kicinski const char *pinfile; 7123ff5a4dcSJakub Kicinski unsigned int i, j; 713c8406848SJakub Kicinski __u32 ifindex = 0; 7143ff5a4dcSJakub Kicinski int idx, err; 71549a086c2SRoman Gushchin 7168d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 7178d1fc3deSJakub Kicinski return -1; 718c8406848SJakub Kicinski attr.file = GET_ARG(); 7198d1fc3deSJakub Kicinski pinfile = GET_ARG(); 72049a086c2SRoman Gushchin 721ba6dd679SJakub Kicinski while (argc) { 72249f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 72349f2cba3SJakub Kicinski char *type; 72449f2cba3SJakub Kicinski 72549f2cba3SJakub Kicinski NEXT_ARG(); 72649f2cba3SJakub Kicinski 72749f2cba3SJakub Kicinski if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 72849f2cba3SJakub Kicinski p_err("program type already specified"); 7293ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 73049f2cba3SJakub Kicinski } 73149f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 7323ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 73349f2cba3SJakub Kicinski 73449f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 73549f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 73649f2cba3SJakub Kicinski if (!type) { 73749f2cba3SJakub Kicinski p_err("mem alloc failed"); 7383ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 73949f2cba3SJakub Kicinski } 74049f2cba3SJakub Kicinski *type = 0; 74149f2cba3SJakub Kicinski strcat(type, *argv); 74249f2cba3SJakub Kicinski strcat(type, "/"); 74349f2cba3SJakub Kicinski 74449f2cba3SJakub Kicinski err = libbpf_prog_type_by_name(type, &attr.prog_type, 745c8406848SJakub Kicinski &expected_attach_type); 74649f2cba3SJakub Kicinski free(type); 74749f2cba3SJakub Kicinski if (err < 0) { 74849f2cba3SJakub Kicinski p_err("unknown program type '%s'", *argv); 7493ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 75049f2cba3SJakub Kicinski } 75149f2cba3SJakub Kicinski NEXT_ARG(); 7523ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 7533ff5a4dcSJakub Kicinski char *endptr, *name; 7543ff5a4dcSJakub Kicinski int fd; 7553ff5a4dcSJakub Kicinski 7563ff5a4dcSJakub Kicinski NEXT_ARG(); 7573ff5a4dcSJakub Kicinski 7583ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 7593ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 7603ff5a4dcSJakub Kicinski 7613ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 7623ff5a4dcSJakub Kicinski NEXT_ARG(); 7633ff5a4dcSJakub Kicinski 7643ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 7653ff5a4dcSJakub Kicinski if (*endptr) { 7663ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 7673ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 7683ff5a4dcSJakub Kicinski } 7693ff5a4dcSJakub Kicinski name = NULL; 7703ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 7713ff5a4dcSJakub Kicinski NEXT_ARG(); 7723ff5a4dcSJakub Kicinski 7733ff5a4dcSJakub Kicinski name = *argv; 7743ff5a4dcSJakub Kicinski idx = -1; 7753ff5a4dcSJakub Kicinski } else { 7763ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 7773ff5a4dcSJakub Kicinski *argv); 7783ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 7793ff5a4dcSJakub Kicinski } 7803ff5a4dcSJakub Kicinski NEXT_ARG(); 7813ff5a4dcSJakub Kicinski 7823ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 7833ff5a4dcSJakub Kicinski if (fd < 0) 7843ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 7853ff5a4dcSJakub Kicinski 7863ff5a4dcSJakub Kicinski map_replace = reallocarray(map_replace, old_map_fds + 1, 7873ff5a4dcSJakub Kicinski sizeof(*map_replace)); 7883ff5a4dcSJakub Kicinski if (!map_replace) { 7893ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 7903ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 7913ff5a4dcSJakub Kicinski } 7923ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 7933ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 7943ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 7953ff5a4dcSJakub Kicinski old_map_fds++; 79649f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 797ba6dd679SJakub Kicinski NEXT_ARG(); 798ba6dd679SJakub Kicinski 799c8406848SJakub Kicinski if (ifindex) { 800ba6dd679SJakub Kicinski p_err("offload device already specified"); 8013ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 802ba6dd679SJakub Kicinski } 803ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 8043ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 805ba6dd679SJakub Kicinski 806c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 807c8406848SJakub Kicinski if (!ifindex) { 808ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 809ba6dd679SJakub Kicinski *argv, strerror(errno)); 8103ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 811ba6dd679SJakub Kicinski } 812ba6dd679SJakub Kicinski NEXT_ARG(); 813ba6dd679SJakub Kicinski } else { 8143ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 815ba6dd679SJakub Kicinski *argv); 8163ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 817ba6dd679SJakub Kicinski } 818ba6dd679SJakub Kicinski } 819ba6dd679SJakub Kicinski 820c8406848SJakub Kicinski obj = bpf_object__open_xattr(&attr); 821c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 822c8406848SJakub Kicinski p_err("failed to open object file"); 8233ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 82449a086c2SRoman Gushchin } 82549a086c2SRoman Gushchin 826c8406848SJakub Kicinski prog = bpf_program__next(NULL, obj); 827c8406848SJakub Kicinski if (!prog) { 828c8406848SJakub Kicinski p_err("object file doesn't contain any bpf program"); 829c8406848SJakub Kicinski goto err_close_obj; 830c8406848SJakub Kicinski } 831c8406848SJakub Kicinski 832c8406848SJakub Kicinski bpf_program__set_ifindex(prog, ifindex); 833c8406848SJakub Kicinski if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 834c8406848SJakub Kicinski const char *sec_name = bpf_program__title(prog, false); 835c8406848SJakub Kicinski 836c8406848SJakub Kicinski err = libbpf_prog_type_by_name(sec_name, &attr.prog_type, 837c8406848SJakub Kicinski &expected_attach_type); 838c8406848SJakub Kicinski if (err < 0) { 839c8406848SJakub Kicinski p_err("failed to guess program type based on section name %s\n", 840c8406848SJakub Kicinski sec_name); 841c8406848SJakub Kicinski goto err_close_obj; 842c8406848SJakub Kicinski } 843c8406848SJakub Kicinski } 844c8406848SJakub Kicinski bpf_program__set_type(prog, attr.prog_type); 845c8406848SJakub Kicinski bpf_program__set_expected_attach_type(prog, expected_attach_type); 846c8406848SJakub Kicinski 8473ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 8483ff5a4dcSJakub Kicinski map_replace_compar); 8493ff5a4dcSJakub Kicinski 8503ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 8513ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 8523ff5a4dcSJakub Kicinski */ 8533ff5a4dcSJakub Kicinski j = 0; 8543ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 8553ff5a4dcSJakub Kicinski i = 0; 8563ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 8573ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 8583ff5a4dcSJakub Kicinski map_replace[j].idx = i; 8593ff5a4dcSJakub Kicinski break; 8603ff5a4dcSJakub Kicinski } 8613ff5a4dcSJakub Kicinski i++; 8623ff5a4dcSJakub Kicinski } 8633ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 8643ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 8653ff5a4dcSJakub Kicinski goto err_close_obj; 8663ff5a4dcSJakub Kicinski } 8673ff5a4dcSJakub Kicinski j++; 8683ff5a4dcSJakub Kicinski } 8693ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 8703ff5a4dcSJakub Kicinski if (j) 8713ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 8723ff5a4dcSJakub Kicinski map_replace_compar); 8733ff5a4dcSJakub Kicinski 8743ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 8753ff5a4dcSJakub Kicinski j = 0; 8763ff5a4dcSJakub Kicinski idx = 0; 8773ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 878c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 879c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 880c8406848SJakub Kicinski 8813ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 8823ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 8833ff5a4dcSJakub Kicinski if (err) { 8843ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 8853ff5a4dcSJakub Kicinski goto err_close_obj; 8863ff5a4dcSJakub Kicinski } 8873ff5a4dcSJakub Kicinski 8883ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 8893ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 8903ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 8913ff5a4dcSJakub Kicinski idx); 8923ff5a4dcSJakub Kicinski goto err_close_obj; 8933ff5a4dcSJakub Kicinski } 8943ff5a4dcSJakub Kicinski } 8953ff5a4dcSJakub Kicinski 8963ff5a4dcSJakub Kicinski idx++; 8973ff5a4dcSJakub Kicinski } 8983ff5a4dcSJakub Kicinski if (j < old_map_fds) { 8993ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 9003ff5a4dcSJakub Kicinski goto err_close_obj; 9013ff5a4dcSJakub Kicinski } 9023ff5a4dcSJakub Kicinski 903c8406848SJakub Kicinski err = bpf_object__load(obj); 904c8406848SJakub Kicinski if (err) { 905c8406848SJakub Kicinski p_err("failed to load object file"); 906c8406848SJakub Kicinski goto err_close_obj; 907c8406848SJakub Kicinski } 908c8406848SJakub Kicinski 909c8406848SJakub Kicinski if (do_pin_fd(bpf_program__fd(prog), pinfile)) 910bfee71fbSJakub Kicinski goto err_close_obj; 91149a086c2SRoman Gushchin 91249a086c2SRoman Gushchin if (json_output) 91349a086c2SRoman Gushchin jsonw_null(json_wtr); 91449a086c2SRoman Gushchin 915bfee71fbSJakub Kicinski bpf_object__close(obj); 9163ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 9173ff5a4dcSJakub Kicinski close(map_replace[i].fd); 9183ff5a4dcSJakub Kicinski free(map_replace); 919bfee71fbSJakub Kicinski 92049a086c2SRoman Gushchin return 0; 921bfee71fbSJakub Kicinski 922bfee71fbSJakub Kicinski err_close_obj: 923bfee71fbSJakub Kicinski bpf_object__close(obj); 9243ff5a4dcSJakub Kicinski err_free_reuse_maps: 9253ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 9263ff5a4dcSJakub Kicinski close(map_replace[i].fd); 9273ff5a4dcSJakub Kicinski free(map_replace); 928bfee71fbSJakub Kicinski return -1; 92949a086c2SRoman Gushchin } 93049a086c2SRoman Gushchin 93171bb428fSJakub Kicinski static int do_help(int argc, char **argv) 93271bb428fSJakub Kicinski { 933004b45c0SQuentin Monnet if (json_output) { 934004b45c0SQuentin Monnet jsonw_null(json_wtr); 935004b45c0SQuentin Monnet return 0; 936004b45c0SQuentin Monnet } 937004b45c0SQuentin Monnet 93871bb428fSJakub Kicinski fprintf(stderr, 9396ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 940b6c1cedbSJiong Wang " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 9418dfbc6d1SQuentin Monnet " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 94271bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 9433ff5a4dcSJakub Kicinski " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" 9443ff5a4dcSJakub Kicinski " [map { idx IDX | name NAME } MAP]\n" 94571bb428fSJakub Kicinski " %s %s help\n" 94671bb428fSJakub Kicinski "\n" 9473ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 94871bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 94949f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 95049f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 95149f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 95249f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 95349f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 95449f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 95549f2cba3SJakub Kicinski " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 9560641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 95771bb428fSJakub Kicinski "", 95871bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 95949a086c2SRoman Gushchin bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 96071bb428fSJakub Kicinski 96171bb428fSJakub Kicinski return 0; 96271bb428fSJakub Kicinski } 96371bb428fSJakub Kicinski 96471bb428fSJakub Kicinski static const struct cmd cmds[] = { 96571bb428fSJakub Kicinski { "show", do_show }, 9666ebe6dbdSJakub Kicinski { "list", do_show }, 9679f606179SQuentin Monnet { "help", do_help }, 96871bb428fSJakub Kicinski { "dump", do_dump }, 96971bb428fSJakub Kicinski { "pin", do_pin }, 97049a086c2SRoman Gushchin { "load", do_load }, 97171bb428fSJakub Kicinski { 0 } 97271bb428fSJakub Kicinski }; 97371bb428fSJakub Kicinski 97471bb428fSJakub Kicinski int do_prog(int argc, char **argv) 97571bb428fSJakub Kicinski { 97671bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 97771bb428fSJakub Kicinski } 978