102ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 202ff58dcSJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 371bb428fSJakub Kicinski 4b3d84af7SQuentin Monnet #ifndef _GNU_SOURCE 53ff5a4dcSJakub Kicinski #define _GNU_SOURCE 6b3d84af7SQuentin Monnet #endif 771bb428fSJakub Kicinski #include <errno.h> 871bb428fSJakub Kicinski #include <fcntl.h> 947c09d6aSSong Liu #include <signal.h> 10c9c35995SJakub Kicinski #include <stdarg.h> 1171bb428fSJakub Kicinski #include <stdio.h> 1271bb428fSJakub Kicinski #include <stdlib.h> 1371bb428fSJakub Kicinski #include <string.h> 1471bb428fSJakub Kicinski #include <time.h> 1571bb428fSJakub Kicinski #include <unistd.h> 16ba6dd679SJakub Kicinski #include <net/if.h> 1747c09d6aSSong Liu #include <sys/ioctl.h> 1871bb428fSJakub Kicinski #include <sys/types.h> 1971bb428fSJakub Kicinski #include <sys/stat.h> 2047c09d6aSSong Liu #include <sys/syscall.h> 21d510296dSAlexei Starovoitov #include <dirent.h> 2271bb428fSJakub Kicinski 23c8406848SJakub Kicinski #include <linux/err.h> 2447c09d6aSSong Liu #include <linux/perf_event.h> 25ba95c745SQuentin Monnet #include <linux/sizes.h> 26c8406848SJakub Kicinski 27229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h> 28229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h> 298f184732SQuentin Monnet #include <bpf/hashmap.h> 30229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h> 31a19df713SMauricio Vásquez #include <bpf/libbpf_internal.h> 32d510296dSAlexei Starovoitov #include <bpf/skel_internal.h> 3371bb428fSJakub Kicinski 34b6c1cedbSJiong Wang #include "cfg.h" 3571bb428fSJakub Kicinski #include "main.h" 3673bb5b4fSJiong Wang #include "xlated_dumper.h" 3771bb428fSJakub Kicinski 38aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX "bpf_metadata_" 39aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1) 40aff52e68SYiFei Zhu 41ec202509SPaul Chaignon enum dump_mode { 42ec202509SPaul Chaignon DUMP_JITED, 43ec202509SPaul Chaignon DUMP_XLATED, 44ec202509SPaul Chaignon }; 45ec202509SPaul Chaignon 461ba5ad36SDaniel Müller static const bool attach_types[] = { 471ba5ad36SDaniel Müller [BPF_SK_SKB_STREAM_PARSER] = true, 481ba5ad36SDaniel Müller [BPF_SK_SKB_STREAM_VERDICT] = true, 491ba5ad36SDaniel Müller [BPF_SK_SKB_VERDICT] = true, 501ba5ad36SDaniel Müller [BPF_SK_MSG_VERDICT] = true, 511ba5ad36SDaniel Müller [BPF_FLOW_DISSECTOR] = true, 521ba5ad36SDaniel Müller [__MAX_BPF_ATTACH_TYPE] = false, 531ba5ad36SDaniel Müller }; 541ba5ad36SDaniel Müller 551ba5ad36SDaniel Müller /* Textual representations traditionally used by the program and kept around 561ba5ad36SDaniel Müller * for the sake of backwards compatibility. 571ba5ad36SDaniel Müller */ 58b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 59b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 60b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 61a7ba4558SCong Wang [BPF_SK_SKB_VERDICT] = "skb_verdict", 62b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 63b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 64b7d3826cSJohn Fastabend }; 65b7d3826cSJohn Fastabend 668f184732SQuentin Monnet static struct hashmap *prog_table; 6746241271SQuentin Monnet 68c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 69b7d3826cSJohn Fastabend { 70b7d3826cSJohn Fastabend enum bpf_attach_type type; 71b7d3826cSJohn Fastabend 72b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 731ba5ad36SDaniel Müller if (attach_types[type]) { 741ba5ad36SDaniel Müller const char *attach_type_str; 751ba5ad36SDaniel Müller 761ba5ad36SDaniel Müller attach_type_str = libbpf_bpf_attach_type_str(type); 771ba5ad36SDaniel Müller if (!strcmp(str, attach_type_str)) 781ba5ad36SDaniel Müller return type; 791ba5ad36SDaniel Müller } 801ba5ad36SDaniel Müller 81b7d3826cSJohn Fastabend if (attach_type_strings[type] && 82b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 83b7d3826cSJohn Fastabend return type; 84b7d3826cSJohn Fastabend } 85b7d3826cSJohn Fastabend 86b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 87b7d3826cSJohn Fastabend } 88b7d3826cSJohn Fastabend 89c59765cfSDave Marchevsky static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 90c59765cfSDave Marchevsky void **info_data, size_t *const info_data_sz) 91c59765cfSDave Marchevsky { 92c59765cfSDave Marchevsky struct bpf_prog_info holder = {}; 93c59765cfSDave Marchevsky size_t needed = 0; 94c59765cfSDave Marchevsky void *ptr; 95c59765cfSDave Marchevsky 96c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 97c59765cfSDave Marchevsky holder.jited_prog_len = info->jited_prog_len; 98c59765cfSDave Marchevsky needed += info->jited_prog_len; 99c59765cfSDave Marchevsky } else { 100c59765cfSDave Marchevsky holder.xlated_prog_len = info->xlated_prog_len; 101c59765cfSDave Marchevsky needed += info->xlated_prog_len; 102c59765cfSDave Marchevsky } 103c59765cfSDave Marchevsky 104c59765cfSDave Marchevsky holder.nr_jited_ksyms = info->nr_jited_ksyms; 105c59765cfSDave Marchevsky needed += info->nr_jited_ksyms * sizeof(__u64); 106c59765cfSDave Marchevsky 107c59765cfSDave Marchevsky holder.nr_jited_func_lens = info->nr_jited_func_lens; 108c59765cfSDave Marchevsky needed += info->nr_jited_func_lens * sizeof(__u32); 109c59765cfSDave Marchevsky 110c59765cfSDave Marchevsky holder.nr_func_info = info->nr_func_info; 111c59765cfSDave Marchevsky holder.func_info_rec_size = info->func_info_rec_size; 112c59765cfSDave Marchevsky needed += info->nr_func_info * info->func_info_rec_size; 113c59765cfSDave Marchevsky 114c59765cfSDave Marchevsky holder.nr_line_info = info->nr_line_info; 115c59765cfSDave Marchevsky holder.line_info_rec_size = info->line_info_rec_size; 116c59765cfSDave Marchevsky needed += info->nr_line_info * info->line_info_rec_size; 117c59765cfSDave Marchevsky 118c59765cfSDave Marchevsky holder.nr_jited_line_info = info->nr_jited_line_info; 119c59765cfSDave Marchevsky holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 120c59765cfSDave Marchevsky needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 121c59765cfSDave Marchevsky 122c59765cfSDave Marchevsky if (needed > *info_data_sz) { 123c59765cfSDave Marchevsky ptr = realloc(*info_data, needed); 124c59765cfSDave Marchevsky if (!ptr) 125c59765cfSDave Marchevsky return -1; 126c59765cfSDave Marchevsky 127c59765cfSDave Marchevsky *info_data = ptr; 128c59765cfSDave Marchevsky *info_data_sz = needed; 129c59765cfSDave Marchevsky } 130c59765cfSDave Marchevsky ptr = *info_data; 131c59765cfSDave Marchevsky 132c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 133c59765cfSDave Marchevsky holder.jited_prog_insns = ptr_to_u64(ptr); 134c59765cfSDave Marchevsky ptr += holder.jited_prog_len; 135c59765cfSDave Marchevsky } else { 136c59765cfSDave Marchevsky holder.xlated_prog_insns = ptr_to_u64(ptr); 137c59765cfSDave Marchevsky ptr += holder.xlated_prog_len; 138c59765cfSDave Marchevsky } 139c59765cfSDave Marchevsky 140c59765cfSDave Marchevsky holder.jited_ksyms = ptr_to_u64(ptr); 141c59765cfSDave Marchevsky ptr += holder.nr_jited_ksyms * sizeof(__u64); 142c59765cfSDave Marchevsky 143c59765cfSDave Marchevsky holder.jited_func_lens = ptr_to_u64(ptr); 144c59765cfSDave Marchevsky ptr += holder.nr_jited_func_lens * sizeof(__u32); 145c59765cfSDave Marchevsky 146c59765cfSDave Marchevsky holder.func_info = ptr_to_u64(ptr); 147c59765cfSDave Marchevsky ptr += holder.nr_func_info * holder.func_info_rec_size; 148c59765cfSDave Marchevsky 149c59765cfSDave Marchevsky holder.line_info = ptr_to_u64(ptr); 150c59765cfSDave Marchevsky ptr += holder.nr_line_info * holder.line_info_rec_size; 151c59765cfSDave Marchevsky 152c59765cfSDave Marchevsky holder.jited_line_info = ptr_to_u64(ptr); 153c59765cfSDave Marchevsky ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 154c59765cfSDave Marchevsky 155c59765cfSDave Marchevsky *info = holder; 156c59765cfSDave Marchevsky return 0; 157c59765cfSDave Marchevsky } 158c59765cfSDave Marchevsky 15971bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 16071bb428fSJakub Kicinski { 16171bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 16271bb428fSJakub Kicinski time_t wallclock_secs; 16371bb428fSJakub Kicinski struct tm load_tm; 16471bb428fSJakub Kicinski 16571bb428fSJakub Kicinski buf[--size] = '\0'; 16671bb428fSJakub Kicinski 16771bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 16871bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 16971bb428fSJakub Kicinski perror("Can't read clocks"); 17071bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 17171bb428fSJakub Kicinski return; 17271bb428fSJakub Kicinski } 17371bb428fSJakub Kicinski 17471bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 17507480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 17607480cbcSJakub Kicinski 1000000000; 17707480cbcSJakub Kicinski 17871bb428fSJakub Kicinski 17971bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 18071bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 18171bb428fSJakub Kicinski return; 18271bb428fSJakub Kicinski } 18371bb428fSJakub Kicinski 184a3fe1f6fSQuentin Monnet if (json_output) 185a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 186a3fe1f6fSQuentin Monnet else 187a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 18871bb428fSJakub Kicinski } 18971bb428fSJakub Kicinski 1906e7e034eSQuentin Monnet static void show_prog_maps(int fd, __u32 num_maps) 19171bb428fSJakub Kicinski { 19271bb428fSJakub Kicinski struct bpf_prog_info info = {}; 19371bb428fSJakub Kicinski __u32 len = sizeof(info); 19471bb428fSJakub Kicinski __u32 map_ids[num_maps]; 19571bb428fSJakub Kicinski unsigned int i; 19671bb428fSJakub Kicinski int err; 19771bb428fSJakub Kicinski 19871bb428fSJakub Kicinski info.nr_map_ids = num_maps; 19971bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 20071bb428fSJakub Kicinski 20138f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fd, &info, &len); 20271bb428fSJakub Kicinski if (err || !info.nr_map_ids) 20371bb428fSJakub Kicinski return; 20471bb428fSJakub Kicinski 205743cc665SQuentin Monnet if (json_output) { 206743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 207743cc665SQuentin Monnet jsonw_start_array(json_wtr); 208743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 209743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 210743cc665SQuentin Monnet jsonw_end_array(json_wtr); 211743cc665SQuentin Monnet } else { 21271bb428fSJakub Kicinski printf(" map_ids "); 21371bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 21471bb428fSJakub Kicinski printf("%u%s", map_ids[i], 21571bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 21671bb428fSJakub Kicinski } 21771bb428fSJakub Kicinski } 21871bb428fSJakub Kicinski 219aff52e68SYiFei Zhu static void *find_metadata(int prog_fd, struct bpf_map_info *map_info) 220aff52e68SYiFei Zhu { 221aff52e68SYiFei Zhu struct bpf_prog_info prog_info; 222aff52e68SYiFei Zhu __u32 prog_info_len; 223aff52e68SYiFei Zhu __u32 map_info_len; 224aff52e68SYiFei Zhu void *value = NULL; 225aff52e68SYiFei Zhu __u32 *map_ids; 226aff52e68SYiFei Zhu int nr_maps; 227aff52e68SYiFei Zhu int key = 0; 228aff52e68SYiFei Zhu int map_fd; 229aff52e68SYiFei Zhu int ret; 230aff52e68SYiFei Zhu __u32 i; 231aff52e68SYiFei Zhu 232aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 233aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 23438f0408eSIlya Leoshkevich ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 235aff52e68SYiFei Zhu if (ret) 236aff52e68SYiFei Zhu return NULL; 237aff52e68SYiFei Zhu 238aff52e68SYiFei Zhu if (!prog_info.nr_map_ids) 239aff52e68SYiFei Zhu return NULL; 240aff52e68SYiFei Zhu 241aff52e68SYiFei Zhu map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); 242aff52e68SYiFei Zhu if (!map_ids) 243aff52e68SYiFei Zhu return NULL; 244aff52e68SYiFei Zhu 245aff52e68SYiFei Zhu nr_maps = prog_info.nr_map_ids; 246aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 247aff52e68SYiFei Zhu prog_info.nr_map_ids = nr_maps; 248aff52e68SYiFei Zhu prog_info.map_ids = ptr_to_u64(map_ids); 249aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 250aff52e68SYiFei Zhu 25138f0408eSIlya Leoshkevich ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 252aff52e68SYiFei Zhu if (ret) 253aff52e68SYiFei Zhu goto free_map_ids; 254aff52e68SYiFei Zhu 255aff52e68SYiFei Zhu for (i = 0; i < prog_info.nr_map_ids; i++) { 256aff52e68SYiFei Zhu map_fd = bpf_map_get_fd_by_id(map_ids[i]); 257aff52e68SYiFei Zhu if (map_fd < 0) 258aff52e68SYiFei Zhu goto free_map_ids; 259aff52e68SYiFei Zhu 260aff52e68SYiFei Zhu memset(map_info, 0, sizeof(*map_info)); 261aff52e68SYiFei Zhu map_info_len = sizeof(*map_info); 26238f0408eSIlya Leoshkevich ret = bpf_map_get_info_by_fd(map_fd, map_info, &map_info_len); 263aff52e68SYiFei Zhu if (ret < 0) { 264aff52e68SYiFei Zhu close(map_fd); 265aff52e68SYiFei Zhu goto free_map_ids; 266aff52e68SYiFei Zhu } 267aff52e68SYiFei Zhu 268aff52e68SYiFei Zhu if (map_info->type != BPF_MAP_TYPE_ARRAY || 269aff52e68SYiFei Zhu map_info->key_size != sizeof(int) || 270aff52e68SYiFei Zhu map_info->max_entries != 1 || 271aff52e68SYiFei Zhu !map_info->btf_value_type_id || 272aff52e68SYiFei Zhu !strstr(map_info->name, ".rodata")) { 273aff52e68SYiFei Zhu close(map_fd); 274aff52e68SYiFei Zhu continue; 275aff52e68SYiFei Zhu } 276aff52e68SYiFei Zhu 277aff52e68SYiFei Zhu value = malloc(map_info->value_size); 278aff52e68SYiFei Zhu if (!value) { 279aff52e68SYiFei Zhu close(map_fd); 280aff52e68SYiFei Zhu goto free_map_ids; 281aff52e68SYiFei Zhu } 282aff52e68SYiFei Zhu 283aff52e68SYiFei Zhu if (bpf_map_lookup_elem(map_fd, &key, value)) { 284aff52e68SYiFei Zhu close(map_fd); 285aff52e68SYiFei Zhu free(value); 286aff52e68SYiFei Zhu value = NULL; 287aff52e68SYiFei Zhu goto free_map_ids; 288aff52e68SYiFei Zhu } 289aff52e68SYiFei Zhu 290aff52e68SYiFei Zhu close(map_fd); 291aff52e68SYiFei Zhu break; 292aff52e68SYiFei Zhu } 293aff52e68SYiFei Zhu 294aff52e68SYiFei Zhu free_map_ids: 295aff52e68SYiFei Zhu free(map_ids); 296aff52e68SYiFei Zhu return value; 297aff52e68SYiFei Zhu } 298aff52e68SYiFei Zhu 299aff52e68SYiFei Zhu static bool has_metadata_prefix(const char *s) 300aff52e68SYiFei Zhu { 301aff52e68SYiFei Zhu return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0; 302aff52e68SYiFei Zhu } 303aff52e68SYiFei Zhu 304aff52e68SYiFei Zhu static void show_prog_metadata(int fd, __u32 num_maps) 305aff52e68SYiFei Zhu { 306aff52e68SYiFei Zhu const struct btf_type *t_datasec, *t_var; 307aff52e68SYiFei Zhu struct bpf_map_info map_info; 308aff52e68SYiFei Zhu struct btf_var_secinfo *vsi; 309aff52e68SYiFei Zhu bool printed_header = false; 310aff52e68SYiFei Zhu unsigned int i, vlen; 311aff52e68SYiFei Zhu void *value = NULL; 312aff52e68SYiFei Zhu const char *name; 31386f4b7f2SQuentin Monnet struct btf *btf; 314aff52e68SYiFei Zhu int err; 315aff52e68SYiFei Zhu 316aff52e68SYiFei Zhu if (!num_maps) 317aff52e68SYiFei Zhu return; 318aff52e68SYiFei Zhu 319aff52e68SYiFei Zhu memset(&map_info, 0, sizeof(map_info)); 320aff52e68SYiFei Zhu value = find_metadata(fd, &map_info); 321aff52e68SYiFei Zhu if (!value) 322aff52e68SYiFei Zhu return; 323aff52e68SYiFei Zhu 32486f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(map_info.btf_id); 325d1313e01SSahid Orentino Ferdjaoui if (!btf) 326aff52e68SYiFei Zhu goto out_free; 327aff52e68SYiFei Zhu 328aff52e68SYiFei Zhu t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); 329aff52e68SYiFei Zhu if (!btf_is_datasec(t_datasec)) 330aff52e68SYiFei Zhu goto out_free; 331aff52e68SYiFei Zhu 332aff52e68SYiFei Zhu vlen = btf_vlen(t_datasec); 333aff52e68SYiFei Zhu vsi = btf_var_secinfos(t_datasec); 334aff52e68SYiFei Zhu 335aff52e68SYiFei Zhu /* We don't proceed to check the kinds of the elements of the DATASEC. 336aff52e68SYiFei Zhu * The verifier enforces them to be BTF_KIND_VAR. 337aff52e68SYiFei Zhu */ 338aff52e68SYiFei Zhu 339aff52e68SYiFei Zhu if (json_output) { 340aff52e68SYiFei Zhu struct btf_dumper d = { 341aff52e68SYiFei Zhu .btf = btf, 342aff52e68SYiFei Zhu .jw = json_wtr, 343aff52e68SYiFei Zhu .is_plain_text = false, 344aff52e68SYiFei Zhu }; 345aff52e68SYiFei Zhu 346aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 347aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 348aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 349aff52e68SYiFei Zhu 350aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 351aff52e68SYiFei Zhu continue; 352aff52e68SYiFei Zhu 353aff52e68SYiFei Zhu if (!printed_header) { 354aff52e68SYiFei Zhu jsonw_name(json_wtr, "metadata"); 355aff52e68SYiFei Zhu jsonw_start_object(json_wtr); 356aff52e68SYiFei Zhu printed_header = true; 357aff52e68SYiFei Zhu } 358aff52e68SYiFei Zhu 359aff52e68SYiFei Zhu jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); 360aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 361aff52e68SYiFei Zhu if (err) { 362aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 363aff52e68SYiFei Zhu break; 364aff52e68SYiFei Zhu } 365aff52e68SYiFei Zhu } 366aff52e68SYiFei Zhu if (printed_header) 367aff52e68SYiFei Zhu jsonw_end_object(json_wtr); 368aff52e68SYiFei Zhu } else { 369e89ef634SQuentin Monnet json_writer_t *btf_wtr; 370aff52e68SYiFei Zhu struct btf_dumper d = { 371aff52e68SYiFei Zhu .btf = btf, 372aff52e68SYiFei Zhu .is_plain_text = true, 373aff52e68SYiFei Zhu }; 374aff52e68SYiFei Zhu 375aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 376aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 377aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 378aff52e68SYiFei Zhu 379aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 380aff52e68SYiFei Zhu continue; 381aff52e68SYiFei Zhu 382aff52e68SYiFei Zhu if (!printed_header) { 383aff52e68SYiFei Zhu printf("\tmetadata:"); 384e89ef634SQuentin Monnet 385e89ef634SQuentin Monnet btf_wtr = jsonw_new(stdout); 386e89ef634SQuentin Monnet if (!btf_wtr) { 387e89ef634SQuentin Monnet p_err("jsonw alloc failed"); 388e89ef634SQuentin Monnet goto out_free; 389e89ef634SQuentin Monnet } 390e89ef634SQuentin Monnet d.jw = btf_wtr, 391e89ef634SQuentin Monnet 392aff52e68SYiFei Zhu printed_header = true; 393aff52e68SYiFei Zhu } 394aff52e68SYiFei Zhu 395aff52e68SYiFei Zhu printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); 396aff52e68SYiFei Zhu 397aff52e68SYiFei Zhu jsonw_reset(btf_wtr); 398aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 399aff52e68SYiFei Zhu if (err) { 400aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 401aff52e68SYiFei Zhu break; 402aff52e68SYiFei Zhu } 403aff52e68SYiFei Zhu } 404aff52e68SYiFei Zhu if (printed_header) 405aff52e68SYiFei Zhu jsonw_destroy(&btf_wtr); 406aff52e68SYiFei Zhu } 407aff52e68SYiFei Zhu 408aff52e68SYiFei Zhu out_free: 409aff52e68SYiFei Zhu btf__free(btf); 410aff52e68SYiFei Zhu free(value); 411aff52e68SYiFei Zhu } 412aff52e68SYiFei Zhu 413b662000aSRaman Shukhau static void print_prog_header_json(struct bpf_prog_info *info, int fd) 414743cc665SQuentin Monnet { 415b700eeb4SDaniel Müller const char *prog_type_str; 416b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 417b662000aSRaman Shukhau 418743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 419b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 420b700eeb4SDaniel Müller 421b700eeb4SDaniel Müller if (prog_type_str) 422b700eeb4SDaniel Müller jsonw_string_field(json_wtr, "type", prog_type_str); 42371bb428fSJakub Kicinski else 424743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 42571bb428fSJakub Kicinski 426b662000aSRaman Shukhau if (*info->name) { 427b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 428b662000aSRaman Shukhau jsonw_string_field(json_wtr, "name", prog_name); 429b662000aSRaman Shukhau } 43071bb428fSJakub Kicinski 431743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 432743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 433743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 434743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 43571bb428fSJakub Kicinski 4369b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 43788ad472bSAlexei Starovoitov if (info->run_time_ns) { 43888ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 43988ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 44088ad472bSAlexei Starovoitov } 4419ed9e9baSAlexei Starovoitov if (info->recursion_misses) 4429ed9e9baSAlexei Starovoitov jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 443ec202509SPaul Chaignon } 4449b984a20SJiri Olsa 445ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 446ec202509SPaul Chaignon { 447ec202509SPaul Chaignon char *memlock; 448ec202509SPaul Chaignon 449ec202509SPaul Chaignon jsonw_start_object(json_wtr); 450b662000aSRaman Shukhau print_prog_header_json(info, fd); 45152262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 45252262210SJakub Kicinski 453743cc665SQuentin Monnet if (info->load_time) { 45471bb428fSJakub Kicinski char buf[32]; 45571bb428fSJakub Kicinski 456743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 45771bb428fSJakub Kicinski 45871bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 459a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 460a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 461743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 46271bb428fSJakub Kicinski } 46371bb428fSJakub Kicinski 464743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 46571bb428fSJakub Kicinski 466743cc665SQuentin Monnet if (info->jited_prog_len) { 467743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 468743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 469743cc665SQuentin Monnet } else { 470743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 471743cc665SQuentin Monnet } 472743cc665SQuentin Monnet 473743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 474743cc665SQuentin Monnet if (memlock) 475357b3cc3SChris J Arges jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock)); 476743cc665SQuentin Monnet free(memlock); 477743cc665SQuentin Monnet 478743cc665SQuentin Monnet if (info->nr_map_ids) 479743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 480743cc665SQuentin Monnet 481569b0c77SPrashant Bhole if (info->btf_id) 482569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 483569b0c77SPrashant Bhole 4848f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 4858f184732SQuentin Monnet struct hashmap_entry *entry; 4864990f1f4SPrashant Bhole 4874990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 4884990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 489c302378bSEduard Zingerman hashmap__for_each_key_entry(prog_table, entry, info->id) 490c302378bSEduard Zingerman jsonw_string(json_wtr, entry->pvalue); 4914990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 4924990f1f4SPrashant Bhole } 4934990f1f4SPrashant Bhole 494d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 495d53dee3fSAndrii Nakryiko 496aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 497aff52e68SYiFei Zhu 498743cc665SQuentin Monnet jsonw_end_object(json_wtr); 499743cc665SQuentin Monnet } 500743cc665SQuentin Monnet 501b662000aSRaman Shukhau static void print_prog_header_plain(struct bpf_prog_info *info, int fd) 502743cc665SQuentin Monnet { 503b700eeb4SDaniel Müller const char *prog_type_str; 504b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 505b662000aSRaman Shukhau 506743cc665SQuentin Monnet printf("%u: ", info->id); 507b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 508b700eeb4SDaniel Müller if (prog_type_str) 509b700eeb4SDaniel Müller printf("%s ", prog_type_str); 510743cc665SQuentin Monnet else 511743cc665SQuentin Monnet printf("type %u ", info->type); 512743cc665SQuentin Monnet 513b662000aSRaman Shukhau if (*info->name) { 514b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 515b662000aSRaman Shukhau printf("name %s ", prog_name); 516b662000aSRaman Shukhau } 517743cc665SQuentin Monnet 518743cc665SQuentin Monnet printf("tag "); 519743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 52052262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5219b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 52288ad472bSAlexei Starovoitov if (info->run_time_ns) 52388ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 52488ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5259ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5269ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 527743cc665SQuentin Monnet printf("\n"); 528ec202509SPaul Chaignon } 529ec202509SPaul Chaignon 530ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 531ec202509SPaul Chaignon { 532ec202509SPaul Chaignon char *memlock; 533ec202509SPaul Chaignon 534b662000aSRaman Shukhau print_prog_header_plain(info, fd); 535743cc665SQuentin Monnet 536743cc665SQuentin Monnet if (info->load_time) { 537743cc665SQuentin Monnet char buf[32]; 538743cc665SQuentin Monnet 539743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 540743cc665SQuentin Monnet 541743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 542743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 543743cc665SQuentin Monnet } 544743cc665SQuentin Monnet 545743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 546743cc665SQuentin Monnet 547743cc665SQuentin Monnet if (info->jited_prog_len) 548743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 54971bb428fSJakub Kicinski else 55071bb428fSJakub Kicinski printf(" not jited"); 55171bb428fSJakub Kicinski 55271bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 55371bb428fSJakub Kicinski if (memlock) 55471bb428fSJakub Kicinski printf(" memlock %sB", memlock); 55571bb428fSJakub Kicinski free(memlock); 55671bb428fSJakub Kicinski 557743cc665SQuentin Monnet if (info->nr_map_ids) 558743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 55971bb428fSJakub Kicinski 5608f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5618f184732SQuentin Monnet struct hashmap_entry *entry; 5624990f1f4SPrashant Bhole 563c302378bSEduard Zingerman hashmap__for_each_key_entry(prog_table, entry, info->id) 564c302378bSEduard Zingerman printf("\n\tpinned %s", (char *)entry->pvalue); 5654990f1f4SPrashant Bhole } 5664990f1f4SPrashant Bhole 567569b0c77SPrashant Bhole if (info->btf_id) 568031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 569569b0c77SPrashant Bhole 570d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 571d53dee3fSAndrii Nakryiko 57271bb428fSJakub Kicinski printf("\n"); 573aff52e68SYiFei Zhu 574aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 575743cc665SQuentin Monnet } 576743cc665SQuentin Monnet 577743cc665SQuentin Monnet static int show_prog(int fd) 578743cc665SQuentin Monnet { 579743cc665SQuentin Monnet struct bpf_prog_info info = {}; 580743cc665SQuentin Monnet __u32 len = sizeof(info); 581743cc665SQuentin Monnet int err; 582743cc665SQuentin Monnet 58338f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fd, &info, &len); 584743cc665SQuentin Monnet if (err) { 5859a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 586743cc665SQuentin Monnet return -1; 587743cc665SQuentin Monnet } 588743cc665SQuentin Monnet 589743cc665SQuentin Monnet if (json_output) 590743cc665SQuentin Monnet print_prog_json(&info, fd); 591743cc665SQuentin Monnet else 592743cc665SQuentin Monnet print_prog_plain(&info, fd); 59371bb428fSJakub Kicinski 59471bb428fSJakub Kicinski return 0; 59571bb428fSJakub Kicinski } 59671bb428fSJakub Kicinski 597ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 598ec202509SPaul Chaignon { 599ec202509SPaul Chaignon int *fds = NULL; 600ec202509SPaul Chaignon int nb_fds, i; 601ec202509SPaul Chaignon int err = -1; 602ec202509SPaul Chaignon 603ec202509SPaul Chaignon fds = malloc(sizeof(int)); 604ec202509SPaul Chaignon if (!fds) { 605ec202509SPaul Chaignon p_err("mem alloc failed"); 606ec202509SPaul Chaignon return -1; 607ec202509SPaul Chaignon } 608ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 609ec202509SPaul Chaignon if (nb_fds < 1) 610ec202509SPaul Chaignon goto exit_free; 611ec202509SPaul Chaignon 612ec202509SPaul Chaignon if (json_output && nb_fds > 1) 613ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 614ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 615ec202509SPaul Chaignon err = show_prog(fds[i]); 616ec202509SPaul Chaignon if (err) { 617ec202509SPaul Chaignon for (; i < nb_fds; i++) 618ec202509SPaul Chaignon close(fds[i]); 619ec202509SPaul Chaignon break; 620ec202509SPaul Chaignon } 621ec202509SPaul Chaignon close(fds[i]); 622ec202509SPaul Chaignon } 623ec202509SPaul Chaignon if (json_output && nb_fds > 1) 624ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 625ec202509SPaul Chaignon 626ec202509SPaul Chaignon exit_free: 627ec202509SPaul Chaignon free(fds); 628ec202509SPaul Chaignon return err; 629ec202509SPaul Chaignon } 630ec202509SPaul Chaignon 63171bb428fSJakub Kicinski static int do_show(int argc, char **argv) 632743cc665SQuentin Monnet { 633743cc665SQuentin Monnet __u32 id = 0; 63471bb428fSJakub Kicinski int err; 63571bb428fSJakub Kicinski int fd; 63671bb428fSJakub Kicinski 63746241271SQuentin Monnet if (show_pinned) { 6388f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6398f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 640622a5b58SMauricio Vásquez if (IS_ERR(prog_table)) { 6418f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6428f184732SQuentin Monnet return -1; 6438f184732SQuentin Monnet } 6448f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 64546241271SQuentin Monnet } 646d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6474990f1f4SPrashant Bhole 648ec202509SPaul Chaignon if (argc == 2) 649ec202509SPaul Chaignon return do_show_subset(argc, argv); 65071bb428fSJakub Kicinski 65171bb428fSJakub Kicinski if (argc) 65271bb428fSJakub Kicinski return BAD_ARG(); 65371bb428fSJakub Kicinski 654743cc665SQuentin Monnet if (json_output) 655743cc665SQuentin Monnet jsonw_start_array(json_wtr); 65671bb428fSJakub Kicinski while (true) { 65771bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 65871bb428fSJakub Kicinski if (err) { 6591739c26dSQuentin Monnet if (errno == ENOENT) { 6601739c26dSQuentin Monnet err = 0; 66171bb428fSJakub Kicinski break; 6621739c26dSQuentin Monnet } 6639a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6649a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 665743cc665SQuentin Monnet err = -1; 666743cc665SQuentin Monnet break; 66771bb428fSJakub Kicinski } 66871bb428fSJakub Kicinski 66971bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 67071bb428fSJakub Kicinski if (fd < 0) { 6718207c6ddSJakub Kicinski if (errno == ENOENT) 6728207c6ddSJakub Kicinski continue; 6739a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 67471bb428fSJakub Kicinski id, strerror(errno)); 675743cc665SQuentin Monnet err = -1; 676743cc665SQuentin Monnet break; 67771bb428fSJakub Kicinski } 67871bb428fSJakub Kicinski 67971bb428fSJakub Kicinski err = show_prog(fd); 68071bb428fSJakub Kicinski close(fd); 68171bb428fSJakub Kicinski if (err) 682743cc665SQuentin Monnet break; 68371bb428fSJakub Kicinski } 68471bb428fSJakub Kicinski 685743cc665SQuentin Monnet if (json_output) 686743cc665SQuentin Monnet jsonw_end_array(json_wtr); 687743cc665SQuentin Monnet 688d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 689d53dee3fSAndrii Nakryiko 69046241271SQuentin Monnet if (show_pinned) 6918f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 69246241271SQuentin Monnet 693743cc665SQuentin Monnet return err; 69471bb428fSJakub Kicinski } 69571bb428fSJakub Kicinski 696ec202509SPaul Chaignon static int 697ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 698ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 69971bb428fSJakub Kicinski { 700b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 7013ddeac67SJakub Kicinski const char *disasm_opt = NULL; 7027105e828SDaniel Borkmann struct dump_data dd = {}; 703cae73f23SSong Liu void *func_info = NULL; 704254471e5SYonghong Song struct btf *btf = NULL; 705254471e5SYonghong Song char func_sig[1024]; 70671bb428fSJakub Kicinski unsigned char *buf; 707cae73f23SSong Liu __u32 member_len; 708ebbd7f64SQuentin Monnet int fd, err = -1; 70971bb428fSJakub Kicinski ssize_t n; 71071bb428fSJakub Kicinski 711cae73f23SSong Liu if (mode == DUMP_JITED) { 7125b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 7139a5ab8bfSQuentin Monnet p_info("no instructions returned"); 714ec202509SPaul Chaignon return -1; 715f84192eeSSandipan Das } 71609f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 717cae73f23SSong Liu member_len = info->jited_prog_len; 718cae73f23SSong Liu } else { /* DUMP_XLATED */ 719d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7207105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 721ec202509SPaul Chaignon return -1; 7227105e828SDaniel Borkmann } 72309f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 724cae73f23SSong Liu member_len = info->xlated_prog_len; 725cae73f23SSong Liu } 7267105e828SDaniel Borkmann 72786f4b7f2SQuentin Monnet if (info->btf_id) { 72886f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 729d1313e01SSahid Orentino Ferdjaoui if (!btf) { 730254471e5SYonghong Song p_err("failed to get btf"); 731ec202509SPaul Chaignon return -1; 732254471e5SYonghong Song } 73386f4b7f2SQuentin Monnet } 734254471e5SYonghong Song 73509f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 736cae73f23SSong Liu 737cae73f23SSong Liu if (info->nr_line_info) { 738cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 739b053b439SMartin KaFai Lau if (!prog_linfo) 74010a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 741b053b439SMartin KaFai Lau } 742b053b439SMartin KaFai Lau 74371bb428fSJakub Kicinski if (filepath) { 74471bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 74571bb428fSJakub Kicinski if (fd < 0) { 7469a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 74771bb428fSJakub Kicinski strerror(errno)); 748ebbd7f64SQuentin Monnet goto exit_free; 74971bb428fSJakub Kicinski } 75071bb428fSJakub Kicinski 751cae73f23SSong Liu n = write(fd, buf, member_len); 75271bb428fSJakub Kicinski close(fd); 75309f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7549a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 75571bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 756ebbd7f64SQuentin Monnet goto exit_free; 75771bb428fSJakub Kicinski } 75852c84d36SQuentin Monnet 75952c84d36SQuentin Monnet if (json_output) 76052c84d36SQuentin Monnet jsonw_null(json_wtr); 761cae73f23SSong Liu } else if (mode == DUMP_JITED) { 762e6593596SJiong Wang const char *name = NULL; 763e6593596SJiong Wang 764cae73f23SSong Liu if (info->ifindex) { 765ce4f6608SQuentin Monnet name = ifindex_to_arch(info->ifindex, info->netns_dev, 766ce4f6608SQuentin Monnet info->netns_ino, &disasm_opt); 767e6593596SJiong Wang if (!name) 768ebbd7f64SQuentin Monnet goto exit_free; 769e6593596SJiong Wang } 770e6593596SJiong Wang 771cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 772f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 773254471e5SYonghong Song struct bpf_func_info *record; 774f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 775f7f62c71SSandipan Das unsigned char *img = buf; 776f7f62c71SSandipan Das __u64 *ksyms = NULL; 777f7f62c71SSandipan Das __u32 *lens; 778f7f62c71SSandipan Das __u32 i; 779cae73f23SSong Liu if (info->nr_jited_ksyms) { 780f7f62c71SSandipan Das kernel_syms_load(&dd); 78109f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 782f7f62c71SSandipan Das } 783f7f62c71SSandipan Das 784f7f62c71SSandipan Das if (json_output) 785f7f62c71SSandipan Das jsonw_start_array(json_wtr); 786f7f62c71SSandipan Das 78709f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 788cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 789f7f62c71SSandipan Das if (ksyms) { 790f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 791f7f62c71SSandipan Das if (sym) 792f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 793f7f62c71SSandipan Das else 794f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 795f7f62c71SSandipan Das } else { 796f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 797f7f62c71SSandipan Das } 798f7f62c71SSandipan Das 799254471e5SYonghong Song if (func_info) { 800cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 801254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 802254471e5SYonghong Song func_sig, 803254471e5SYonghong Song sizeof(func_sig)); 804254471e5SYonghong Song } 805254471e5SYonghong Song 806f7f62c71SSandipan Das if (json_output) { 807f7f62c71SSandipan Das jsonw_start_object(json_wtr); 808254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 809254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 810254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 811254471e5SYonghong Song } 812f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 813f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 814f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 815f7f62c71SSandipan Das } else { 816254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 817254471e5SYonghong Song printf("%s:\n", func_sig); 818f7f62c71SSandipan Das printf("%s:\n", sym_name); 819f7f62c71SSandipan Das } 820f7f62c71SSandipan Das 82155b4de58SQuentin Monnet if (disasm_print_insn(img, lens[i], opcodes, 822b053b439SMartin KaFai Lau name, disasm_opt, btf, 823b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 82455b4de58SQuentin Monnet linum)) 82555b4de58SQuentin Monnet goto exit_free; 826b053b439SMartin KaFai Lau 827f7f62c71SSandipan Das img += lens[i]; 828f7f62c71SSandipan Das 829f7f62c71SSandipan Das if (json_output) 830f7f62c71SSandipan Das jsonw_end_object(json_wtr); 831f7f62c71SSandipan Das else 832f7f62c71SSandipan Das printf("\n"); 833f7f62c71SSandipan Das } 834f7f62c71SSandipan Das 835f7f62c71SSandipan Das if (json_output) 836f7f62c71SSandipan Das jsonw_end_array(json_wtr); 837f7f62c71SSandipan Das } else { 83855b4de58SQuentin Monnet if (disasm_print_insn(buf, member_len, opcodes, name, 83955b4de58SQuentin Monnet disasm_opt, btf, NULL, 0, 0, 84055b4de58SQuentin Monnet false)) 84155b4de58SQuentin Monnet goto exit_free; 842f7f62c71SSandipan Das } 8437105e828SDaniel Borkmann } else { 8447105e828SDaniel Borkmann kernel_syms_load(&dd); 845cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 84609f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 847254471e5SYonghong Song dd.btf = btf; 848254471e5SYonghong Song dd.func_info = func_info; 849cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 850b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 851f84192eeSSandipan Das 85205a06be7SQuentin Monnet if (json_output) 8539fd49684SQuentin Monnet dump_xlated_json(&dd, buf, member_len, opcodes, linum); 8549fd49684SQuentin Monnet else if (visual) 8557483a7a7SQuentin Monnet dump_xlated_cfg(&dd, buf, member_len, opcodes, linum); 856f05e2c32SQuentin Monnet else 8579fd49684SQuentin Monnet dump_xlated_plain(&dd, buf, member_len, opcodes, linum); 8587105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8597105e828SDaniel Borkmann } 86071bb428fSJakub Kicinski 861ebbd7f64SQuentin Monnet err = 0; 862369e955bSQuentin Monnet 863ebbd7f64SQuentin Monnet exit_free: 864ebbd7f64SQuentin Monnet btf__free(btf); 865ebbd7f64SQuentin Monnet bpf_prog_linfo__free(prog_linfo); 866ebbd7f64SQuentin Monnet return err; 867ec202509SPaul Chaignon } 86871bb428fSJakub Kicinski 869ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 870ec202509SPaul Chaignon { 871c59765cfSDave Marchevsky struct bpf_prog_info info; 872c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 873c59765cfSDave Marchevsky size_t info_data_sz = 0; 874c59765cfSDave Marchevsky void *info_data = NULL; 875ec202509SPaul Chaignon char *filepath = NULL; 876ec202509SPaul Chaignon bool opcodes = false; 877ec202509SPaul Chaignon bool visual = false; 878ec202509SPaul Chaignon enum dump_mode mode; 879ec202509SPaul Chaignon bool linum = false; 880ec202509SPaul Chaignon int nb_fds, i = 0; 881c59765cfSDave Marchevsky int *fds = NULL; 882ec202509SPaul Chaignon int err = -1; 883ec202509SPaul Chaignon 884ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 885ec202509SPaul Chaignon if (disasm_init()) 88671bb428fSJakub Kicinski return -1; 887ec202509SPaul Chaignon mode = DUMP_JITED; 888ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 889ec202509SPaul Chaignon mode = DUMP_XLATED; 890ec202509SPaul Chaignon } else { 891ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 892ec202509SPaul Chaignon return -1; 893ec202509SPaul Chaignon } 894ec202509SPaul Chaignon NEXT_ARG(); 895ec202509SPaul Chaignon 896ec202509SPaul Chaignon if (argc < 2) 897ec202509SPaul Chaignon usage(); 898ec202509SPaul Chaignon 899ec202509SPaul Chaignon fds = malloc(sizeof(int)); 900ec202509SPaul Chaignon if (!fds) { 901ec202509SPaul Chaignon p_err("mem alloc failed"); 902ec202509SPaul Chaignon return -1; 903ec202509SPaul Chaignon } 904ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 905ec202509SPaul Chaignon if (nb_fds < 1) 906ec202509SPaul Chaignon goto exit_free; 907ec202509SPaul Chaignon 9089b79f027SQuentin Monnet while (argc) { 909ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 910ec202509SPaul Chaignon NEXT_ARG(); 911ec202509SPaul Chaignon if (!argc) { 912ec202509SPaul Chaignon p_err("expected file path"); 913ec202509SPaul Chaignon goto exit_close; 914ec202509SPaul Chaignon } 915ec202509SPaul Chaignon if (nb_fds > 1) { 916ec202509SPaul Chaignon p_err("several programs matched"); 917ec202509SPaul Chaignon goto exit_close; 918ec202509SPaul Chaignon } 919ec202509SPaul Chaignon 920ec202509SPaul Chaignon filepath = *argv; 921ec202509SPaul Chaignon NEXT_ARG(); 922ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 923ec202509SPaul Chaignon opcodes = true; 924ec202509SPaul Chaignon NEXT_ARG(); 925ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 926ec202509SPaul Chaignon if (nb_fds > 1) { 927ec202509SPaul Chaignon p_err("several programs matched"); 928ec202509SPaul Chaignon goto exit_close; 929ec202509SPaul Chaignon } 930ec202509SPaul Chaignon 931ec202509SPaul Chaignon visual = true; 932ec202509SPaul Chaignon NEXT_ARG(); 933ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 934ec202509SPaul Chaignon linum = true; 935ec202509SPaul Chaignon NEXT_ARG(); 9369b79f027SQuentin Monnet } else { 9379b79f027SQuentin Monnet usage(); 9389b79f027SQuentin Monnet goto exit_close; 9399b79f027SQuentin Monnet } 940ec202509SPaul Chaignon } 941ec202509SPaul Chaignon 9429b79f027SQuentin Monnet if (filepath && (opcodes || visual || linum)) { 9439b79f027SQuentin Monnet p_err("'file' is not compatible with 'opcodes', 'visual', or 'linum'"); 944ec202509SPaul Chaignon goto exit_close; 945ec202509SPaul Chaignon } 94605a06be7SQuentin Monnet if (json_output && visual) { 94705a06be7SQuentin Monnet p_err("'visual' is not compatible with JSON output"); 94805a06be7SQuentin Monnet goto exit_close; 94905a06be7SQuentin Monnet } 950ec202509SPaul Chaignon 951ec202509SPaul Chaignon if (json_output && nb_fds > 1) 952ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 953ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 954c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 955c59765cfSDave Marchevsky 95638f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len); 957c59765cfSDave Marchevsky if (err) { 958c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 959c59765cfSDave Marchevsky break; 960c59765cfSDave Marchevsky } 961c59765cfSDave Marchevsky 962c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 963c59765cfSDave Marchevsky if (err) { 964c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 965c59765cfSDave Marchevsky break; 966c59765cfSDave Marchevsky } 967c59765cfSDave Marchevsky 96838f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len); 969c59765cfSDave Marchevsky if (err) { 970ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 971ec202509SPaul Chaignon break; 972ec202509SPaul Chaignon } 973ec202509SPaul Chaignon 974ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 975ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 976b662000aSRaman Shukhau print_prog_header_json(&info, fds[i]); 977ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 978ec202509SPaul Chaignon } else if (nb_fds > 1) { 979b662000aSRaman Shukhau print_prog_header_plain(&info, fds[i]); 980ec202509SPaul Chaignon } 981ec202509SPaul Chaignon 982c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 983ec202509SPaul Chaignon 984ec202509SPaul Chaignon if (json_output && nb_fds > 1) 985ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 986ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 987ec202509SPaul Chaignon printf("\n"); 988ec202509SPaul Chaignon 989ec202509SPaul Chaignon if (err) 990ec202509SPaul Chaignon break; 991ec202509SPaul Chaignon close(fds[i]); 992ec202509SPaul Chaignon } 993ec202509SPaul Chaignon if (json_output && nb_fds > 1) 994ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 995ec202509SPaul Chaignon 996ec202509SPaul Chaignon exit_close: 997ec202509SPaul Chaignon for (; i < nb_fds; i++) 998ec202509SPaul Chaignon close(fds[i]); 999ec202509SPaul Chaignon exit_free: 1000c59765cfSDave Marchevsky free(info_data); 1001ec202509SPaul Chaignon free(fds); 1002ec202509SPaul Chaignon return err; 100371bb428fSJakub Kicinski } 100471bb428fSJakub Kicinski 100571bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 100671bb428fSJakub Kicinski { 1007004b45c0SQuentin Monnet int err; 1008004b45c0SQuentin Monnet 100975a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 1010004b45c0SQuentin Monnet if (!err && json_output) 1011004b45c0SQuentin Monnet jsonw_null(json_wtr); 1012004b45c0SQuentin Monnet return err; 101371bb428fSJakub Kicinski } 101471bb428fSJakub Kicinski 10153ff5a4dcSJakub Kicinski struct map_replace { 10163ff5a4dcSJakub Kicinski int idx; 10173ff5a4dcSJakub Kicinski int fd; 10183ff5a4dcSJakub Kicinski char *name; 10193ff5a4dcSJakub Kicinski }; 10203ff5a4dcSJakub Kicinski 1021c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 10223ff5a4dcSJakub Kicinski { 10233ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10243ff5a4dcSJakub Kicinski 10253ff5a4dcSJakub Kicinski return a->idx - b->idx; 10263ff5a4dcSJakub Kicinski } 10273ff5a4dcSJakub Kicinski 1028092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1029092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1030092f0892SStanislav Fomichev int *mapfd) 1031092f0892SStanislav Fomichev { 1032092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1033092f0892SStanislav Fomichev return -EINVAL; 1034092f0892SStanislav Fomichev 1035092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1036092f0892SStanislav Fomichev if (*progfd < 0) 1037092f0892SStanislav Fomichev return *progfd; 1038092f0892SStanislav Fomichev 1039092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1040092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1041092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1042092f0892SStanislav Fomichev return -EINVAL; 1043092f0892SStanislav Fomichev } 1044092f0892SStanislav Fomichev 1045092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1046f9b7ff0dSLorenz Bauer *mapfd = 0; 1047092f0892SStanislav Fomichev return 0; 1048092f0892SStanislav Fomichev } 1049092f0892SStanislav Fomichev 1050092f0892SStanislav Fomichev NEXT_ARG(); 1051092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1052092f0892SStanislav Fomichev return -EINVAL; 1053092f0892SStanislav Fomichev 1054092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1055092f0892SStanislav Fomichev if (*mapfd < 0) 1056092f0892SStanislav Fomichev return *mapfd; 1057092f0892SStanislav Fomichev 1058092f0892SStanislav Fomichev return 0; 1059092f0892SStanislav Fomichev } 1060092f0892SStanislav Fomichev 1061b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1062b7d3826cSJohn Fastabend { 1063b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1064092f0892SStanislav Fomichev int err, progfd; 1065092f0892SStanislav Fomichev int mapfd; 1066b7d3826cSJohn Fastabend 1067092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1068092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1069092f0892SStanislav Fomichev if (err) 1070092f0892SStanislav Fomichev return err; 1071b7d3826cSJohn Fastabend 1072b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1073b7d3826cSJohn Fastabend if (err) { 1074b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1075b7d3826cSJohn Fastabend return -EINVAL; 1076b7d3826cSJohn Fastabend } 1077b7d3826cSJohn Fastabend 1078b7d3826cSJohn Fastabend if (json_output) 1079b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1080b7d3826cSJohn Fastabend return 0; 1081b7d3826cSJohn Fastabend } 1082b7d3826cSJohn Fastabend 1083b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1084b7d3826cSJohn Fastabend { 1085b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1086092f0892SStanislav Fomichev int err, progfd; 1087092f0892SStanislav Fomichev int mapfd; 1088b7d3826cSJohn Fastabend 1089092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1090092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1091092f0892SStanislav Fomichev if (err) 1092092f0892SStanislav Fomichev return err; 1093b7d3826cSJohn Fastabend 1094b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1095b7d3826cSJohn Fastabend if (err) { 1096b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1097b7d3826cSJohn Fastabend return -EINVAL; 1098b7d3826cSJohn Fastabend } 1099b7d3826cSJohn Fastabend 1100b7d3826cSJohn Fastabend if (json_output) 1101b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1102b7d3826cSJohn Fastabend return 0; 1103b7d3826cSJohn Fastabend } 110477380998SStanislav Fomichev 1105ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1106ba95c745SQuentin Monnet { 1107ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1108ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1109ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1110ba95c745SQuentin Monnet return -1; 1111ba95c745SQuentin Monnet } 1112ba95c745SQuentin Monnet 1113ba95c745SQuentin Monnet return 0; 1114ba95c745SQuentin Monnet } 1115ba95c745SQuentin Monnet 1116ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1117ba95c745SQuentin Monnet { 1118ba95c745SQuentin Monnet size_t block_size = 256; 1119ba95c745SQuentin Monnet size_t buf_size = block_size; 1120ba95c745SQuentin Monnet size_t nb_read = 0; 1121ba95c745SQuentin Monnet void *tmp; 1122ba95c745SQuentin Monnet FILE *f; 1123ba95c745SQuentin Monnet 1124ba95c745SQuentin Monnet if (!fname) { 1125ba95c745SQuentin Monnet *data_ptr = NULL; 1126ba95c745SQuentin Monnet *size = 0; 1127ba95c745SQuentin Monnet return 0; 1128ba95c745SQuentin Monnet } 1129ba95c745SQuentin Monnet 1130ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1131ba95c745SQuentin Monnet f = stdin; 1132ba95c745SQuentin Monnet else 1133ba95c745SQuentin Monnet f = fopen(fname, "r"); 1134ba95c745SQuentin Monnet if (!f) { 1135ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1136ba95c745SQuentin Monnet return -1; 1137ba95c745SQuentin Monnet } 1138ba95c745SQuentin Monnet 1139ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1140ba95c745SQuentin Monnet if (!*data_ptr) { 1141ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1142ba95c745SQuentin Monnet strerror(errno)); 1143ba95c745SQuentin Monnet goto err_fclose; 1144ba95c745SQuentin Monnet } 1145ba95c745SQuentin Monnet 1146ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1147ba95c745SQuentin Monnet if (feof(f)) 1148ba95c745SQuentin Monnet break; 1149ba95c745SQuentin Monnet if (ferror(f)) { 1150ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1151ba95c745SQuentin Monnet fname, strerror(errno)); 1152ba95c745SQuentin Monnet goto err_free; 1153ba95c745SQuentin Monnet } 1154ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1155ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1156ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1157ba95c745SQuentin Monnet UINT32_MAX); 1158ba95c745SQuentin Monnet goto err_free; 1159ba95c745SQuentin Monnet } 1160ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1161ba95c745SQuentin Monnet buf_size *= 2; 1162ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1163ba95c745SQuentin Monnet if (!tmp) { 1164ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1165ba95c745SQuentin Monnet strerror(errno)); 1166ba95c745SQuentin Monnet goto err_free; 1167ba95c745SQuentin Monnet } 1168ba95c745SQuentin Monnet *data_ptr = tmp; 1169ba95c745SQuentin Monnet } 1170ba95c745SQuentin Monnet } 1171ba95c745SQuentin Monnet if (f != stdin) 1172ba95c745SQuentin Monnet fclose(f); 1173ba95c745SQuentin Monnet 1174ba95c745SQuentin Monnet *size = nb_read; 1175ba95c745SQuentin Monnet return 0; 1176ba95c745SQuentin Monnet 1177ba95c745SQuentin Monnet err_free: 1178ba95c745SQuentin Monnet free(*data_ptr); 1179ba95c745SQuentin Monnet *data_ptr = NULL; 1180ba95c745SQuentin Monnet err_fclose: 1181ba95c745SQuentin Monnet if (f != stdin) 1182ba95c745SQuentin Monnet fclose(f); 1183ba95c745SQuentin Monnet return -1; 1184ba95c745SQuentin Monnet } 1185ba95c745SQuentin Monnet 1186ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1187ba95c745SQuentin Monnet { 1188ba95c745SQuentin Monnet size_t i, j; 1189ba95c745SQuentin Monnet char c; 1190ba95c745SQuentin Monnet 1191ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1192ba95c745SQuentin Monnet /* Row offset */ 1193ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1194ba95c745SQuentin Monnet 1195ba95c745SQuentin Monnet /* Hexadecimal values */ 1196ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1197ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1198ba95c745SQuentin Monnet j % 2 ? " " : ""); 1199ba95c745SQuentin Monnet for (; j < i + 16; j++) 1200ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1201ba95c745SQuentin Monnet 1202ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1203ba95c745SQuentin Monnet fprintf(f, "| "); 1204ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1205ba95c745SQuentin Monnet c = *(char *)(data + j); 1206ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1207ba95c745SQuentin Monnet c = '.'; 1208ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1209ba95c745SQuentin Monnet } 1210ba95c745SQuentin Monnet 1211ba95c745SQuentin Monnet fprintf(f, "\n"); 1212ba95c745SQuentin Monnet } 1213ba95c745SQuentin Monnet } 1214ba95c745SQuentin Monnet 1215ba95c745SQuentin Monnet static int 1216ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1217ba95c745SQuentin Monnet const char *json_key) 1218ba95c745SQuentin Monnet { 1219ba95c745SQuentin Monnet size_t nb_written; 1220ba95c745SQuentin Monnet FILE *f; 1221ba95c745SQuentin Monnet 1222ba95c745SQuentin Monnet if (!fname) 1223ba95c745SQuentin Monnet return 0; 1224ba95c745SQuentin Monnet 1225ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1226ba95c745SQuentin Monnet f = stdout; 1227ba95c745SQuentin Monnet if (json_output) { 1228ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1229ba95c745SQuentin Monnet print_data_json(data, size); 1230ba95c745SQuentin Monnet } else { 1231ba95c745SQuentin Monnet hex_print(data, size, f); 1232ba95c745SQuentin Monnet } 1233ba95c745SQuentin Monnet return 0; 1234ba95c745SQuentin Monnet } 1235ba95c745SQuentin Monnet 1236ba95c745SQuentin Monnet f = fopen(fname, "w"); 1237ba95c745SQuentin Monnet if (!f) { 1238ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1239ba95c745SQuentin Monnet return -1; 1240ba95c745SQuentin Monnet } 1241ba95c745SQuentin Monnet 1242ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1243ba95c745SQuentin Monnet fclose(f); 1244ba95c745SQuentin Monnet if (nb_written != size) { 1245ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1246ba95c745SQuentin Monnet return -1; 1247ba95c745SQuentin Monnet } 1248ba95c745SQuentin Monnet 1249ba95c745SQuentin Monnet return 0; 1250ba95c745SQuentin Monnet } 1251ba95c745SQuentin Monnet 1252ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1253ba95c745SQuentin Monnet { 1254ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1255ba95c745SQuentin Monnet if (!*data_ptr) { 1256ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1257ba95c745SQuentin Monnet strerror(errno)); 1258ba95c745SQuentin Monnet return -1; 1259ba95c745SQuentin Monnet } 1260ba95c745SQuentin Monnet 1261ba95c745SQuentin Monnet return 0; 1262ba95c745SQuentin Monnet } 1263ba95c745SQuentin Monnet 1264ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1265ba95c745SQuentin Monnet { 1266ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1267ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1268ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1269ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1270ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1271ba95c745SQuentin Monnet unsigned int repeat = 1; 1272ba95c745SQuentin Monnet int fd, err; 12739cce5313SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, test_attr); 1274ba95c745SQuentin Monnet 1275ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1276ba95c745SQuentin Monnet return -1; 1277ba95c745SQuentin Monnet 1278ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1279ba95c745SQuentin Monnet if (fd < 0) 1280ba95c745SQuentin Monnet return -1; 1281ba95c745SQuentin Monnet 1282ba95c745SQuentin Monnet while (argc) { 1283ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1284ba95c745SQuentin Monnet "data_size_out", NULL)) 1285ba95c745SQuentin Monnet return -1; 1286ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1287ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1288ba95c745SQuentin Monnet return -1; 1289ba95c745SQuentin Monnet 1290ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1291ba95c745SQuentin Monnet NEXT_ARG(); 1292ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1293ba95c745SQuentin Monnet return -1; 1294ba95c745SQuentin Monnet 1295ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1296ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1297ba95c745SQuentin Monnet return -1; 1298ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1299ba95c745SQuentin Monnet NEXT_ARG(); 1300ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1301ba95c745SQuentin Monnet return -1; 1302ba95c745SQuentin Monnet 1303ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1304ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1305ba95c745SQuentin Monnet char *endptr; 1306ba95c745SQuentin Monnet 1307ba95c745SQuentin Monnet NEXT_ARG(); 1308ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1309ba95c745SQuentin Monnet return -1; 1310ba95c745SQuentin Monnet 1311ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1312ba95c745SQuentin Monnet if (*endptr) { 1313ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1314ba95c745SQuentin Monnet *argv); 1315ba95c745SQuentin Monnet return -1; 1316ba95c745SQuentin Monnet } 1317ba95c745SQuentin Monnet NEXT_ARG(); 1318ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1319ba95c745SQuentin Monnet NEXT_ARG(); 1320ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1321ba95c745SQuentin Monnet return -1; 1322ba95c745SQuentin Monnet 1323ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1324ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1325ba95c745SQuentin Monnet return -1; 1326ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1327ba95c745SQuentin Monnet NEXT_ARG(); 1328ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1329ba95c745SQuentin Monnet return -1; 1330ba95c745SQuentin Monnet 1331ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1332ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1333ba95c745SQuentin Monnet char *endptr; 1334ba95c745SQuentin Monnet 1335ba95c745SQuentin Monnet NEXT_ARG(); 1336ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1337ba95c745SQuentin Monnet return -1; 1338ba95c745SQuentin Monnet 1339ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1340ba95c745SQuentin Monnet if (*endptr) { 1341ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1342ba95c745SQuentin Monnet *argv); 1343ba95c745SQuentin Monnet return -1; 1344ba95c745SQuentin Monnet } 1345ba95c745SQuentin Monnet NEXT_ARG(); 1346ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1347ba95c745SQuentin Monnet char *endptr; 1348ba95c745SQuentin Monnet 1349ba95c745SQuentin Monnet NEXT_ARG(); 1350ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1351ba95c745SQuentin Monnet return -1; 1352ba95c745SQuentin Monnet 1353ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1354ba95c745SQuentin Monnet if (*endptr) { 1355ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1356ba95c745SQuentin Monnet *argv); 1357ba95c745SQuentin Monnet return -1; 1358ba95c745SQuentin Monnet } 1359ba95c745SQuentin Monnet NEXT_ARG(); 1360ba95c745SQuentin Monnet } else { 1361ba95c745SQuentin Monnet p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1362ba95c745SQuentin Monnet *argv); 1363ba95c745SQuentin Monnet return -1; 1364ba95c745SQuentin Monnet } 1365ba95c745SQuentin Monnet } 1366ba95c745SQuentin Monnet 1367ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1368ba95c745SQuentin Monnet if (err) 1369ba95c745SQuentin Monnet return -1; 1370ba95c745SQuentin Monnet 1371ba95c745SQuentin Monnet if (data_in) { 1372ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1373ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1374ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1375ba95c745SQuentin Monnet if (err) 1376ba95c745SQuentin Monnet goto free_data_in; 1377ba95c745SQuentin Monnet } 1378ba95c745SQuentin Monnet 1379ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1380ba95c745SQuentin Monnet if (err) 1381ba95c745SQuentin Monnet goto free_data_out; 1382ba95c745SQuentin Monnet 1383ba95c745SQuentin Monnet if (ctx_in) { 1384ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1385ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1386ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1387ba95c745SQuentin Monnet if (err) 1388ba95c745SQuentin Monnet goto free_ctx_in; 1389ba95c745SQuentin Monnet } 1390ba95c745SQuentin Monnet 1391ba95c745SQuentin Monnet test_attr.repeat = repeat; 1392ba95c745SQuentin Monnet test_attr.data_in = data_in; 1393ba95c745SQuentin Monnet test_attr.data_out = data_out; 1394ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1395ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1396ba95c745SQuentin Monnet 13979cce5313SDelyan Kratunov err = bpf_prog_test_run_opts(fd, &test_attr); 1398ba95c745SQuentin Monnet if (err) { 1399ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1400ba95c745SQuentin Monnet goto free_ctx_out; 1401ba95c745SQuentin Monnet } 1402ba95c745SQuentin Monnet 1403ba95c745SQuentin Monnet err = 0; 1404ba95c745SQuentin Monnet 1405ba95c745SQuentin Monnet if (json_output) 1406ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1407ba95c745SQuentin Monnet 1408ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1409ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1410ba95c745SQuentin Monnet */ 1411ba95c745SQuentin Monnet if (test_attr.data_size_out) 1412ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1413ba95c745SQuentin Monnet test_attr.data_size_out, 1414ba95c745SQuentin Monnet data_fname_out, "data_out"); 1415ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1416ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1417ba95c745SQuentin Monnet test_attr.ctx_size_out, 1418ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1419ba95c745SQuentin Monnet 1420ba95c745SQuentin Monnet if (json_output) { 1421ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1422ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1423ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1424ba95c745SQuentin Monnet } else { 1425ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1426ba95c745SQuentin Monnet test_attr.retval, 1427ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1428ba95c745SQuentin Monnet } 1429ba95c745SQuentin Monnet 1430ba95c745SQuentin Monnet free_ctx_out: 1431ba95c745SQuentin Monnet free(ctx_out); 1432ba95c745SQuentin Monnet free_ctx_in: 1433ba95c745SQuentin Monnet free(ctx_in); 1434ba95c745SQuentin Monnet free_data_out: 1435ba95c745SQuentin Monnet free(data_out); 1436ba95c745SQuentin Monnet free_data_in: 1437ba95c745SQuentin Monnet free(data_in); 1438ba95c745SQuentin Monnet 1439ba95c745SQuentin Monnet return err; 1440ba95c745SQuentin Monnet } 1441ba95c745SQuentin Monnet 14426ae32b29SQuentin Monnet static int 14436ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14446ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14456ae32b29SQuentin Monnet { 14466ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14476ae32b29SQuentin Monnet int ret; 14486ae32b29SQuentin Monnet 14496ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14506ae32b29SQuentin Monnet if (!ret) 14516ae32b29SQuentin Monnet return ret; 14526ae32b29SQuentin Monnet 14536ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14546ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14556ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14566ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14576ae32b29SQuentin Monnet 14586ae32b29SQuentin Monnet return ret; 14596ae32b29SQuentin Monnet } 14606ae32b29SQuentin Monnet 146119526e70SWang Yufen static int 146219526e70SWang Yufen auto_attach_program(struct bpf_program *prog, const char *path) 146319526e70SWang Yufen { 146419526e70SWang Yufen struct bpf_link *link; 146519526e70SWang Yufen int err; 146619526e70SWang Yufen 146719526e70SWang Yufen link = bpf_program__attach(prog); 146819526e70SWang Yufen if (!link) { 146919526e70SWang Yufen p_info("Program %s does not support autoattach, falling back to pinning", 147019526e70SWang Yufen bpf_program__name(prog)); 147119526e70SWang Yufen return bpf_obj_pin(bpf_program__fd(prog), path); 147219526e70SWang Yufen } 147319526e70SWang Yufen 147419526e70SWang Yufen err = bpf_link__pin(link, path); 147519526e70SWang Yufen bpf_link__destroy(link); 147619526e70SWang Yufen return err; 147719526e70SWang Yufen } 147819526e70SWang Yufen 147919526e70SWang Yufen static int 148019526e70SWang Yufen auto_attach_programs(struct bpf_object *obj, const char *path) 148119526e70SWang Yufen { 148219526e70SWang Yufen struct bpf_program *prog; 148319526e70SWang Yufen char buf[PATH_MAX]; 148419526e70SWang Yufen int err; 148519526e70SWang Yufen 148619526e70SWang Yufen bpf_object__for_each_program(prog, obj) { 148719526e70SWang Yufen err = pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog)); 148819526e70SWang Yufen if (err) 148919526e70SWang Yufen goto err_unpin_programs; 149019526e70SWang Yufen 149119526e70SWang Yufen err = auto_attach_program(prog, buf); 149219526e70SWang Yufen if (err) 149319526e70SWang Yufen goto err_unpin_programs; 149419526e70SWang Yufen } 149519526e70SWang Yufen 149619526e70SWang Yufen return 0; 149719526e70SWang Yufen 149819526e70SWang Yufen err_unpin_programs: 149919526e70SWang Yufen while ((prog = bpf_object__prev_program(obj, prog))) { 150019526e70SWang Yufen if (pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog))) 150119526e70SWang Yufen continue; 150219526e70SWang Yufen 150319526e70SWang Yufen bpf_program__unpin(prog, buf); 150419526e70SWang Yufen } 150519526e70SWang Yufen 150619526e70SWang Yufen return err; 150719526e70SWang Yufen } 150819526e70SWang Yufen 150977380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 151049a086c2SRoman Gushchin { 151132e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1512e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1513e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1514e00aca65SAndrii Nakryiko ); 151555d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 15163ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 151777380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 15183ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 15193767a94bSStanislav Fomichev const char *pinmaps = NULL; 1520*f46392eeSLarysa Zaremba __u32 xdpmeta_ifindex = 0; 1521*f46392eeSLarysa Zaremba __u32 offload_ifindex = 0; 152219526e70SWang Yufen bool auto_attach = false; 152349a086c2SRoman Gushchin struct bpf_object *obj; 1524c8406848SJakub Kicinski struct bpf_map *map; 1525c8406848SJakub Kicinski const char *pinfile; 15263ff5a4dcSJakub Kicinski unsigned int i, j; 152732e3e58eSAndrii Nakryiko const char *file; 15283ff5a4dcSJakub Kicinski int idx, err; 152949a086c2SRoman Gushchin 153032e3e58eSAndrii Nakryiko 15318d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 15328d1fc3deSJakub Kicinski return -1; 153332e3e58eSAndrii Nakryiko file = GET_ARG(); 15348d1fc3deSJakub Kicinski pinfile = GET_ARG(); 153549a086c2SRoman Gushchin 1536ba6dd679SJakub Kicinski while (argc) { 153749f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 153849f2cba3SJakub Kicinski NEXT_ARG(); 153949f2cba3SJakub Kicinski 154032e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 154149f2cba3SJakub Kicinski p_err("program type already specified"); 15423ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 154349f2cba3SJakub Kicinski } 154449f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 15453ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 154649f2cba3SJakub Kicinski 1547314f14abSStanislav Fomichev err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1548314f14abSStanislav Fomichev &expected_attach_type); 1549314f14abSStanislav Fomichev if (err < 0) { 155049f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 1551314f14abSStanislav Fomichev char *type = malloc(strlen(*argv) + 2); 1552314f14abSStanislav Fomichev 155349f2cba3SJakub Kicinski if (!type) { 155449f2cba3SJakub Kicinski p_err("mem alloc failed"); 15553ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 155649f2cba3SJakub Kicinski } 155749f2cba3SJakub Kicinski *type = 0; 155849f2cba3SJakub Kicinski strcat(type, *argv); 155949f2cba3SJakub Kicinski strcat(type, "/"); 156049f2cba3SJakub Kicinski 15616ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1562c8406848SJakub Kicinski &expected_attach_type); 156349f2cba3SJakub Kicinski free(type); 1564c76e4c22STaeung Song if (err < 0) 15653ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1566314f14abSStanislav Fomichev } 1567c76e4c22STaeung Song 156849f2cba3SJakub Kicinski NEXT_ARG(); 15693ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1570dde7011aSJakub Kicinski void *new_map_replace; 15713ff5a4dcSJakub Kicinski char *endptr, *name; 15723ff5a4dcSJakub Kicinski int fd; 15733ff5a4dcSJakub Kicinski 15743ff5a4dcSJakub Kicinski NEXT_ARG(); 15753ff5a4dcSJakub Kicinski 15763ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 15773ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15783ff5a4dcSJakub Kicinski 15793ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 15803ff5a4dcSJakub Kicinski NEXT_ARG(); 15813ff5a4dcSJakub Kicinski 15823ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 15833ff5a4dcSJakub Kicinski if (*endptr) { 15843ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 15853ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15863ff5a4dcSJakub Kicinski } 15873ff5a4dcSJakub Kicinski name = NULL; 15883ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 15893ff5a4dcSJakub Kicinski NEXT_ARG(); 15903ff5a4dcSJakub Kicinski 15913ff5a4dcSJakub Kicinski name = *argv; 15923ff5a4dcSJakub Kicinski idx = -1; 15933ff5a4dcSJakub Kicinski } else { 15943ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 15953ff5a4dcSJakub Kicinski *argv); 15963ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15973ff5a4dcSJakub Kicinski } 15983ff5a4dcSJakub Kicinski NEXT_ARG(); 15993ff5a4dcSJakub Kicinski 16003ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 16013ff5a4dcSJakub Kicinski if (fd < 0) 16023ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16033ff5a4dcSJakub Kicinski 1604a19df713SMauricio Vásquez new_map_replace = libbpf_reallocarray(map_replace, 1605dde7011aSJakub Kicinski old_map_fds + 1, 16063ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1607dde7011aSJakub Kicinski if (!new_map_replace) { 16083ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 16093ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16103ff5a4dcSJakub Kicinski } 1611dde7011aSJakub Kicinski map_replace = new_map_replace; 1612dde7011aSJakub Kicinski 16133ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 16143ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 16153ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 16163ff5a4dcSJakub Kicinski old_map_fds++; 161749f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1618*f46392eeSLarysa Zaremba p_info("Warning: 'bpftool prog load [...] dev <ifname>' syntax is deprecated.\n" 1619*f46392eeSLarysa Zaremba "Going further, please use 'offload_dev <ifname>' to offload program to device.\n" 1620*f46392eeSLarysa Zaremba "For applications using XDP hints only, use 'xdpmeta_dev <ifname>'."); 1621*f46392eeSLarysa Zaremba goto offload_dev; 1622*f46392eeSLarysa Zaremba } else if (is_prefix(*argv, "offload_dev")) { 1623*f46392eeSLarysa Zaremba offload_dev: 1624ba6dd679SJakub Kicinski NEXT_ARG(); 1625ba6dd679SJakub Kicinski 1626*f46392eeSLarysa Zaremba if (offload_ifindex) { 1627*f46392eeSLarysa Zaremba p_err("offload_dev already specified"); 1628*f46392eeSLarysa Zaremba goto err_free_reuse_maps; 1629*f46392eeSLarysa Zaremba } else if (xdpmeta_ifindex) { 1630*f46392eeSLarysa Zaremba p_err("xdpmeta_dev and offload_dev are mutually exclusive"); 16313ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1632ba6dd679SJakub Kicinski } 1633ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 16343ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1635ba6dd679SJakub Kicinski 1636*f46392eeSLarysa Zaremba offload_ifindex = if_nametoindex(*argv); 1637*f46392eeSLarysa Zaremba if (!offload_ifindex) { 1638*f46392eeSLarysa Zaremba p_err("unrecognized netdevice '%s': %s", 1639*f46392eeSLarysa Zaremba *argv, strerror(errno)); 1640*f46392eeSLarysa Zaremba goto err_free_reuse_maps; 1641*f46392eeSLarysa Zaremba } 1642*f46392eeSLarysa Zaremba NEXT_ARG(); 1643*f46392eeSLarysa Zaremba } else if (is_prefix(*argv, "xdpmeta_dev")) { 1644*f46392eeSLarysa Zaremba NEXT_ARG(); 1645*f46392eeSLarysa Zaremba 1646*f46392eeSLarysa Zaremba if (xdpmeta_ifindex) { 1647*f46392eeSLarysa Zaremba p_err("xdpmeta_dev already specified"); 1648*f46392eeSLarysa Zaremba goto err_free_reuse_maps; 1649*f46392eeSLarysa Zaremba } else if (offload_ifindex) { 1650*f46392eeSLarysa Zaremba p_err("xdpmeta_dev and offload_dev are mutually exclusive"); 1651*f46392eeSLarysa Zaremba goto err_free_reuse_maps; 1652*f46392eeSLarysa Zaremba } 1653*f46392eeSLarysa Zaremba if (!REQ_ARGS(1)) 1654*f46392eeSLarysa Zaremba goto err_free_reuse_maps; 1655*f46392eeSLarysa Zaremba 1656*f46392eeSLarysa Zaremba xdpmeta_ifindex = if_nametoindex(*argv); 1657*f46392eeSLarysa Zaremba if (!xdpmeta_ifindex) { 1658ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1659ba6dd679SJakub Kicinski *argv, strerror(errno)); 16603ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1661ba6dd679SJakub Kicinski } 1662ba6dd679SJakub Kicinski NEXT_ARG(); 16633767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 16643767a94bSStanislav Fomichev NEXT_ARG(); 16653767a94bSStanislav Fomichev 16663767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 16673767a94bSStanislav Fomichev goto err_free_reuse_maps; 16683767a94bSStanislav Fomichev 16693767a94bSStanislav Fomichev pinmaps = GET_ARG(); 167019526e70SWang Yufen } else if (is_prefix(*argv, "autoattach")) { 167119526e70SWang Yufen auto_attach = true; 167219526e70SWang Yufen NEXT_ARG(); 1673ba6dd679SJakub Kicinski } else { 16743ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1675ba6dd679SJakub Kicinski *argv); 16763ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1677ba6dd679SJakub Kicinski } 1678ba6dd679SJakub Kicinski } 1679ba6dd679SJakub Kicinski 16806b4384ffSQuentin Monnet set_max_rlimit(); 16816b4384ffSQuentin Monnet 1682b59e4ce8SAndrii Nakryiko if (verifier_logs) 1683b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1684b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1685b59e4ce8SAndrii Nakryiko 168632e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1687d1313e01SSahid Orentino Ferdjaoui if (!obj) { 1688c8406848SJakub Kicinski p_err("failed to open object file"); 16893ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 169049a086c2SRoman Gushchin } 169149a086c2SRoman Gushchin 169277380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 169332e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1694c8406848SJakub Kicinski 169532e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1696fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1697c8406848SJakub Kicinski 16986ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1699c8406848SJakub Kicinski &expected_attach_type); 1700c76e4c22STaeung Song if (err < 0) 1701c8406848SJakub Kicinski goto err_close_obj; 1702c8406848SJakub Kicinski } 170377380998SStanislav Fomichev 1704*f46392eeSLarysa Zaremba if (prog_type == BPF_PROG_TYPE_XDP && xdpmeta_ifindex) { 1705*f46392eeSLarysa Zaremba bpf_program__set_flags(pos, BPF_F_XDP_DEV_BOUND_ONLY); 1706*f46392eeSLarysa Zaremba bpf_program__set_ifindex(pos, xdpmeta_ifindex); 1707*f46392eeSLarysa Zaremba } else { 1708*f46392eeSLarysa Zaremba bpf_program__set_ifindex(pos, offload_ifindex); 1709*f46392eeSLarysa Zaremba } 1710b24f0b04SWei Yongjun if (bpf_program__type(pos) != prog_type) 171177380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 171277380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 171377380998SStanislav Fomichev } 1714c8406848SJakub Kicinski 17153ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 17163ff5a4dcSJakub Kicinski map_replace_compar); 17173ff5a4dcSJakub Kicinski 17183ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 17193ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 17203ff5a4dcSJakub Kicinski */ 17213ff5a4dcSJakub Kicinski j = 0; 17223ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 17233ff5a4dcSJakub Kicinski i = 0; 1724f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 17253ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 17263ff5a4dcSJakub Kicinski map_replace[j].idx = i; 17273ff5a4dcSJakub Kicinski break; 17283ff5a4dcSJakub Kicinski } 17293ff5a4dcSJakub Kicinski i++; 17303ff5a4dcSJakub Kicinski } 17313ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 17323ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 17333ff5a4dcSJakub Kicinski goto err_close_obj; 17343ff5a4dcSJakub Kicinski } 17353ff5a4dcSJakub Kicinski j++; 17363ff5a4dcSJakub Kicinski } 17373ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 17383ff5a4dcSJakub Kicinski if (j) 17393ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 17403ff5a4dcSJakub Kicinski map_replace_compar); 17413ff5a4dcSJakub Kicinski 17423ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 17433ff5a4dcSJakub Kicinski j = 0; 17443ff5a4dcSJakub Kicinski idx = 0; 1745f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 17469855c131SChristy Lee if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1747*f46392eeSLarysa Zaremba bpf_map__set_ifindex(map, offload_ifindex); 1748c8406848SJakub Kicinski 17493ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 17503ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 17513ff5a4dcSJakub Kicinski if (err) { 17523ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 17533ff5a4dcSJakub Kicinski goto err_close_obj; 17543ff5a4dcSJakub Kicinski } 17553ff5a4dcSJakub Kicinski 17563ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 17573ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 17583ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 17593ff5a4dcSJakub Kicinski idx); 17603ff5a4dcSJakub Kicinski goto err_close_obj; 17613ff5a4dcSJakub Kicinski } 17623ff5a4dcSJakub Kicinski } 17633ff5a4dcSJakub Kicinski 17643ff5a4dcSJakub Kicinski idx++; 17653ff5a4dcSJakub Kicinski } 17663ff5a4dcSJakub Kicinski if (j < old_map_fds) { 17673ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 17683ff5a4dcSJakub Kicinski goto err_close_obj; 17693ff5a4dcSJakub Kicinski } 17703ff5a4dcSJakub Kicinski 1771b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1772c8406848SJakub Kicinski if (err) { 1773c8406848SJakub Kicinski p_err("failed to load object file"); 1774c8406848SJakub Kicinski goto err_close_obj; 1775c8406848SJakub Kicinski } 1776c8406848SJakub Kicinski 17772a36c26fSPengcheng Yang err = mount_bpffs_for_pin(pinfile, !first_prog_only); 177877380998SStanislav Fomichev if (err) 1779bfee71fbSJakub Kicinski goto err_close_obj; 178049a086c2SRoman Gushchin 178177380998SStanislav Fomichev if (first_prog_only) { 17826f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 178377380998SStanislav Fomichev if (!prog) { 178477380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 178577380998SStanislav Fomichev goto err_close_obj; 178677380998SStanislav Fomichev } 178777380998SStanislav Fomichev 178819526e70SWang Yufen if (auto_attach) 178919526e70SWang Yufen err = auto_attach_program(prog, pinfile); 179019526e70SWang Yufen else 179177380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 179277380998SStanislav Fomichev if (err) { 179377380998SStanislav Fomichev p_err("failed to pin program %s", 1794fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 179577380998SStanislav Fomichev goto err_close_obj; 179677380998SStanislav Fomichev } 179777380998SStanislav Fomichev } else { 179819526e70SWang Yufen if (auto_attach) 179919526e70SWang Yufen err = auto_attach_programs(obj, pinfile); 180019526e70SWang Yufen else 180177380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 180277380998SStanislav Fomichev if (err) { 180377380998SStanislav Fomichev p_err("failed to pin all programs"); 180477380998SStanislav Fomichev goto err_close_obj; 180577380998SStanislav Fomichev } 180677380998SStanislav Fomichev } 180777380998SStanislav Fomichev 18083767a94bSStanislav Fomichev if (pinmaps) { 18093767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 18103767a94bSStanislav Fomichev if (err) { 18113767a94bSStanislav Fomichev p_err("failed to pin all maps"); 18123767a94bSStanislav Fomichev goto err_unpin; 18133767a94bSStanislav Fomichev } 18143767a94bSStanislav Fomichev } 18153767a94bSStanislav Fomichev 181649a086c2SRoman Gushchin if (json_output) 181749a086c2SRoman Gushchin jsonw_null(json_wtr); 181849a086c2SRoman Gushchin 1819bfee71fbSJakub Kicinski bpf_object__close(obj); 18203ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 18213ff5a4dcSJakub Kicinski close(map_replace[i].fd); 18223ff5a4dcSJakub Kicinski free(map_replace); 1823bfee71fbSJakub Kicinski 182449a086c2SRoman Gushchin return 0; 1825bfee71fbSJakub Kicinski 18263767a94bSStanislav Fomichev err_unpin: 18273767a94bSStanislav Fomichev if (first_prog_only) 18283767a94bSStanislav Fomichev unlink(pinfile); 18293767a94bSStanislav Fomichev else 18303767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1831bfee71fbSJakub Kicinski err_close_obj: 1832bfee71fbSJakub Kicinski bpf_object__close(obj); 18333ff5a4dcSJakub Kicinski err_free_reuse_maps: 18343ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 18353ff5a4dcSJakub Kicinski close(map_replace[i].fd); 18363ff5a4dcSJakub Kicinski free(map_replace); 1837bfee71fbSJakub Kicinski return -1; 183849a086c2SRoman Gushchin } 183949a086c2SRoman Gushchin 1840d510296dSAlexei Starovoitov static int count_open_fds(void) 1841d510296dSAlexei Starovoitov { 1842d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1843d510296dSAlexei Starovoitov struct dirent *de; 1844d510296dSAlexei Starovoitov int cnt = -3; 1845d510296dSAlexei Starovoitov 1846d510296dSAlexei Starovoitov if (!dp) 1847d510296dSAlexei Starovoitov return -1; 1848d510296dSAlexei Starovoitov 1849d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1850d510296dSAlexei Starovoitov cnt++; 1851d510296dSAlexei Starovoitov 1852d510296dSAlexei Starovoitov closedir(dp); 1853d510296dSAlexei Starovoitov return cnt; 1854d510296dSAlexei Starovoitov } 1855d510296dSAlexei Starovoitov 1856d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1857d510296dSAlexei Starovoitov { 1858d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1859d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1860d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1861d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1862d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1863d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1864942df4dcSAlexei Starovoitov char *log_buf = NULL; 1865d510296dSAlexei Starovoitov 1866d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1867d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1868d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1869942df4dcSAlexei Starovoitov if (verifier_logs) { 1870942df4dcSAlexei Starovoitov ctx->log_level = 1 + 2 + 4; 1871d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1872d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1873d510296dSAlexei Starovoitov if (!log_buf) 1874d510296dSAlexei Starovoitov return -ENOMEM; 1875d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1876942df4dcSAlexei Starovoitov } 1877d510296dSAlexei Starovoitov opts.ctx = ctx; 1878d510296dSAlexei Starovoitov opts.data = gen->data; 1879d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1880d510296dSAlexei Starovoitov opts.insns = gen->insns; 1881d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1882d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1883d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1884d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1885942df4dcSAlexei Starovoitov if (err < 0 || verifier_logs) { 1886d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1887942df4dcSAlexei Starovoitov if (fd_delta && err < 0) 1888d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1889d510296dSAlexei Starovoitov fd_delta); 1890d510296dSAlexei Starovoitov } 1891d510296dSAlexei Starovoitov free(log_buf); 1892d510296dSAlexei Starovoitov return err; 1893d510296dSAlexei Starovoitov } 1894d510296dSAlexei Starovoitov 1895d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1896d510296dSAlexei Starovoitov { 1897d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1898d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1899d510296dSAlexei Starovoitov struct bpf_object *obj; 1900d510296dSAlexei Starovoitov const char *file; 1901d510296dSAlexei Starovoitov int err = 0; 1902d510296dSAlexei Starovoitov 1903d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1904d510296dSAlexei Starovoitov return -1; 1905d510296dSAlexei Starovoitov file = GET_ARG(); 1906d510296dSAlexei Starovoitov 1907b59e4ce8SAndrii Nakryiko if (verifier_logs) 1908b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1909b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1910b59e4ce8SAndrii Nakryiko 1911d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1912d1313e01SSahid Orentino Ferdjaoui if (!obj) { 1913d510296dSAlexei Starovoitov p_err("failed to open object file"); 1914d510296dSAlexei Starovoitov goto err_close_obj; 1915d510296dSAlexei Starovoitov } 1916d510296dSAlexei Starovoitov 1917d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1918d510296dSAlexei Starovoitov if (err) 1919d510296dSAlexei Starovoitov goto err_close_obj; 1920d510296dSAlexei Starovoitov 1921b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1922d510296dSAlexei Starovoitov if (err) { 1923d510296dSAlexei Starovoitov p_err("failed to load object file"); 1924d510296dSAlexei Starovoitov goto err_close_obj; 1925d510296dSAlexei Starovoitov } 1926d510296dSAlexei Starovoitov 1927d510296dSAlexei Starovoitov if (verifier_logs) { 1928d510296dSAlexei Starovoitov struct dump_data dd = {}; 1929d510296dSAlexei Starovoitov 1930d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1931d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1932d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1933d510296dSAlexei Starovoitov } 1934d510296dSAlexei Starovoitov err = try_loader(&gen); 1935d510296dSAlexei Starovoitov err_close_obj: 1936d510296dSAlexei Starovoitov bpf_object__close(obj); 1937d510296dSAlexei Starovoitov return err; 1938d510296dSAlexei Starovoitov } 1939d510296dSAlexei Starovoitov 194077380998SStanislav Fomichev static int do_load(int argc, char **argv) 194177380998SStanislav Fomichev { 1942d510296dSAlexei Starovoitov if (use_loader) 1943d510296dSAlexei Starovoitov return do_loader(argc, argv); 194477380998SStanislav Fomichev return load_with_options(argc, argv, true); 194577380998SStanislav Fomichev } 194677380998SStanislav Fomichev 194777380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 194877380998SStanislav Fomichev { 194977380998SStanislav Fomichev return load_with_options(argc, argv, false); 195077380998SStanislav Fomichev } 195177380998SStanislav Fomichev 195247c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 195347c09d6aSSong Liu 195447c09d6aSSong Liu static int do_profile(int argc, char **argv) 195547c09d6aSSong Liu { 195614e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 195747c09d6aSSong Liu return 0; 195847c09d6aSSong Liu } 195947c09d6aSSong Liu 196047c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 196147c09d6aSSong Liu 196247c09d6aSSong Liu #include "profiler.skel.h" 196347c09d6aSSong Liu 196447c09d6aSSong Liu struct profile_metric { 196547c09d6aSSong Liu const char *name; 196647c09d6aSSong Liu struct bpf_perf_event_value val; 196747c09d6aSSong Liu struct perf_event_attr attr; 196847c09d6aSSong Liu bool selected; 196947c09d6aSSong Liu 197047c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 197147c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 197247c09d6aSSong Liu const char *ratio_desc; 197347c09d6aSSong Liu const float ratio_mul; 197447c09d6aSSong Liu } metrics[] = { 197547c09d6aSSong Liu { 197647c09d6aSSong Liu .name = "cycles", 197747c09d6aSSong Liu .attr = { 197847c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 197947c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 198047c09d6aSSong Liu .exclude_user = 1, 198147c09d6aSSong Liu }, 198247c09d6aSSong Liu }, 198347c09d6aSSong Liu { 198447c09d6aSSong Liu .name = "instructions", 198547c09d6aSSong Liu .attr = { 198647c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 198747c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 198847c09d6aSSong Liu .exclude_user = 1, 198947c09d6aSSong Liu }, 199047c09d6aSSong Liu .ratio_metric = 1, 199147c09d6aSSong Liu .ratio_desc = "insns per cycle", 199247c09d6aSSong Liu .ratio_mul = 1.0, 199347c09d6aSSong Liu }, 199447c09d6aSSong Liu { 199547c09d6aSSong Liu .name = "l1d_loads", 199647c09d6aSSong Liu .attr = { 199747c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 199847c09d6aSSong Liu .config = 199947c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 200047c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 200147c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 200247c09d6aSSong Liu .exclude_user = 1, 200347c09d6aSSong Liu }, 200447c09d6aSSong Liu }, 200547c09d6aSSong Liu { 200647c09d6aSSong Liu .name = "llc_misses", 200747c09d6aSSong Liu .attr = { 200847c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 200947c09d6aSSong Liu .config = 201047c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 201147c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 201247c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 201347c09d6aSSong Liu .exclude_user = 1 201447c09d6aSSong Liu }, 201547c09d6aSSong Liu .ratio_metric = 2, 201647c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 201747c09d6aSSong Liu .ratio_mul = 1e6, 201847c09d6aSSong Liu }, 2019450d060eSYonghong Song { 2020450d060eSYonghong Song .name = "itlb_misses", 2021450d060eSYonghong Song .attr = { 2022450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 2023450d060eSYonghong Song .config = 2024450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 2025450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2026450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 2027450d060eSYonghong Song .exclude_user = 1 2028450d060eSYonghong Song }, 2029450d060eSYonghong Song .ratio_metric = 2, 2030450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 2031450d060eSYonghong Song .ratio_mul = 1e6, 2032450d060eSYonghong Song }, 2033450d060eSYonghong Song { 2034450d060eSYonghong Song .name = "dtlb_misses", 2035450d060eSYonghong Song .attr = { 2036450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 2037450d060eSYonghong Song .config = 2038450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 2039450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2040450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 2041450d060eSYonghong Song .exclude_user = 1 2042450d060eSYonghong Song }, 2043450d060eSYonghong Song .ratio_metric = 2, 2044450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 2045450d060eSYonghong Song .ratio_mul = 1e6, 2046450d060eSYonghong Song }, 204747c09d6aSSong Liu }; 204847c09d6aSSong Liu 204947c09d6aSSong Liu static __u64 profile_total_count; 205047c09d6aSSong Liu 205147c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 205247c09d6aSSong Liu 205347c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 205447c09d6aSSong Liu { 205547c09d6aSSong Liu unsigned int metric_cnt; 205647c09d6aSSong Liu int selected_cnt = 0; 205747c09d6aSSong Liu unsigned int i; 205847c09d6aSSong Liu 20595eff8c18SRongguang Wei metric_cnt = ARRAY_SIZE(metrics); 206047c09d6aSSong Liu 206147c09d6aSSong Liu while (argc > 0) { 206247c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 206347c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 206447c09d6aSSong Liu if (!metrics[i].selected) 206547c09d6aSSong Liu selected_cnt++; 206647c09d6aSSong Liu metrics[i].selected = true; 206747c09d6aSSong Liu break; 206847c09d6aSSong Liu } 206947c09d6aSSong Liu } 207047c09d6aSSong Liu if (i == metric_cnt) { 207147c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 207247c09d6aSSong Liu return -1; 207347c09d6aSSong Liu } 207447c09d6aSSong Liu NEXT_ARG(); 207547c09d6aSSong Liu } 207647c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 207747c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 207847c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 207947c09d6aSSong Liu return -1; 208047c09d6aSSong Liu } 208147c09d6aSSong Liu return selected_cnt; 208247c09d6aSSong Liu } 208347c09d6aSSong Liu 208447c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 208547c09d6aSSong Liu { 208647c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 208747c09d6aSSong Liu int reading_map_fd, count_map_fd; 208847c09d6aSSong Liu __u64 counts[num_cpu]; 208947c09d6aSSong Liu __u32 key = 0; 209047c09d6aSSong Liu int err; 209147c09d6aSSong Liu 209247c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 209347c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 209447c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 209547c09d6aSSong Liu p_err("failed to get fd for map"); 209647c09d6aSSong Liu return; 209747c09d6aSSong Liu } 209847c09d6aSSong Liu 209947c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 210047c09d6aSSong Liu if (err) { 210147c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 210247c09d6aSSong Liu return; 210347c09d6aSSong Liu } 210447c09d6aSSong Liu 210547c09d6aSSong Liu profile_total_count = 0; 210647c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 210747c09d6aSSong Liu profile_total_count += counts[cpu]; 210847c09d6aSSong Liu 210947c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 211047c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 211147c09d6aSSong Liu 211247c09d6aSSong Liu if (!metrics[m].selected) 211347c09d6aSSong Liu continue; 211447c09d6aSSong Liu 211547c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 211647c09d6aSSong Liu if (err) { 211747c09d6aSSong Liu p_err("failed to read reading_map: %s", 211847c09d6aSSong Liu strerror(errno)); 211947c09d6aSSong Liu return; 212047c09d6aSSong Liu } 212147c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 212247c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 212347c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 212447c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 212547c09d6aSSong Liu } 212647c09d6aSSong Liu key++; 212747c09d6aSSong Liu } 212847c09d6aSSong Liu } 212947c09d6aSSong Liu 213047c09d6aSSong Liu static void profile_print_readings_json(void) 213147c09d6aSSong Liu { 213247c09d6aSSong Liu __u32 m; 213347c09d6aSSong Liu 213447c09d6aSSong Liu jsonw_start_array(json_wtr); 213547c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 213647c09d6aSSong Liu if (!metrics[m].selected) 213747c09d6aSSong Liu continue; 213847c09d6aSSong Liu jsonw_start_object(json_wtr); 213947c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 214047c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 214147c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 214247c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 214347c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 214447c09d6aSSong Liu 214547c09d6aSSong Liu jsonw_end_object(json_wtr); 214647c09d6aSSong Liu } 214747c09d6aSSong Liu jsonw_end_array(json_wtr); 214847c09d6aSSong Liu } 214947c09d6aSSong Liu 215047c09d6aSSong Liu static void profile_print_readings_plain(void) 215147c09d6aSSong Liu { 215247c09d6aSSong Liu __u32 m; 215347c09d6aSSong Liu 215447c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 215547c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 215647c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 215747c09d6aSSong Liu int r; 215847c09d6aSSong Liu 215947c09d6aSSong Liu if (!metrics[m].selected) 216047c09d6aSSong Liu continue; 216147c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 216247c09d6aSSong Liu 216347c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 216447c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 216547c09d6aSSong Liu metrics[r].val.counter > 0) { 216647c09d6aSSong Liu printf("# %8.2f %-30s", 216747c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 216847c09d6aSSong Liu metrics[r].val.counter, 216947c09d6aSSong Liu metrics[m].ratio_desc); 217047c09d6aSSong Liu } else { 217147c09d6aSSong Liu printf("%-41s", ""); 217247c09d6aSSong Liu } 217347c09d6aSSong Liu 217447c09d6aSSong Liu if (val->enabled > val->running) 217547c09d6aSSong Liu printf("(%4.2f%%)", 217647c09d6aSSong Liu val->running * 100.0 / val->enabled); 217747c09d6aSSong Liu printf("\n"); 217847c09d6aSSong Liu } 217947c09d6aSSong Liu } 218047c09d6aSSong Liu 218147c09d6aSSong Liu static void profile_print_readings(void) 218247c09d6aSSong Liu { 218347c09d6aSSong Liu if (json_output) 218447c09d6aSSong Liu profile_print_readings_json(); 218547c09d6aSSong Liu else 218647c09d6aSSong Liu profile_print_readings_plain(); 218747c09d6aSSong Liu } 218847c09d6aSSong Liu 218947c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 219047c09d6aSSong Liu { 2191c59765cfSDave Marchevsky struct bpf_func_info func_info; 2192c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2193c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 219447c09d6aSSong Liu const struct btf_type *t; 2195c59765cfSDave Marchevsky __u32 func_info_rec_size; 2196369e955bSQuentin Monnet struct btf *btf = NULL; 219747c09d6aSSong Liu char *name = NULL; 2198c59765cfSDave Marchevsky int err; 219947c09d6aSSong Liu 220038f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len); 2201c59765cfSDave Marchevsky if (err) { 220238f0408eSIlya Leoshkevich p_err("failed to get info for prog FD %d", tgt_fd); 2203c59765cfSDave Marchevsky goto out; 220447c09d6aSSong Liu } 220547c09d6aSSong Liu 2206c59765cfSDave Marchevsky if (info.btf_id == 0) { 220747c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 220847c09d6aSSong Liu goto out; 220947c09d6aSSong Liu } 221047c09d6aSSong Liu 2211c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2212c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 221338f0408eSIlya Leoshkevich p_err("found 0 func_info for prog FD %d", tgt_fd); 2214c59765cfSDave Marchevsky goto out; 2215c59765cfSDave Marchevsky } 2216c59765cfSDave Marchevsky 2217c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2218c59765cfSDave Marchevsky info.nr_func_info = 1; 2219c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2220c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2221c59765cfSDave Marchevsky 222238f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len); 2223c59765cfSDave Marchevsky if (err) { 2224c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2225c59765cfSDave Marchevsky goto out; 2226c59765cfSDave Marchevsky } 2227c59765cfSDave Marchevsky 2228c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 2229d1313e01SSahid Orentino Ferdjaoui if (!btf) { 223086f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 223186f4b7f2SQuentin Monnet goto out; 223286f4b7f2SQuentin Monnet } 223386f4b7f2SQuentin Monnet 2234c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 223547c09d6aSSong Liu if (!t) { 223647c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2237c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 223847c09d6aSSong Liu goto out; 223947c09d6aSSong Liu } 224047c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 224147c09d6aSSong Liu out: 2242369e955bSQuentin Monnet btf__free(btf); 224347c09d6aSSong Liu return name; 224447c09d6aSSong Liu } 224547c09d6aSSong Liu 224647c09d6aSSong Liu static struct profiler_bpf *profile_obj; 224747c09d6aSSong Liu static int profile_tgt_fd = -1; 224847c09d6aSSong Liu static char *profile_tgt_name; 224947c09d6aSSong Liu static int *profile_perf_events; 225047c09d6aSSong Liu static int profile_perf_event_cnt; 225147c09d6aSSong Liu 225247c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 225347c09d6aSSong Liu { 225447c09d6aSSong Liu int i; 225547c09d6aSSong Liu 225647c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 225747c09d6aSSong Liu close(profile_perf_events[i]); 225847c09d6aSSong Liu 225947c09d6aSSong Liu free(profile_perf_events); 226047c09d6aSSong Liu profile_perf_event_cnt = 0; 226147c09d6aSSong Liu } 226247c09d6aSSong Liu 2263377c16faSTonghao Zhang static int profile_open_perf_event(int mid, int cpu, int map_fd) 2264377c16faSTonghao Zhang { 2265377c16faSTonghao Zhang int pmu_fd; 2266377c16faSTonghao Zhang 2267377c16faSTonghao Zhang pmu_fd = syscall(__NR_perf_event_open, &metrics[mid].attr, 2268377c16faSTonghao Zhang -1 /*pid*/, cpu, -1 /*group_fd*/, 0); 2269377c16faSTonghao Zhang if (pmu_fd < 0) { 2270377c16faSTonghao Zhang if (errno == ENODEV) { 2271377c16faSTonghao Zhang p_info("cpu %d may be offline, skip %s profiling.", 2272377c16faSTonghao Zhang cpu, metrics[mid].name); 2273377c16faSTonghao Zhang profile_perf_event_cnt++; 2274377c16faSTonghao Zhang return 0; 2275377c16faSTonghao Zhang } 2276377c16faSTonghao Zhang return -1; 2277377c16faSTonghao Zhang } 2278377c16faSTonghao Zhang 2279377c16faSTonghao Zhang if (bpf_map_update_elem(map_fd, 2280377c16faSTonghao Zhang &profile_perf_event_cnt, 2281377c16faSTonghao Zhang &pmu_fd, BPF_ANY) || 2282377c16faSTonghao Zhang ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 2283377c16faSTonghao Zhang close(pmu_fd); 2284377c16faSTonghao Zhang return -1; 2285377c16faSTonghao Zhang } 2286377c16faSTonghao Zhang 2287377c16faSTonghao Zhang profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 2288377c16faSTonghao Zhang return 0; 2289377c16faSTonghao Zhang } 2290377c16faSTonghao Zhang 229147c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 229247c09d6aSSong Liu { 229347c09d6aSSong Liu unsigned int cpu, m; 2294377c16faSTonghao Zhang int map_fd; 229547c09d6aSSong Liu 229647c09d6aSSong Liu profile_perf_events = calloc( 229747c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 229847c09d6aSSong Liu if (!profile_perf_events) { 229947c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 230047c09d6aSSong Liu strerror(errno)); 230147c09d6aSSong Liu return -1; 230247c09d6aSSong Liu } 230347c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 230447c09d6aSSong Liu if (map_fd < 0) { 230547c09d6aSSong Liu p_err("failed to get fd for events map"); 230647c09d6aSSong Liu return -1; 230747c09d6aSSong Liu } 230847c09d6aSSong Liu 230947c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 231047c09d6aSSong Liu if (!metrics[m].selected) 231147c09d6aSSong Liu continue; 231247c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 2313377c16faSTonghao Zhang if (profile_open_perf_event(m, cpu, map_fd)) { 231447c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 231547c09d6aSSong Liu metrics[m].name, cpu); 231647c09d6aSSong Liu return -1; 231747c09d6aSSong Liu } 231847c09d6aSSong Liu } 231947c09d6aSSong Liu } 232047c09d6aSSong Liu return 0; 232147c09d6aSSong Liu } 232247c09d6aSSong Liu 232347c09d6aSSong Liu static void profile_print_and_cleanup(void) 232447c09d6aSSong Liu { 232547c09d6aSSong Liu profile_close_perf_events(profile_obj); 232647c09d6aSSong Liu profile_read_values(profile_obj); 232747c09d6aSSong Liu profile_print_readings(); 232847c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 232947c09d6aSSong Liu 233047c09d6aSSong Liu close(profile_tgt_fd); 233147c09d6aSSong Liu free(profile_tgt_name); 233247c09d6aSSong Liu } 233347c09d6aSSong Liu 233447c09d6aSSong Liu static void int_exit(int signo) 233547c09d6aSSong Liu { 233647c09d6aSSong Liu profile_print_and_cleanup(); 233747c09d6aSSong Liu exit(0); 233847c09d6aSSong Liu } 233947c09d6aSSong Liu 234047c09d6aSSong Liu static int do_profile(int argc, char **argv) 234147c09d6aSSong Liu { 234247c09d6aSSong Liu int num_metric, num_cpu, err = -1; 234347c09d6aSSong Liu struct bpf_program *prog; 234447c09d6aSSong Liu unsigned long duration; 234547c09d6aSSong Liu char *endptr; 234647c09d6aSSong Liu 234747c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 234847c09d6aSSong Liu if (!REQ_ARGS(3)) 234947c09d6aSSong Liu return -EINVAL; 235047c09d6aSSong Liu 235147c09d6aSSong Liu /* parse target fd */ 235247c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 235347c09d6aSSong Liu if (profile_tgt_fd < 0) { 235447c09d6aSSong Liu p_err("failed to parse fd"); 235547c09d6aSSong Liu return -1; 235647c09d6aSSong Liu } 235747c09d6aSSong Liu 235847c09d6aSSong Liu /* parse profiling optional duration */ 235947c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 236047c09d6aSSong Liu NEXT_ARG(); 236147c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 236247c09d6aSSong Liu if (*endptr) 236347c09d6aSSong Liu usage(); 236447c09d6aSSong Liu NEXT_ARG(); 236547c09d6aSSong Liu } else { 236647c09d6aSSong Liu duration = UINT_MAX; 236747c09d6aSSong Liu } 236847c09d6aSSong Liu 236947c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 237047c09d6aSSong Liu if (num_metric <= 0) 237147c09d6aSSong Liu goto out; 237247c09d6aSSong Liu 237347c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 237447c09d6aSSong Liu if (num_cpu <= 0) { 237547c09d6aSSong Liu p_err("failed to identify number of CPUs"); 237647c09d6aSSong Liu goto out; 237747c09d6aSSong Liu } 237847c09d6aSSong Liu 237947c09d6aSSong Liu profile_obj = profiler_bpf__open(); 238047c09d6aSSong Liu if (!profile_obj) { 238147c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 238247c09d6aSSong Liu goto out; 238347c09d6aSSong Liu } 238447c09d6aSSong Liu 238547c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 238647c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 238747c09d6aSSong Liu 238847c09d6aSSong Liu /* adjust map sizes */ 238939748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu); 239039748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric); 239139748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric); 239239748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.counts, 1); 239347c09d6aSSong Liu 239447c09d6aSSong Liu /* change target name */ 239547c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 239647c09d6aSSong Liu if (!profile_tgt_name) 239747c09d6aSSong Liu goto out; 239847c09d6aSSong Liu 239947c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 240047c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 240147c09d6aSSong Liu profile_tgt_name); 240247c09d6aSSong Liu if (err) { 240347c09d6aSSong Liu p_err("failed to set attach target\n"); 240447c09d6aSSong Liu goto out; 240547c09d6aSSong Liu } 240647c09d6aSSong Liu } 240747c09d6aSSong Liu 24086b4384ffSQuentin Monnet set_max_rlimit(); 240947c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 241047c09d6aSSong Liu if (err) { 241147c09d6aSSong Liu p_err("failed to load profile_obj"); 241247c09d6aSSong Liu goto out; 241347c09d6aSSong Liu } 241447c09d6aSSong Liu 241547c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 241647c09d6aSSong Liu if (err) 241747c09d6aSSong Liu goto out; 241847c09d6aSSong Liu 241947c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 242047c09d6aSSong Liu if (err) { 242147c09d6aSSong Liu p_err("failed to attach profile_obj"); 242247c09d6aSSong Liu goto out; 242347c09d6aSSong Liu } 242447c09d6aSSong Liu signal(SIGINT, int_exit); 242547c09d6aSSong Liu 242647c09d6aSSong Liu sleep(duration); 242747c09d6aSSong Liu profile_print_and_cleanup(); 242847c09d6aSSong Liu return 0; 242947c09d6aSSong Liu 243047c09d6aSSong Liu out: 243147c09d6aSSong Liu profile_close_perf_events(profile_obj); 243247c09d6aSSong Liu if (profile_obj) 243347c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 243447c09d6aSSong Liu close(profile_tgt_fd); 243547c09d6aSSong Liu free(profile_tgt_name); 243647c09d6aSSong Liu return err; 243747c09d6aSSong Liu } 243847c09d6aSSong Liu 243947c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 244047c09d6aSSong Liu 244171bb428fSJakub Kicinski static int do_help(int argc, char **argv) 244271bb428fSJakub Kicinski { 2443004b45c0SQuentin Monnet if (json_output) { 2444004b45c0SQuentin Monnet jsonw_null(json_wtr); 2445004b45c0SQuentin Monnet return 0; 2446004b45c0SQuentin Monnet } 2447004b45c0SQuentin Monnet 244871bb428fSJakub Kicinski fprintf(stderr, 244990040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 24509b79f027SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | [opcodes] [linum] [visual] }]\n" 24519b79f027SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | [opcodes] [linum] }]\n" 245290040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 245390040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 2454*f46392eeSLarysa Zaremba " [type TYPE] [{ offload_dev | xdpmeta_dev } NAME] \\\n" 24553767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 24563767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 245719526e70SWang Yufen " [autoattach]\n" 245890040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 245990040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 246090040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2461ba95c745SQuentin Monnet " data_in FILE \\\n" 2462ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2463ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2464ba95c745SQuentin Monnet " [repeat N]\n" 246590040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 246690040351SQuentin Monnet " %1$s %2$s tracelog\n" 246790040351SQuentin Monnet " %1$s %2$s help\n" 246871bb428fSJakub Kicinski "\n" 24693ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 247071bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 247149f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 247249f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 247349f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 247449f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2475f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 247649f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 247749f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 247805ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 247905ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 248005ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2481a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 248293a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 24831ba5ad36SDaniel Müller " ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n" 24841ba5ad36SDaniel Müller " sk_skb_stream_parser | flow_dissector }\n" 2485450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2486c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 24878cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 24888cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 248971bb428fSJakub Kicinski "", 249090040351SQuentin Monnet bin_name, argv[-2]); 249171bb428fSJakub Kicinski 249271bb428fSJakub Kicinski return 0; 249371bb428fSJakub Kicinski } 249471bb428fSJakub Kicinski 249571bb428fSJakub Kicinski static const struct cmd cmds[] = { 249671bb428fSJakub Kicinski { "show", do_show }, 24976ebe6dbdSJakub Kicinski { "list", do_show }, 24989f606179SQuentin Monnet { "help", do_help }, 249971bb428fSJakub Kicinski { "dump", do_dump }, 250071bb428fSJakub Kicinski { "pin", do_pin }, 250149a086c2SRoman Gushchin { "load", do_load }, 250277380998SStanislav Fomichev { "loadall", do_loadall }, 2503b7d3826cSJohn Fastabend { "attach", do_attach }, 2504b7d3826cSJohn Fastabend { "detach", do_detach }, 250530da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2506ba95c745SQuentin Monnet { "run", do_run }, 250747c09d6aSSong Liu { "profile", do_profile }, 250871bb428fSJakub Kicinski { 0 } 250971bb428fSJakub Kicinski }; 251071bb428fSJakub Kicinski 251171bb428fSJakub Kicinski int do_prog(int argc, char **argv) 251271bb428fSJakub Kicinski { 251371bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 251471bb428fSJakub Kicinski } 2515