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> 50*254471e5SYonghong 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 5771bb428fSJakub Kicinski static const char * const prog_type_name[] = { 5871bb428fSJakub Kicinski [BPF_PROG_TYPE_UNSPEC] = "unspec", 5971bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 6071bb428fSJakub Kicinski [BPF_PROG_TYPE_KPROBE] = "kprobe", 6171bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 6271bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 6371bb428fSJakub Kicinski [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 6471bb428fSJakub Kicinski [BPF_PROG_TYPE_XDP] = "xdp", 6571bb428fSJakub Kicinski [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 6671bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 6771bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 6871bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 6971bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 7071bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 7171bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 7271bb428fSJakub Kicinski [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 7345e5e121SRoman Gushchin [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 74393de512SAndrey Ignatov [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 75393de512SAndrey Ignatov [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 76393de512SAndrey Ignatov [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 776bdd533cSSean Young [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 78c22fbae7SPetar Penkov [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", 7971bb428fSJakub Kicinski }; 8071bb428fSJakub Kicinski 81b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 82b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 83b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 84b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 85092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 86b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 87b7d3826cSJohn Fastabend }; 88b7d3826cSJohn Fastabend 89b7d3826cSJohn Fastabend enum bpf_attach_type parse_attach_type(const char *str) 90b7d3826cSJohn Fastabend { 91b7d3826cSJohn Fastabend enum bpf_attach_type type; 92b7d3826cSJohn Fastabend 93b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 94b7d3826cSJohn Fastabend if (attach_type_strings[type] && 95b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 96b7d3826cSJohn Fastabend return type; 97b7d3826cSJohn Fastabend } 98b7d3826cSJohn Fastabend 99b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 100b7d3826cSJohn Fastabend } 101b7d3826cSJohn Fastabend 10271bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 10371bb428fSJakub Kicinski { 10471bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 10571bb428fSJakub Kicinski time_t wallclock_secs; 10671bb428fSJakub Kicinski struct tm load_tm; 10771bb428fSJakub Kicinski 10871bb428fSJakub Kicinski buf[--size] = '\0'; 10971bb428fSJakub Kicinski 11071bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 11171bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 11271bb428fSJakub Kicinski perror("Can't read clocks"); 11371bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 11471bb428fSJakub Kicinski return; 11571bb428fSJakub Kicinski } 11671bb428fSJakub Kicinski 11771bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 11807480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 11907480cbcSJakub Kicinski 1000000000; 12007480cbcSJakub Kicinski 12171bb428fSJakub Kicinski 12271bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 12371bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 12471bb428fSJakub Kicinski return; 12571bb428fSJakub Kicinski } 12671bb428fSJakub Kicinski 127a3fe1f6fSQuentin Monnet if (json_output) 128a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 129a3fe1f6fSQuentin Monnet else 130a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 13171bb428fSJakub Kicinski } 13271bb428fSJakub Kicinski 13371bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 13471bb428fSJakub Kicinski { 13571bb428fSJakub Kicinski struct bpf_prog_info info = {}; 13671bb428fSJakub Kicinski __u32 len = sizeof(info); 13771bb428fSJakub Kicinski unsigned int id = 0; 13871bb428fSJakub Kicinski int err; 13971bb428fSJakub Kicinski int fd; 14071bb428fSJakub Kicinski 14171bb428fSJakub Kicinski while (true) { 14271bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 14371bb428fSJakub Kicinski if (err) { 1449a5ab8bfSQuentin Monnet p_err("%s", strerror(errno)); 14571bb428fSJakub Kicinski return -1; 14671bb428fSJakub Kicinski } 14771bb428fSJakub Kicinski 14871bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 14971bb428fSJakub Kicinski if (fd < 0) { 1509a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 15171bb428fSJakub Kicinski id, strerror(errno)); 15271bb428fSJakub Kicinski return -1; 15371bb428fSJakub Kicinski } 15471bb428fSJakub Kicinski 15571bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 15671bb428fSJakub Kicinski if (err) { 1579a5ab8bfSQuentin Monnet p_err("can't get prog info (%u): %s", 15871bb428fSJakub Kicinski id, strerror(errno)); 15971bb428fSJakub Kicinski close(fd); 16071bb428fSJakub Kicinski return -1; 16171bb428fSJakub Kicinski } 16271bb428fSJakub Kicinski 16371bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 16471bb428fSJakub Kicinski return fd; 16571bb428fSJakub Kicinski 16671bb428fSJakub Kicinski close(fd); 16771bb428fSJakub Kicinski } 16871bb428fSJakub Kicinski } 16971bb428fSJakub Kicinski 17071bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 17171bb428fSJakub Kicinski { 17271bb428fSJakub Kicinski int fd; 17371bb428fSJakub Kicinski 17471bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 17571bb428fSJakub Kicinski unsigned int id; 17671bb428fSJakub Kicinski char *endptr; 17771bb428fSJakub Kicinski 17871bb428fSJakub Kicinski NEXT_ARGP(); 17971bb428fSJakub Kicinski 18071bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 18171bb428fSJakub Kicinski if (*endptr) { 1829a5ab8bfSQuentin Monnet p_err("can't parse %s as ID", **argv); 18371bb428fSJakub Kicinski return -1; 18471bb428fSJakub Kicinski } 18571bb428fSJakub Kicinski NEXT_ARGP(); 18671bb428fSJakub Kicinski 18771bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 18871bb428fSJakub Kicinski if (fd < 0) 1899a5ab8bfSQuentin Monnet p_err("get by id (%u): %s", id, strerror(errno)); 19071bb428fSJakub Kicinski return fd; 19171bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 19271bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 19371bb428fSJakub Kicinski 19471bb428fSJakub Kicinski NEXT_ARGP(); 19571bb428fSJakub Kicinski 19671bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 19771bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 19871bb428fSJakub Kicinski != BPF_TAG_SIZE) { 1999a5ab8bfSQuentin Monnet p_err("can't parse tag"); 20071bb428fSJakub Kicinski return -1; 20171bb428fSJakub Kicinski } 20271bb428fSJakub Kicinski NEXT_ARGP(); 20371bb428fSJakub Kicinski 20471bb428fSJakub Kicinski return prog_fd_by_tag(tag); 20571bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 20671bb428fSJakub Kicinski char *path; 20771bb428fSJakub Kicinski 20871bb428fSJakub Kicinski NEXT_ARGP(); 20971bb428fSJakub Kicinski 21071bb428fSJakub Kicinski path = **argv; 21171bb428fSJakub Kicinski NEXT_ARGP(); 21271bb428fSJakub Kicinski 21371bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 21471bb428fSJakub Kicinski } 21571bb428fSJakub Kicinski 2169a5ab8bfSQuentin Monnet p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 21771bb428fSJakub Kicinski return -1; 21871bb428fSJakub Kicinski } 21971bb428fSJakub Kicinski 22071bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 22171bb428fSJakub Kicinski { 22271bb428fSJakub Kicinski struct bpf_prog_info info = {}; 22371bb428fSJakub Kicinski __u32 len = sizeof(info); 22471bb428fSJakub Kicinski __u32 map_ids[num_maps]; 22571bb428fSJakub Kicinski unsigned int i; 22671bb428fSJakub Kicinski int err; 22771bb428fSJakub Kicinski 22871bb428fSJakub Kicinski info.nr_map_ids = num_maps; 22971bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 23071bb428fSJakub Kicinski 23171bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 23271bb428fSJakub Kicinski if (err || !info.nr_map_ids) 23371bb428fSJakub Kicinski return; 23471bb428fSJakub Kicinski 235743cc665SQuentin Monnet if (json_output) { 236743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 237743cc665SQuentin Monnet jsonw_start_array(json_wtr); 238743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 239743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 240743cc665SQuentin Monnet jsonw_end_array(json_wtr); 241743cc665SQuentin Monnet } else { 24271bb428fSJakub Kicinski printf(" map_ids "); 24371bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 24471bb428fSJakub Kicinski printf("%u%s", map_ids[i], 24571bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 24671bb428fSJakub Kicinski } 24771bb428fSJakub Kicinski } 24871bb428fSJakub Kicinski 249743cc665SQuentin Monnet static void print_prog_json(struct bpf_prog_info *info, int fd) 250743cc665SQuentin Monnet { 251743cc665SQuentin Monnet char *memlock; 252743cc665SQuentin Monnet 253743cc665SQuentin Monnet jsonw_start_object(json_wtr); 254743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 255743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 256743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 257743cc665SQuentin Monnet prog_type_name[info->type]); 25871bb428fSJakub Kicinski else 259743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 26071bb428fSJakub Kicinski 261743cc665SQuentin Monnet if (*info->name) 262743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 26371bb428fSJakub Kicinski 264743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 265743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 266743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 267743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 26871bb428fSJakub Kicinski 2699b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 2709b984a20SJiri Olsa 27152262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 27252262210SJakub Kicinski 273743cc665SQuentin Monnet if (info->load_time) { 27471bb428fSJakub Kicinski char buf[32]; 27571bb428fSJakub Kicinski 276743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 27771bb428fSJakub Kicinski 27871bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 279a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 280a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 281743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 28271bb428fSJakub Kicinski } 28371bb428fSJakub Kicinski 284743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 28571bb428fSJakub Kicinski 286743cc665SQuentin Monnet if (info->jited_prog_len) { 287743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 288743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 289743cc665SQuentin Monnet } else { 290743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 291743cc665SQuentin Monnet } 292743cc665SQuentin Monnet 293743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 294743cc665SQuentin Monnet if (memlock) 295743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 296743cc665SQuentin Monnet free(memlock); 297743cc665SQuentin Monnet 298743cc665SQuentin Monnet if (info->nr_map_ids) 299743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 300743cc665SQuentin Monnet 3014990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3024990f1f4SPrashant Bhole struct pinned_obj *obj; 3034990f1f4SPrashant Bhole 3044990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 3054990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 3064990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3074990f1f4SPrashant Bhole if (obj->id == info->id) 3084990f1f4SPrashant Bhole jsonw_string(json_wtr, obj->path); 3094990f1f4SPrashant Bhole } 3104990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 3114990f1f4SPrashant Bhole } 3124990f1f4SPrashant Bhole 313743cc665SQuentin Monnet jsonw_end_object(json_wtr); 314743cc665SQuentin Monnet } 315743cc665SQuentin Monnet 316743cc665SQuentin Monnet static void print_prog_plain(struct bpf_prog_info *info, int fd) 317743cc665SQuentin Monnet { 318743cc665SQuentin Monnet char *memlock; 319743cc665SQuentin Monnet 320743cc665SQuentin Monnet printf("%u: ", info->id); 321743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 322743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 323743cc665SQuentin Monnet else 324743cc665SQuentin Monnet printf("type %u ", info->type); 325743cc665SQuentin Monnet 326743cc665SQuentin Monnet if (*info->name) 327743cc665SQuentin Monnet printf("name %s ", info->name); 328743cc665SQuentin Monnet 329743cc665SQuentin Monnet printf("tag "); 330743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 33152262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 3329b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 333743cc665SQuentin Monnet printf("\n"); 334743cc665SQuentin Monnet 335743cc665SQuentin Monnet if (info->load_time) { 336743cc665SQuentin Monnet char buf[32]; 337743cc665SQuentin Monnet 338743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 339743cc665SQuentin Monnet 340743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 341743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 342743cc665SQuentin Monnet } 343743cc665SQuentin Monnet 344743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 345743cc665SQuentin Monnet 346743cc665SQuentin Monnet if (info->jited_prog_len) 347743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 34871bb428fSJakub Kicinski else 34971bb428fSJakub Kicinski printf(" not jited"); 35071bb428fSJakub Kicinski 35171bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 35271bb428fSJakub Kicinski if (memlock) 35371bb428fSJakub Kicinski printf(" memlock %sB", memlock); 35471bb428fSJakub Kicinski free(memlock); 35571bb428fSJakub Kicinski 356743cc665SQuentin Monnet if (info->nr_map_ids) 357743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 35871bb428fSJakub Kicinski 3594990f1f4SPrashant Bhole if (!hash_empty(prog_table.table)) { 3604990f1f4SPrashant Bhole struct pinned_obj *obj; 3614990f1f4SPrashant Bhole 3624990f1f4SPrashant Bhole printf("\n"); 3634990f1f4SPrashant Bhole hash_for_each_possible(prog_table.table, obj, hash, info->id) { 3644990f1f4SPrashant Bhole if (obj->id == info->id) 3654990f1f4SPrashant Bhole printf("\tpinned %s\n", obj->path); 3664990f1f4SPrashant Bhole } 3674990f1f4SPrashant Bhole } 3684990f1f4SPrashant Bhole 36971bb428fSJakub Kicinski printf("\n"); 370743cc665SQuentin Monnet } 371743cc665SQuentin Monnet 372743cc665SQuentin Monnet static int show_prog(int fd) 373743cc665SQuentin Monnet { 374743cc665SQuentin Monnet struct bpf_prog_info info = {}; 375743cc665SQuentin Monnet __u32 len = sizeof(info); 376743cc665SQuentin Monnet int err; 377743cc665SQuentin Monnet 378743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 379743cc665SQuentin Monnet if (err) { 3809a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 381743cc665SQuentin Monnet return -1; 382743cc665SQuentin Monnet } 383743cc665SQuentin Monnet 384743cc665SQuentin Monnet if (json_output) 385743cc665SQuentin Monnet print_prog_json(&info, fd); 386743cc665SQuentin Monnet else 387743cc665SQuentin Monnet print_prog_plain(&info, fd); 38871bb428fSJakub Kicinski 38971bb428fSJakub Kicinski return 0; 39071bb428fSJakub Kicinski } 39171bb428fSJakub Kicinski 39271bb428fSJakub Kicinski static int do_show(int argc, char **argv) 393743cc665SQuentin Monnet { 394743cc665SQuentin Monnet __u32 id = 0; 39571bb428fSJakub Kicinski int err; 39671bb428fSJakub Kicinski int fd; 39771bb428fSJakub Kicinski 398c541b734SPrashant Bhole if (show_pinned) 3994990f1f4SPrashant Bhole build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 4004990f1f4SPrashant Bhole 40171bb428fSJakub Kicinski if (argc == 2) { 40271bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 40371bb428fSJakub Kicinski if (fd < 0) 40471bb428fSJakub Kicinski return -1; 40571bb428fSJakub Kicinski 40671bb428fSJakub Kicinski return show_prog(fd); 40771bb428fSJakub Kicinski } 40871bb428fSJakub Kicinski 40971bb428fSJakub Kicinski if (argc) 41071bb428fSJakub Kicinski return BAD_ARG(); 41171bb428fSJakub Kicinski 412743cc665SQuentin Monnet if (json_output) 413743cc665SQuentin Monnet jsonw_start_array(json_wtr); 41471bb428fSJakub Kicinski while (true) { 41571bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 41671bb428fSJakub Kicinski if (err) { 4171739c26dSQuentin Monnet if (errno == ENOENT) { 4181739c26dSQuentin Monnet err = 0; 41971bb428fSJakub Kicinski break; 4201739c26dSQuentin Monnet } 4219a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 4229a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 423743cc665SQuentin Monnet err = -1; 424743cc665SQuentin Monnet break; 42571bb428fSJakub Kicinski } 42671bb428fSJakub Kicinski 42771bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 42871bb428fSJakub Kicinski if (fd < 0) { 4298207c6ddSJakub Kicinski if (errno == ENOENT) 4308207c6ddSJakub Kicinski continue; 4319a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 43271bb428fSJakub Kicinski id, strerror(errno)); 433743cc665SQuentin Monnet err = -1; 434743cc665SQuentin Monnet break; 43571bb428fSJakub Kicinski } 43671bb428fSJakub Kicinski 43771bb428fSJakub Kicinski err = show_prog(fd); 43871bb428fSJakub Kicinski close(fd); 43971bb428fSJakub Kicinski if (err) 440743cc665SQuentin Monnet break; 44171bb428fSJakub Kicinski } 44271bb428fSJakub Kicinski 443743cc665SQuentin Monnet if (json_output) 444743cc665SQuentin Monnet jsonw_end_array(json_wtr); 445743cc665SQuentin Monnet 446743cc665SQuentin Monnet return err; 44771bb428fSJakub Kicinski } 44871bb428fSJakub Kicinski 44971bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 45071bb428fSJakub Kicinski { 451f84192eeSSandipan Das unsigned long *func_ksyms = NULL; 45271bb428fSJakub Kicinski struct bpf_prog_info info = {}; 453f7f62c71SSandipan Das unsigned int *func_lens = NULL; 4543ddeac67SJakub Kicinski const char *disasm_opt = NULL; 455*254471e5SYonghong Song unsigned int finfo_rec_size; 456f84192eeSSandipan Das unsigned int nr_func_ksyms; 457f7f62c71SSandipan Das unsigned int nr_func_lens; 4587105e828SDaniel Borkmann struct dump_data dd = {}; 45971bb428fSJakub Kicinski __u32 len = sizeof(info); 460*254471e5SYonghong Song struct btf *btf = NULL; 461*254471e5SYonghong Song void *func_info = NULL; 462*254471e5SYonghong Song unsigned int finfo_cnt; 46371bb428fSJakub Kicinski unsigned int buf_size; 46471bb428fSJakub Kicinski char *filepath = NULL; 46571bb428fSJakub Kicinski bool opcodes = false; 466b6c1cedbSJiong Wang bool visual = false; 467*254471e5SYonghong Song char func_sig[1024]; 46871bb428fSJakub Kicinski unsigned char *buf; 46971bb428fSJakub Kicinski __u32 *member_len; 47071bb428fSJakub Kicinski __u64 *member_ptr; 47171bb428fSJakub Kicinski ssize_t n; 47271bb428fSJakub Kicinski int err; 47371bb428fSJakub Kicinski int fd; 47471bb428fSJakub Kicinski 47571bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 47629a9c10eSStanislav Fomichev if (disasm_init()) 47729a9c10eSStanislav Fomichev return -1; 47829a9c10eSStanislav Fomichev 47971bb428fSJakub Kicinski member_len = &info.jited_prog_len; 48071bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 48171bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 48271bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 48371bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 48471bb428fSJakub Kicinski } else { 4859a5ab8bfSQuentin Monnet p_err("expected 'xlated' or 'jited', got: %s", *argv); 48671bb428fSJakub Kicinski return -1; 48771bb428fSJakub Kicinski } 48871bb428fSJakub Kicinski NEXT_ARG(); 48971bb428fSJakub Kicinski 49071bb428fSJakub Kicinski if (argc < 2) 49171bb428fSJakub Kicinski usage(); 49271bb428fSJakub Kicinski 49371bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 49471bb428fSJakub Kicinski if (fd < 0) 49571bb428fSJakub Kicinski return -1; 49671bb428fSJakub Kicinski 49771bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 49871bb428fSJakub Kicinski NEXT_ARG(); 49971bb428fSJakub Kicinski if (!argc) { 5009a5ab8bfSQuentin Monnet p_err("expected file path"); 50171bb428fSJakub Kicinski return -1; 50271bb428fSJakub Kicinski } 50371bb428fSJakub Kicinski 50471bb428fSJakub Kicinski filepath = *argv; 50571bb428fSJakub Kicinski NEXT_ARG(); 50671bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 50771bb428fSJakub Kicinski opcodes = true; 50871bb428fSJakub Kicinski NEXT_ARG(); 509b6c1cedbSJiong Wang } else if (is_prefix(*argv, "visual")) { 510b6c1cedbSJiong Wang visual = true; 511b6c1cedbSJiong Wang NEXT_ARG(); 51271bb428fSJakub Kicinski } 51371bb428fSJakub Kicinski 51471bb428fSJakub Kicinski if (argc) { 51571bb428fSJakub Kicinski usage(); 51671bb428fSJakub Kicinski return -1; 51771bb428fSJakub Kicinski } 51871bb428fSJakub Kicinski 51971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 52071bb428fSJakub Kicinski if (err) { 5219a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 52271bb428fSJakub Kicinski return -1; 52371bb428fSJakub Kicinski } 52471bb428fSJakub Kicinski 52571bb428fSJakub Kicinski if (!*member_len) { 5269a5ab8bfSQuentin Monnet p_info("no instructions returned"); 52771bb428fSJakub Kicinski close(fd); 52871bb428fSJakub Kicinski return 0; 52971bb428fSJakub Kicinski } 53071bb428fSJakub Kicinski 53171bb428fSJakub Kicinski buf_size = *member_len; 53271bb428fSJakub Kicinski 53371bb428fSJakub Kicinski buf = malloc(buf_size); 53471bb428fSJakub Kicinski if (!buf) { 5359a5ab8bfSQuentin Monnet p_err("mem alloc failed"); 53671bb428fSJakub Kicinski close(fd); 53771bb428fSJakub Kicinski return -1; 53871bb428fSJakub Kicinski } 53971bb428fSJakub Kicinski 540f84192eeSSandipan Das nr_func_ksyms = info.nr_jited_ksyms; 541f84192eeSSandipan Das if (nr_func_ksyms) { 542f84192eeSSandipan Das func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 543f84192eeSSandipan Das if (!func_ksyms) { 544f84192eeSSandipan Das p_err("mem alloc failed"); 545f84192eeSSandipan Das close(fd); 546f84192eeSSandipan Das goto err_free; 547f84192eeSSandipan Das } 548f84192eeSSandipan Das } 549f84192eeSSandipan Das 550f7f62c71SSandipan Das nr_func_lens = info.nr_jited_func_lens; 551f7f62c71SSandipan Das if (nr_func_lens) { 552f7f62c71SSandipan Das func_lens = malloc(nr_func_lens * sizeof(__u32)); 553f7f62c71SSandipan Das if (!func_lens) { 554f7f62c71SSandipan Das p_err("mem alloc failed"); 555f7f62c71SSandipan Das close(fd); 556f7f62c71SSandipan Das goto err_free; 557f7f62c71SSandipan Das } 558f7f62c71SSandipan Das } 559f7f62c71SSandipan Das 560*254471e5SYonghong Song finfo_cnt = info.func_info_cnt; 561*254471e5SYonghong Song finfo_rec_size = info.func_info_rec_size; 562*254471e5SYonghong Song if (finfo_cnt && finfo_rec_size) { 563*254471e5SYonghong Song func_info = malloc(finfo_cnt * finfo_rec_size); 564*254471e5SYonghong Song if (!func_info) { 565*254471e5SYonghong Song p_err("mem alloc failed"); 566*254471e5SYonghong Song close(fd); 567*254471e5SYonghong Song goto err_free; 568*254471e5SYonghong Song } 569*254471e5SYonghong Song } 570*254471e5SYonghong Song 57171bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 57271bb428fSJakub Kicinski 57371bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 57471bb428fSJakub Kicinski *member_len = buf_size; 575f84192eeSSandipan Das info.jited_ksyms = ptr_to_u64(func_ksyms); 576f84192eeSSandipan Das info.nr_jited_ksyms = nr_func_ksyms; 577f7f62c71SSandipan Das info.jited_func_lens = ptr_to_u64(func_lens); 578f7f62c71SSandipan Das info.nr_jited_func_lens = nr_func_lens; 579*254471e5SYonghong Song info.func_info_cnt = finfo_cnt; 580*254471e5SYonghong Song info.func_info_rec_size = finfo_rec_size; 581*254471e5SYonghong Song info.func_info = ptr_to_u64(func_info); 58271bb428fSJakub Kicinski 58371bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 58471bb428fSJakub Kicinski close(fd); 58571bb428fSJakub Kicinski if (err) { 5869a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 58771bb428fSJakub Kicinski goto err_free; 58871bb428fSJakub Kicinski } 58971bb428fSJakub Kicinski 59071bb428fSJakub Kicinski if (*member_len > buf_size) { 5919a5ab8bfSQuentin Monnet p_err("too many instructions returned"); 59271bb428fSJakub Kicinski goto err_free; 59371bb428fSJakub Kicinski } 59471bb428fSJakub Kicinski 595f84192eeSSandipan Das if (info.nr_jited_ksyms > nr_func_ksyms) { 596f84192eeSSandipan Das p_err("too many addresses returned"); 597f84192eeSSandipan Das goto err_free; 598f84192eeSSandipan Das } 599f84192eeSSandipan Das 600f7f62c71SSandipan Das if (info.nr_jited_func_lens > nr_func_lens) { 601f7f62c71SSandipan Das p_err("too many values returned"); 602f7f62c71SSandipan Das goto err_free; 603f7f62c71SSandipan Das } 604f7f62c71SSandipan Das 605*254471e5SYonghong Song if (info.func_info_cnt != finfo_cnt) { 606*254471e5SYonghong Song p_err("incorrect func_info_cnt %d vs. expected %d", 607*254471e5SYonghong Song info.func_info_cnt, finfo_cnt); 608*254471e5SYonghong Song goto err_free; 609*254471e5SYonghong Song } 610*254471e5SYonghong Song 611*254471e5SYonghong Song if (info.func_info_rec_size != finfo_rec_size) { 612*254471e5SYonghong Song p_err("incorrect func_info_rec_size %d vs. expected %d", 613*254471e5SYonghong Song info.func_info_rec_size, finfo_rec_size); 614*254471e5SYonghong Song goto err_free; 615*254471e5SYonghong Song } 616*254471e5SYonghong Song 6177105e828SDaniel Borkmann if ((member_len == &info.jited_prog_len && 6187105e828SDaniel Borkmann info.jited_prog_insns == 0) || 6197105e828SDaniel Borkmann (member_len == &info.xlated_prog_len && 6207105e828SDaniel Borkmann info.xlated_prog_insns == 0)) { 6217105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 6227105e828SDaniel Borkmann goto err_free; 6237105e828SDaniel Borkmann } 6247105e828SDaniel Borkmann 625*254471e5SYonghong Song if (info.btf_id && btf_get_from_id(info.btf_id, &btf)) { 626*254471e5SYonghong Song p_err("failed to get btf"); 627*254471e5SYonghong Song goto err_free; 628*254471e5SYonghong Song } 629*254471e5SYonghong Song 63071bb428fSJakub Kicinski if (filepath) { 63171bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 63271bb428fSJakub Kicinski if (fd < 0) { 6339a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 63471bb428fSJakub Kicinski strerror(errno)); 63571bb428fSJakub Kicinski goto err_free; 63671bb428fSJakub Kicinski } 63771bb428fSJakub Kicinski 63871bb428fSJakub Kicinski n = write(fd, buf, *member_len); 63971bb428fSJakub Kicinski close(fd); 64071bb428fSJakub Kicinski if (n != *member_len) { 6419a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 64271bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 64371bb428fSJakub Kicinski goto err_free; 64471bb428fSJakub Kicinski } 64552c84d36SQuentin Monnet 64652c84d36SQuentin Monnet if (json_output) 64752c84d36SQuentin Monnet jsonw_null(json_wtr); 6483197239dSJiong Wang } else if (member_len == &info.jited_prog_len) { 649e6593596SJiong Wang const char *name = NULL; 650e6593596SJiong Wang 651e6593596SJiong Wang if (info.ifindex) { 6523ddeac67SJakub Kicinski name = ifindex_to_bfd_params(info.ifindex, 653e6593596SJiong Wang info.netns_dev, 6543ddeac67SJakub Kicinski info.netns_ino, 6553ddeac67SJakub Kicinski &disasm_opt); 656e6593596SJiong Wang if (!name) 657e6593596SJiong Wang goto err_free; 658e6593596SJiong Wang } 659e6593596SJiong Wang 660f7f62c71SSandipan Das if (info.nr_jited_func_lens && info.jited_func_lens) { 661f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 662*254471e5SYonghong Song struct bpf_func_info *record; 663f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 664f7f62c71SSandipan Das unsigned char *img = buf; 665f7f62c71SSandipan Das __u64 *ksyms = NULL; 666f7f62c71SSandipan Das __u32 *lens; 667f7f62c71SSandipan Das __u32 i; 668f7f62c71SSandipan Das 669f7f62c71SSandipan Das if (info.nr_jited_ksyms) { 670f7f62c71SSandipan Das kernel_syms_load(&dd); 671f7f62c71SSandipan Das ksyms = (__u64 *) info.jited_ksyms; 672f7f62c71SSandipan Das } 673f7f62c71SSandipan Das 674f7f62c71SSandipan Das if (json_output) 675f7f62c71SSandipan Das jsonw_start_array(json_wtr); 676f7f62c71SSandipan Das 677f7f62c71SSandipan Das lens = (__u32 *) info.jited_func_lens; 678f7f62c71SSandipan Das for (i = 0; i < info.nr_jited_func_lens; i++) { 679f7f62c71SSandipan Das if (ksyms) { 680f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 681f7f62c71SSandipan Das if (sym) 682f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 683f7f62c71SSandipan Das else 684f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 685f7f62c71SSandipan Das } else { 686f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 687f7f62c71SSandipan Das } 688f7f62c71SSandipan Das 689*254471e5SYonghong Song if (func_info) { 690*254471e5SYonghong Song record = func_info + i * finfo_rec_size; 691*254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 692*254471e5SYonghong Song func_sig, 693*254471e5SYonghong Song sizeof(func_sig)); 694*254471e5SYonghong Song } 695*254471e5SYonghong Song 696f7f62c71SSandipan Das if (json_output) { 697f7f62c71SSandipan Das jsonw_start_object(json_wtr); 698*254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 699*254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 700*254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 701*254471e5SYonghong Song } 702f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 703f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 704f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 705f7f62c71SSandipan Das } else { 706*254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 707*254471e5SYonghong Song printf("%s:\n", func_sig); 708f7f62c71SSandipan Das printf("%s:\n", sym_name); 709f7f62c71SSandipan Das } 710f7f62c71SSandipan Das 7113ddeac67SJakub Kicinski disasm_print_insn(img, lens[i], opcodes, name, 7123ddeac67SJakub Kicinski disasm_opt); 713f7f62c71SSandipan Das img += lens[i]; 714f7f62c71SSandipan Das 715f7f62c71SSandipan Das if (json_output) 716f7f62c71SSandipan Das jsonw_end_object(json_wtr); 717f7f62c71SSandipan Das else 718f7f62c71SSandipan Das printf("\n"); 719f7f62c71SSandipan Das } 720f7f62c71SSandipan Das 721f7f62c71SSandipan Das if (json_output) 722f7f62c71SSandipan Das jsonw_end_array(json_wtr); 723f7f62c71SSandipan Das } else { 7243ddeac67SJakub Kicinski disasm_print_insn(buf, *member_len, opcodes, name, 7253ddeac67SJakub Kicinski disasm_opt); 726f7f62c71SSandipan Das } 727b6c1cedbSJiong Wang } else if (visual) { 728b6c1cedbSJiong Wang if (json_output) 729b6c1cedbSJiong Wang jsonw_null(json_wtr); 730b6c1cedbSJiong Wang else 731b6c1cedbSJiong Wang dump_xlated_cfg(buf, *member_len); 7327105e828SDaniel Borkmann } else { 7337105e828SDaniel Borkmann kernel_syms_load(&dd); 734f84192eeSSandipan Das dd.nr_jited_ksyms = info.nr_jited_ksyms; 735f84192eeSSandipan Das dd.jited_ksyms = (__u64 *) info.jited_ksyms; 736*254471e5SYonghong Song dd.btf = btf; 737*254471e5SYonghong Song dd.func_info = func_info; 738*254471e5SYonghong Song dd.finfo_rec_size = finfo_rec_size; 739f84192eeSSandipan Das 740f05e2c32SQuentin Monnet if (json_output) 7417105e828SDaniel Borkmann dump_xlated_json(&dd, buf, *member_len, opcodes); 742f05e2c32SQuentin Monnet else 7437105e828SDaniel Borkmann dump_xlated_plain(&dd, buf, *member_len, opcodes); 7447105e828SDaniel Borkmann kernel_syms_destroy(&dd); 7457105e828SDaniel Borkmann } 74671bb428fSJakub Kicinski 74771bb428fSJakub Kicinski free(buf); 748f84192eeSSandipan Das free(func_ksyms); 749f7f62c71SSandipan Das free(func_lens); 750*254471e5SYonghong Song free(func_info); 75171bb428fSJakub Kicinski return 0; 75271bb428fSJakub Kicinski 75371bb428fSJakub Kicinski err_free: 75471bb428fSJakub Kicinski free(buf); 755f84192eeSSandipan Das free(func_ksyms); 756f7f62c71SSandipan Das free(func_lens); 757*254471e5SYonghong Song free(func_info); 75871bb428fSJakub Kicinski return -1; 75971bb428fSJakub Kicinski } 76071bb428fSJakub Kicinski 76171bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 76271bb428fSJakub Kicinski { 763004b45c0SQuentin Monnet int err; 764004b45c0SQuentin Monnet 765004b45c0SQuentin Monnet err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 766004b45c0SQuentin Monnet if (!err && json_output) 767004b45c0SQuentin Monnet jsonw_null(json_wtr); 768004b45c0SQuentin Monnet return err; 76971bb428fSJakub Kicinski } 77071bb428fSJakub Kicinski 7713ff5a4dcSJakub Kicinski struct map_replace { 7723ff5a4dcSJakub Kicinski int idx; 7733ff5a4dcSJakub Kicinski int fd; 7743ff5a4dcSJakub Kicinski char *name; 7753ff5a4dcSJakub Kicinski }; 7763ff5a4dcSJakub Kicinski 7773ff5a4dcSJakub Kicinski int map_replace_compar(const void *p1, const void *p2) 7783ff5a4dcSJakub Kicinski { 7793ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 7803ff5a4dcSJakub Kicinski 7813ff5a4dcSJakub Kicinski return a->idx - b->idx; 7823ff5a4dcSJakub Kicinski } 7833ff5a4dcSJakub Kicinski 784092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 785092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 786092f0892SStanislav Fomichev int *mapfd) 787092f0892SStanislav Fomichev { 788092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 789092f0892SStanislav Fomichev return -EINVAL; 790092f0892SStanislav Fomichev 791092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 792092f0892SStanislav Fomichev if (*progfd < 0) 793092f0892SStanislav Fomichev return *progfd; 794092f0892SStanislav Fomichev 795092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 796092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 797092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 798092f0892SStanislav Fomichev return -EINVAL; 799092f0892SStanislav Fomichev } 800092f0892SStanislav Fomichev 801092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 802092f0892SStanislav Fomichev *mapfd = -1; 803092f0892SStanislav Fomichev return 0; 804092f0892SStanislav Fomichev } 805092f0892SStanislav Fomichev 806092f0892SStanislav Fomichev NEXT_ARG(); 807092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 808092f0892SStanislav Fomichev return -EINVAL; 809092f0892SStanislav Fomichev 810092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 811092f0892SStanislav Fomichev if (*mapfd < 0) 812092f0892SStanislav Fomichev return *mapfd; 813092f0892SStanislav Fomichev 814092f0892SStanislav Fomichev return 0; 815092f0892SStanislav Fomichev } 816092f0892SStanislav Fomichev 817b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 818b7d3826cSJohn Fastabend { 819b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 820092f0892SStanislav Fomichev int err, progfd; 821092f0892SStanislav Fomichev int mapfd; 822b7d3826cSJohn Fastabend 823092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 824092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 825092f0892SStanislav Fomichev if (err) 826092f0892SStanislav Fomichev return err; 827b7d3826cSJohn Fastabend 828b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 829b7d3826cSJohn Fastabend if (err) { 830b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 831b7d3826cSJohn Fastabend return -EINVAL; 832b7d3826cSJohn Fastabend } 833b7d3826cSJohn Fastabend 834b7d3826cSJohn Fastabend if (json_output) 835b7d3826cSJohn Fastabend jsonw_null(json_wtr); 836b7d3826cSJohn Fastabend return 0; 837b7d3826cSJohn Fastabend } 838b7d3826cSJohn Fastabend 839b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 840b7d3826cSJohn Fastabend { 841b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 842092f0892SStanislav Fomichev int err, progfd; 843092f0892SStanislav Fomichev int mapfd; 844b7d3826cSJohn Fastabend 845092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 846092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 847092f0892SStanislav Fomichev if (err) 848092f0892SStanislav Fomichev return err; 849b7d3826cSJohn Fastabend 850b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 851b7d3826cSJohn Fastabend if (err) { 852b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 853b7d3826cSJohn Fastabend return -EINVAL; 854b7d3826cSJohn Fastabend } 855b7d3826cSJohn Fastabend 856b7d3826cSJohn Fastabend if (json_output) 857b7d3826cSJohn Fastabend jsonw_null(json_wtr); 858b7d3826cSJohn Fastabend return 0; 859b7d3826cSJohn Fastabend } 86077380998SStanislav Fomichev 86177380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 86249a086c2SRoman Gushchin { 863c8406848SJakub Kicinski enum bpf_attach_type expected_attach_type; 864c8406848SJakub Kicinski struct bpf_object_open_attr attr = { 865ba6dd679SJakub Kicinski .prog_type = BPF_PROG_TYPE_UNSPEC, 866ba6dd679SJakub Kicinski }; 8673ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 86877380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 8693ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 8703767a94bSStanislav Fomichev const char *pinmaps = NULL; 87149a086c2SRoman Gushchin struct bpf_object *obj; 872c8406848SJakub Kicinski struct bpf_map *map; 873c8406848SJakub Kicinski const char *pinfile; 8743ff5a4dcSJakub Kicinski unsigned int i, j; 875c8406848SJakub Kicinski __u32 ifindex = 0; 8763ff5a4dcSJakub Kicinski int idx, err; 87749a086c2SRoman Gushchin 8788d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 8798d1fc3deSJakub Kicinski return -1; 880c8406848SJakub Kicinski attr.file = GET_ARG(); 8818d1fc3deSJakub Kicinski pinfile = GET_ARG(); 88249a086c2SRoman Gushchin 883ba6dd679SJakub Kicinski while (argc) { 88449f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 88549f2cba3SJakub Kicinski char *type; 88649f2cba3SJakub Kicinski 88749f2cba3SJakub Kicinski NEXT_ARG(); 88849f2cba3SJakub Kicinski 88949f2cba3SJakub Kicinski if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 89049f2cba3SJakub Kicinski p_err("program type already specified"); 8913ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 89249f2cba3SJakub Kicinski } 89349f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 8943ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 89549f2cba3SJakub Kicinski 89649f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 89749f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 89849f2cba3SJakub Kicinski if (!type) { 89949f2cba3SJakub Kicinski p_err("mem alloc failed"); 9003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 90149f2cba3SJakub Kicinski } 90249f2cba3SJakub Kicinski *type = 0; 90349f2cba3SJakub Kicinski strcat(type, *argv); 90449f2cba3SJakub Kicinski strcat(type, "/"); 90549f2cba3SJakub Kicinski 90649f2cba3SJakub Kicinski err = libbpf_prog_type_by_name(type, &attr.prog_type, 907c8406848SJakub Kicinski &expected_attach_type); 90849f2cba3SJakub Kicinski free(type); 90949f2cba3SJakub Kicinski if (err < 0) { 91049f2cba3SJakub Kicinski p_err("unknown program type '%s'", *argv); 9113ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 91249f2cba3SJakub Kicinski } 91349f2cba3SJakub Kicinski NEXT_ARG(); 9143ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 9153ff5a4dcSJakub Kicinski char *endptr, *name; 9163ff5a4dcSJakub Kicinski int fd; 9173ff5a4dcSJakub Kicinski 9183ff5a4dcSJakub Kicinski NEXT_ARG(); 9193ff5a4dcSJakub Kicinski 9203ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 9213ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9223ff5a4dcSJakub Kicinski 9233ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 9243ff5a4dcSJakub Kicinski NEXT_ARG(); 9253ff5a4dcSJakub Kicinski 9263ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 9273ff5a4dcSJakub Kicinski if (*endptr) { 9283ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 9293ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9303ff5a4dcSJakub Kicinski } 9313ff5a4dcSJakub Kicinski name = NULL; 9323ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 9333ff5a4dcSJakub Kicinski NEXT_ARG(); 9343ff5a4dcSJakub Kicinski 9353ff5a4dcSJakub Kicinski name = *argv; 9363ff5a4dcSJakub Kicinski idx = -1; 9373ff5a4dcSJakub Kicinski } else { 9383ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 9393ff5a4dcSJakub Kicinski *argv); 9403ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9413ff5a4dcSJakub Kicinski } 9423ff5a4dcSJakub Kicinski NEXT_ARG(); 9433ff5a4dcSJakub Kicinski 9443ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 9453ff5a4dcSJakub Kicinski if (fd < 0) 9463ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9473ff5a4dcSJakub Kicinski 9483ff5a4dcSJakub Kicinski map_replace = reallocarray(map_replace, old_map_fds + 1, 9493ff5a4dcSJakub Kicinski sizeof(*map_replace)); 9503ff5a4dcSJakub Kicinski if (!map_replace) { 9513ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 9523ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 9533ff5a4dcSJakub Kicinski } 9543ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 9553ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 9563ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 9573ff5a4dcSJakub Kicinski old_map_fds++; 95849f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 959ba6dd679SJakub Kicinski NEXT_ARG(); 960ba6dd679SJakub Kicinski 961c8406848SJakub Kicinski if (ifindex) { 962ba6dd679SJakub Kicinski p_err("offload device already specified"); 9633ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 964ba6dd679SJakub Kicinski } 965ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 9663ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 967ba6dd679SJakub Kicinski 968c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 969c8406848SJakub Kicinski if (!ifindex) { 970ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 971ba6dd679SJakub Kicinski *argv, strerror(errno)); 9723ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 973ba6dd679SJakub Kicinski } 974ba6dd679SJakub Kicinski NEXT_ARG(); 9753767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 9763767a94bSStanislav Fomichev NEXT_ARG(); 9773767a94bSStanislav Fomichev 9783767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 9793767a94bSStanislav Fomichev goto err_free_reuse_maps; 9803767a94bSStanislav Fomichev 9813767a94bSStanislav Fomichev pinmaps = GET_ARG(); 982ba6dd679SJakub Kicinski } else { 9833ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 984ba6dd679SJakub Kicinski *argv); 9853ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 986ba6dd679SJakub Kicinski } 987ba6dd679SJakub Kicinski } 988ba6dd679SJakub Kicinski 989c034a177SJohn Fastabend obj = __bpf_object__open_xattr(&attr, bpf_flags); 990c8406848SJakub Kicinski if (IS_ERR_OR_NULL(obj)) { 991c8406848SJakub Kicinski p_err("failed to open object file"); 9923ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 99349a086c2SRoman Gushchin } 99449a086c2SRoman Gushchin 99577380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 99677380998SStanislav Fomichev enum bpf_prog_type prog_type = attr.prog_type; 997c8406848SJakub Kicinski 998c8406848SJakub Kicinski if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 99977380998SStanislav Fomichev const char *sec_name = bpf_program__title(pos, false); 1000c8406848SJakub Kicinski 100177380998SStanislav Fomichev err = libbpf_prog_type_by_name(sec_name, &prog_type, 1002c8406848SJakub Kicinski &expected_attach_type); 1003c8406848SJakub Kicinski if (err < 0) { 1004c8406848SJakub Kicinski p_err("failed to guess program type based on section name %s\n", 1005c8406848SJakub Kicinski sec_name); 1006c8406848SJakub Kicinski goto err_close_obj; 1007c8406848SJakub Kicinski } 1008c8406848SJakub Kicinski } 100977380998SStanislav Fomichev 101077380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 101177380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 101277380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 101377380998SStanislav Fomichev } 1014c8406848SJakub Kicinski 10153ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 10163ff5a4dcSJakub Kicinski map_replace_compar); 10173ff5a4dcSJakub Kicinski 10183ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 10193ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 10203ff5a4dcSJakub Kicinski */ 10213ff5a4dcSJakub Kicinski j = 0; 10223ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 10233ff5a4dcSJakub Kicinski i = 0; 10243ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 10253ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 10263ff5a4dcSJakub Kicinski map_replace[j].idx = i; 10273ff5a4dcSJakub Kicinski break; 10283ff5a4dcSJakub Kicinski } 10293ff5a4dcSJakub Kicinski i++; 10303ff5a4dcSJakub Kicinski } 10313ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 10323ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 10333ff5a4dcSJakub Kicinski goto err_close_obj; 10343ff5a4dcSJakub Kicinski } 10353ff5a4dcSJakub Kicinski j++; 10363ff5a4dcSJakub Kicinski } 10373ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 10383ff5a4dcSJakub Kicinski if (j) 10393ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 10403ff5a4dcSJakub Kicinski map_replace_compar); 10413ff5a4dcSJakub Kicinski 10423ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 10433ff5a4dcSJakub Kicinski j = 0; 10443ff5a4dcSJakub Kicinski idx = 0; 10453ff5a4dcSJakub Kicinski bpf_map__for_each(map, obj) { 1046c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1047c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1048c8406848SJakub Kicinski 10493ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 10503ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 10513ff5a4dcSJakub Kicinski if (err) { 10523ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 10533ff5a4dcSJakub Kicinski goto err_close_obj; 10543ff5a4dcSJakub Kicinski } 10553ff5a4dcSJakub Kicinski 10563ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 10573ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 10583ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 10593ff5a4dcSJakub Kicinski idx); 10603ff5a4dcSJakub Kicinski goto err_close_obj; 10613ff5a4dcSJakub Kicinski } 10623ff5a4dcSJakub Kicinski } 10633ff5a4dcSJakub Kicinski 10643ff5a4dcSJakub Kicinski idx++; 10653ff5a4dcSJakub Kicinski } 10663ff5a4dcSJakub Kicinski if (j < old_map_fds) { 10673ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 10683ff5a4dcSJakub Kicinski goto err_close_obj; 10693ff5a4dcSJakub Kicinski } 10703ff5a4dcSJakub Kicinski 10718302b9bdSQuentin Monnet set_max_rlimit(); 10728302b9bdSQuentin Monnet 1073c8406848SJakub Kicinski err = bpf_object__load(obj); 1074c8406848SJakub Kicinski if (err) { 1075c8406848SJakub Kicinski p_err("failed to load object file"); 1076c8406848SJakub Kicinski goto err_close_obj; 1077c8406848SJakub Kicinski } 1078c8406848SJakub Kicinski 107977380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 108077380998SStanislav Fomichev if (err) 1081bfee71fbSJakub Kicinski goto err_close_obj; 108249a086c2SRoman Gushchin 108377380998SStanislav Fomichev if (first_prog_only) { 108477380998SStanislav Fomichev prog = bpf_program__next(NULL, obj); 108577380998SStanislav Fomichev if (!prog) { 108677380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 108777380998SStanislav Fomichev goto err_close_obj; 108877380998SStanislav Fomichev } 108977380998SStanislav Fomichev 109077380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 109177380998SStanislav Fomichev if (err) { 109277380998SStanislav Fomichev p_err("failed to pin program %s", 109377380998SStanislav Fomichev bpf_program__title(prog, false)); 109477380998SStanislav Fomichev goto err_close_obj; 109577380998SStanislav Fomichev } 109677380998SStanislav Fomichev } else { 109777380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 109877380998SStanislav Fomichev if (err) { 109977380998SStanislav Fomichev p_err("failed to pin all programs"); 110077380998SStanislav Fomichev goto err_close_obj; 110177380998SStanislav Fomichev } 110277380998SStanislav Fomichev } 110377380998SStanislav Fomichev 11043767a94bSStanislav Fomichev if (pinmaps) { 11053767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 11063767a94bSStanislav Fomichev if (err) { 11073767a94bSStanislav Fomichev p_err("failed to pin all maps"); 11083767a94bSStanislav Fomichev goto err_unpin; 11093767a94bSStanislav Fomichev } 11103767a94bSStanislav Fomichev } 11113767a94bSStanislav Fomichev 111249a086c2SRoman Gushchin if (json_output) 111349a086c2SRoman Gushchin jsonw_null(json_wtr); 111449a086c2SRoman Gushchin 1115bfee71fbSJakub Kicinski bpf_object__close(obj); 11163ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 11173ff5a4dcSJakub Kicinski close(map_replace[i].fd); 11183ff5a4dcSJakub Kicinski free(map_replace); 1119bfee71fbSJakub Kicinski 112049a086c2SRoman Gushchin return 0; 1121bfee71fbSJakub Kicinski 11223767a94bSStanislav Fomichev err_unpin: 11233767a94bSStanislav Fomichev if (first_prog_only) 11243767a94bSStanislav Fomichev unlink(pinfile); 11253767a94bSStanislav Fomichev else 11263767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1127bfee71fbSJakub Kicinski err_close_obj: 1128bfee71fbSJakub Kicinski bpf_object__close(obj); 11293ff5a4dcSJakub Kicinski err_free_reuse_maps: 11303ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 11313ff5a4dcSJakub Kicinski close(map_replace[i].fd); 11323ff5a4dcSJakub Kicinski free(map_replace); 1133bfee71fbSJakub Kicinski return -1; 113449a086c2SRoman Gushchin } 113549a086c2SRoman Gushchin 113677380998SStanislav Fomichev static int do_load(int argc, char **argv) 113777380998SStanislav Fomichev { 113877380998SStanislav Fomichev return load_with_options(argc, argv, true); 113977380998SStanislav Fomichev } 114077380998SStanislav Fomichev 114177380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 114277380998SStanislav Fomichev { 114377380998SStanislav Fomichev return load_with_options(argc, argv, false); 114477380998SStanislav Fomichev } 114577380998SStanislav Fomichev 114671bb428fSJakub Kicinski static int do_help(int argc, char **argv) 114771bb428fSJakub Kicinski { 1148004b45c0SQuentin Monnet if (json_output) { 1149004b45c0SQuentin Monnet jsonw_null(json_wtr); 1150004b45c0SQuentin Monnet return 0; 1151004b45c0SQuentin Monnet } 1152004b45c0SQuentin Monnet 115371bb428fSJakub Kicinski fprintf(stderr, 11546ebe6dbdSJakub Kicinski "Usage: %s %s { show | list } [PROG]\n" 1155b6c1cedbSJiong Wang " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 11568dfbc6d1SQuentin Monnet " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 115771bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 115877380998SStanislav Fomichev " %s %s { load | loadall } OBJ PATH \\\n" 115977380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 11603767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 11613767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 1162092f0892SStanislav Fomichev " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1163092f0892SStanislav Fomichev " %s %s detach PROG ATTACH_TYPE [MAP]\n" 116471bb428fSJakub Kicinski " %s %s help\n" 116571bb428fSJakub Kicinski "\n" 11663ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 116771bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 116849f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 116949f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 117049f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 117149f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 117249f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 117349f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 117449f2cba3SJakub Kicinski " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 1175092f0892SStanislav Fomichev " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse |\n" 1176092f0892SStanislav Fomichev " flow_dissector }\n" 11770641c3c8SQuentin Monnet " " HELP_SPEC_OPTIONS "\n" 117871bb428fSJakub Kicinski "", 117971bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1180b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1181b7d3826cSJohn Fastabend bin_name, argv[-2], bin_name, argv[-2]); 118271bb428fSJakub Kicinski 118371bb428fSJakub Kicinski return 0; 118471bb428fSJakub Kicinski } 118571bb428fSJakub Kicinski 118671bb428fSJakub Kicinski static const struct cmd cmds[] = { 118771bb428fSJakub Kicinski { "show", do_show }, 11886ebe6dbdSJakub Kicinski { "list", do_show }, 11899f606179SQuentin Monnet { "help", do_help }, 119071bb428fSJakub Kicinski { "dump", do_dump }, 119171bb428fSJakub Kicinski { "pin", do_pin }, 119249a086c2SRoman Gushchin { "load", do_load }, 119377380998SStanislav Fomichev { "loadall", do_loadall }, 1194b7d3826cSJohn Fastabend { "attach", do_attach }, 1195b7d3826cSJohn Fastabend { "detach", do_detach }, 119671bb428fSJakub Kicinski { 0 } 119771bb428fSJakub Kicinski }; 119871bb428fSJakub Kicinski 119971bb428fSJakub Kicinski int do_prog(int argc, char **argv) 120071bb428fSJakub Kicinski { 120171bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 120271bb428fSJakub Kicinski } 1203