1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
14 #include <sys/types.h>
17 #include <linux/err.h>
18 #include <linux/sizes.h>
26 #include "xlated_dumper.h"
33 static const char * const attach_type_strings[] = {
34 [BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
35 [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
36 [BPF_SK_MSG_VERDICT] = "msg_verdict",
37 [BPF_FLOW_DISSECTOR] = "flow_dissector",
38 [__MAX_BPF_ATTACH_TYPE] = NULL,
41 static enum bpf_attach_type parse_attach_type(const char *str)
43 enum bpf_attach_type type;
45 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
46 if (attach_type_strings[type] &&
47 is_prefix(str, attach_type_strings[type]))
51 return __MAX_BPF_ATTACH_TYPE;
54 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
56 struct timespec real_time_ts, boot_time_ts;
57 time_t wallclock_secs;
62 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
63 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
64 perror("Can't read clocks");
65 snprintf(buf, size, "%llu", nsecs / 1000000000);
69 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
70 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) /
74 if (!localtime_r(&wallclock_secs, &load_tm)) {
75 snprintf(buf, size, "%llu", nsecs / 1000000000);
80 strftime(buf, size, "%s", &load_tm);
82 strftime(buf, size, "%FT%T%z", &load_tm);
85 static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
93 struct bpf_prog_info info = {};
94 __u32 len = sizeof(info);
96 err = bpf_prog_get_next_id(id, &id);
98 if (errno != ENOENT) {
99 p_err("%s", strerror(errno));
105 fd = bpf_prog_get_fd_by_id(id);
107 p_err("can't get prog by id (%u): %s",
108 id, strerror(errno));
112 err = bpf_obj_get_info_by_fd(fd, &info, &len);
114 p_err("can't get prog info (%u): %s",
115 id, strerror(errno));
119 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
120 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
126 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
128 p_err("failed to realloc");
133 (*fds)[nb_fds++] = fd;
139 while (--nb_fds >= 0)
140 close((*fds)[nb_fds]);
144 static int prog_parse_fds(int *argc, char ***argv, int **fds)
146 if (is_prefix(**argv, "id")) {
152 id = strtoul(**argv, &endptr, 0);
154 p_err("can't parse %s as ID", **argv);
159 (*fds)[0] = bpf_prog_get_fd_by_id(id);
161 p_err("get by id (%u): %s", id, strerror(errno));
165 } else if (is_prefix(**argv, "tag")) {
166 unsigned char tag[BPF_TAG_SIZE];
170 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
171 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
173 p_err("can't parse tag");
178 return prog_fd_by_nametag(tag, fds, true);
179 } else if (is_prefix(**argv, "name")) {
185 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
186 p_err("can't parse name");
191 return prog_fd_by_nametag(name, fds, false);
192 } else if (is_prefix(**argv, "pinned")) {
200 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
206 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
210 int prog_parse_fd(int *argc, char ***argv)
215 fds = malloc(sizeof(int));
217 p_err("mem alloc failed");
220 nb_fds = prog_parse_fds(argc, argv, &fds);
223 p_err("several programs match this handle");
237 static void show_prog_maps(int fd, u32 num_maps)
239 struct bpf_prog_info info = {};
240 __u32 len = sizeof(info);
241 __u32 map_ids[num_maps];
245 info.nr_map_ids = num_maps;
246 info.map_ids = ptr_to_u64(map_ids);
248 err = bpf_obj_get_info_by_fd(fd, &info, &len);
249 if (err || !info.nr_map_ids)
253 jsonw_name(json_wtr, "map_ids");
254 jsonw_start_array(json_wtr);
255 for (i = 0; i < info.nr_map_ids; i++)
256 jsonw_uint(json_wtr, map_ids[i]);
257 jsonw_end_array(json_wtr);
260 for (i = 0; i < info.nr_map_ids; i++)
261 printf("%u%s", map_ids[i],
262 i == info.nr_map_ids - 1 ? "" : ",");
266 static void print_prog_header_json(struct bpf_prog_info *info)
268 jsonw_uint_field(json_wtr, "id", info->id);
269 if (info->type < ARRAY_SIZE(prog_type_name))
270 jsonw_string_field(json_wtr, "type",
271 prog_type_name[info->type]);
273 jsonw_uint_field(json_wtr, "type", info->type);
276 jsonw_string_field(json_wtr, "name", info->name);
278 jsonw_name(json_wtr, "tag");
279 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
280 info->tag[0], info->tag[1], info->tag[2], info->tag[3],
281 info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
283 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible);
284 if (info->run_time_ns) {
285 jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns);
286 jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt);
290 static void print_prog_json(struct bpf_prog_info *info, int fd)
294 jsonw_start_object(json_wtr);
295 print_prog_header_json(info);
296 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
298 if (info->load_time) {
301 print_boot_time(info->load_time, buf, sizeof(buf));
303 /* Piggy back on load_time, since 0 uid is a valid one */
304 jsonw_name(json_wtr, "loaded_at");
305 jsonw_printf(json_wtr, "%s", buf);
306 jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
309 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
311 if (info->jited_prog_len) {
312 jsonw_bool_field(json_wtr, "jited", true);
313 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
315 jsonw_bool_field(json_wtr, "jited", false);
318 memlock = get_fdinfo(fd, "memlock");
320 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
323 if (info->nr_map_ids)
324 show_prog_maps(fd, info->nr_map_ids);
327 jsonw_int_field(json_wtr, "btf_id", info->btf_id);
329 if (!hash_empty(prog_table.table)) {
330 struct pinned_obj *obj;
332 jsonw_name(json_wtr, "pinned");
333 jsonw_start_array(json_wtr);
334 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
335 if (obj->id == info->id)
336 jsonw_string(json_wtr, obj->path);
338 jsonw_end_array(json_wtr);
341 jsonw_end_object(json_wtr);
344 static void print_prog_header_plain(struct bpf_prog_info *info)
346 printf("%u: ", info->id);
347 if (info->type < ARRAY_SIZE(prog_type_name))
348 printf("%s ", prog_type_name[info->type]);
350 printf("type %u ", info->type);
353 printf("name %s ", info->name);
356 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
357 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
358 printf("%s", info->gpl_compatible ? " gpl" : "");
359 if (info->run_time_ns)
360 printf(" run_time_ns %lld run_cnt %lld",
361 info->run_time_ns, info->run_cnt);
365 static void print_prog_plain(struct bpf_prog_info *info, int fd)
369 print_prog_header_plain(info);
371 if (info->load_time) {
374 print_boot_time(info->load_time, buf, sizeof(buf));
376 /* Piggy back on load_time, since 0 uid is a valid one */
377 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid);
380 printf("\txlated %uB", info->xlated_prog_len);
382 if (info->jited_prog_len)
383 printf(" jited %uB", info->jited_prog_len);
385 printf(" not jited");
387 memlock = get_fdinfo(fd, "memlock");
389 printf(" memlock %sB", memlock);
392 if (info->nr_map_ids)
393 show_prog_maps(fd, info->nr_map_ids);
395 if (!hash_empty(prog_table.table)) {
396 struct pinned_obj *obj;
398 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
399 if (obj->id == info->id)
400 printf("\n\tpinned %s", obj->path);
405 printf("\n\tbtf_id %d", info->btf_id);
410 static int show_prog(int fd)
412 struct bpf_prog_info info = {};
413 __u32 len = sizeof(info);
416 err = bpf_obj_get_info_by_fd(fd, &info, &len);
418 p_err("can't get prog info: %s", strerror(errno));
423 print_prog_json(&info, fd);
425 print_prog_plain(&info, fd);
430 static int do_show_subset(int argc, char **argv)
436 fds = malloc(sizeof(int));
438 p_err("mem alloc failed");
441 nb_fds = prog_parse_fds(&argc, &argv, &fds);
445 if (json_output && nb_fds > 1)
446 jsonw_start_array(json_wtr); /* root array */
447 for (i = 0; i < nb_fds; i++) {
448 err = show_prog(fds[i]);
450 for (; i < nb_fds; i++)
456 if (json_output && nb_fds > 1)
457 jsonw_end_array(json_wtr); /* root array */
464 static int do_show(int argc, char **argv)
471 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
474 return do_show_subset(argc, argv);
480 jsonw_start_array(json_wtr);
482 err = bpf_prog_get_next_id(id, &id);
484 if (errno == ENOENT) {
488 p_err("can't get next program: %s%s", strerror(errno),
489 errno == EINVAL ? " -- kernel too old?" : "");
494 fd = bpf_prog_get_fd_by_id(id);
498 p_err("can't get prog by id (%u): %s",
499 id, strerror(errno));
511 jsonw_end_array(json_wtr);
517 prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
518 char *filepath, bool opcodes, bool visual, bool linum)
520 struct bpf_prog_linfo *prog_linfo = NULL;
521 const char *disasm_opt = NULL;
522 struct dump_data dd = {};
523 void *func_info = NULL;
524 struct btf *btf = NULL;
531 if (mode == DUMP_JITED) {
532 if (info->jited_prog_len == 0) {
533 p_info("no instructions returned");
536 buf = (unsigned char *)(info->jited_prog_insns);
537 member_len = info->jited_prog_len;
538 } else { /* DUMP_XLATED */
539 if (info->xlated_prog_len == 0) {
540 p_err("error retrieving insn dump: kernel.kptr_restrict set?");
543 buf = (unsigned char *)info->xlated_prog_insns;
544 member_len = info->xlated_prog_len;
547 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) {
548 p_err("failed to get btf");
552 func_info = (void *)info->func_info;
554 if (info->nr_line_info) {
555 prog_linfo = bpf_prog_linfo__new(info);
557 p_info("error in processing bpf_line_info. continue without it.");
561 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
563 p_err("can't open file %s: %s", filepath,
568 n = write(fd, buf, member_len);
570 if (n != member_len) {
571 p_err("error writing output file: %s",
572 n < 0 ? strerror(errno) : "short write");
577 jsonw_null(json_wtr);
578 } else if (mode == DUMP_JITED) {
579 const char *name = NULL;
582 name = ifindex_to_bfd_params(info->ifindex,
590 if (info->nr_jited_func_lens && info->jited_func_lens) {
591 struct kernel_sym *sym = NULL;
592 struct bpf_func_info *record;
593 char sym_name[SYM_MAX_NAME];
594 unsigned char *img = buf;
598 if (info->nr_jited_ksyms) {
599 kernel_syms_load(&dd);
600 ksyms = (__u64 *) info->jited_ksyms;
604 jsonw_start_array(json_wtr);
606 lens = (__u32 *) info->jited_func_lens;
607 for (i = 0; i < info->nr_jited_func_lens; i++) {
609 sym = kernel_syms_search(&dd, ksyms[i]);
611 sprintf(sym_name, "%s", sym->name);
613 sprintf(sym_name, "0x%016llx", ksyms[i]);
615 strcpy(sym_name, "unknown");
619 record = func_info + i * info->func_info_rec_size;
620 btf_dumper_type_only(btf, record->type_id,
626 jsonw_start_object(json_wtr);
627 if (func_info && func_sig[0] != '\0') {
628 jsonw_name(json_wtr, "proto");
629 jsonw_string(json_wtr, func_sig);
631 jsonw_name(json_wtr, "name");
632 jsonw_string(json_wtr, sym_name);
633 jsonw_name(json_wtr, "insns");
635 if (func_info && func_sig[0] != '\0')
636 printf("%s:\n", func_sig);
637 printf("%s:\n", sym_name);
640 disasm_print_insn(img, lens[i], opcodes,
641 name, disasm_opt, btf,
642 prog_linfo, ksyms[i], i,
648 jsonw_end_object(json_wtr);
654 jsonw_end_array(json_wtr);
656 disasm_print_insn(buf, member_len, opcodes, name,
657 disasm_opt, btf, NULL, 0, 0, false);
661 jsonw_null(json_wtr);
663 dump_xlated_cfg(buf, member_len);
665 kernel_syms_load(&dd);
666 dd.nr_jited_ksyms = info->nr_jited_ksyms;
667 dd.jited_ksyms = (__u64 *) info->jited_ksyms;
669 dd.func_info = func_info;
670 dd.finfo_rec_size = info->func_info_rec_size;
671 dd.prog_linfo = prog_linfo;
674 dump_xlated_json(&dd, buf, member_len, opcodes,
677 dump_xlated_plain(&dd, buf, member_len, opcodes,
679 kernel_syms_destroy(&dd);
685 static int do_dump(int argc, char **argv)
687 struct bpf_prog_info_linear *info_linear;
688 char *filepath = NULL;
689 bool opcodes = false;
698 if (is_prefix(*argv, "jited")) {
702 } else if (is_prefix(*argv, "xlated")) {
705 p_err("expected 'xlated' or 'jited', got: %s", *argv);
713 fds = malloc(sizeof(int));
715 p_err("mem alloc failed");
718 nb_fds = prog_parse_fds(&argc, &argv, &fds);
722 if (is_prefix(*argv, "file")) {
725 p_err("expected file path");
729 p_err("several programs matched");
735 } else if (is_prefix(*argv, "opcodes")) {
738 } else if (is_prefix(*argv, "visual")) {
740 p_err("several programs matched");
746 } else if (is_prefix(*argv, "linum")) {
756 if (mode == DUMP_JITED)
757 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS;
759 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS;
761 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS;
762 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
763 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
764 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
765 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
767 if (json_output && nb_fds > 1)
768 jsonw_start_array(json_wtr); /* root array */
769 for (i = 0; i < nb_fds; i++) {
770 info_linear = bpf_program__get_prog_info_linear(fds[i], arrays);
771 if (IS_ERR_OR_NULL(info_linear)) {
772 p_err("can't get prog info: %s", strerror(errno));
776 if (json_output && nb_fds > 1) {
777 jsonw_start_object(json_wtr); /* prog object */
778 print_prog_header_json(&info_linear->info);
779 jsonw_name(json_wtr, "insns");
780 } else if (nb_fds > 1) {
781 print_prog_header_plain(&info_linear->info);
784 err = prog_dump(&info_linear->info, mode, filepath, opcodes,
787 if (json_output && nb_fds > 1)
788 jsonw_end_object(json_wtr); /* prog object */
789 else if (i != nb_fds - 1 && nb_fds > 1)
797 if (json_output && nb_fds > 1)
798 jsonw_end_array(json_wtr); /* root array */
801 for (; i < nb_fds; i++)
808 static int do_pin(int argc, char **argv)
812 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id);
813 if (!err && json_output)
814 jsonw_null(json_wtr);
824 static int map_replace_compar(const void *p1, const void *p2)
826 const struct map_replace *a = p1, *b = p2;
828 return a->idx - b->idx;
831 static int parse_attach_detach_args(int argc, char **argv, int *progfd,
832 enum bpf_attach_type *attach_type,
838 *progfd = prog_parse_fd(&argc, &argv);
842 *attach_type = parse_attach_type(*argv);
843 if (*attach_type == __MAX_BPF_ATTACH_TYPE) {
844 p_err("invalid attach/detach type");
848 if (*attach_type == BPF_FLOW_DISSECTOR) {
857 *mapfd = map_parse_fd(&argc, &argv);
864 static int do_attach(int argc, char **argv)
866 enum bpf_attach_type attach_type;
870 err = parse_attach_detach_args(argc, argv,
871 &progfd, &attach_type, &mapfd);
875 err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
877 p_err("failed prog attach to map");
882 jsonw_null(json_wtr);
886 static int do_detach(int argc, char **argv)
888 enum bpf_attach_type attach_type;
892 err = parse_attach_detach_args(argc, argv,
893 &progfd, &attach_type, &mapfd);
897 err = bpf_prog_detach2(progfd, mapfd, attach_type);
899 p_err("failed prog detach from map");
904 jsonw_null(json_wtr);
908 static int check_single_stdin(char *file_data_in, char *file_ctx_in)
910 if (file_data_in && file_ctx_in &&
911 !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) {
912 p_err("cannot use standard input for both data_in and ctx_in");
919 static int get_run_data(const char *fname, void **data_ptr, unsigned int *size)
921 size_t block_size = 256;
922 size_t buf_size = block_size;
933 if (!strcmp(fname, "-"))
936 f = fopen(fname, "r");
938 p_err("failed to open %s: %s", fname, strerror(errno));
942 *data_ptr = malloc(block_size);
944 p_err("failed to allocate memory for data_in/ctx_in: %s",
949 while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) {
953 p_err("failed to read data_in/ctx_in from %s: %s",
954 fname, strerror(errno));
957 if (nb_read > buf_size - block_size) {
958 if (buf_size == UINT32_MAX) {
959 p_err("data_in/ctx_in is too long (max: %d)",
963 /* No space for fread()-ing next chunk; realloc() */
965 tmp = realloc(*data_ptr, buf_size);
967 p_err("failed to reallocate data_in/ctx_in: %s",
989 static void hex_print(void *data, unsigned int size, FILE *f)
994 for (i = 0; i < size; i += 16) {
996 fprintf(f, "%07zx\t", i);
998 /* Hexadecimal values */
999 for (j = i; j < i + 16 && j < size; j++)
1000 fprintf(f, "%02x%s", *(uint8_t *)(data + j),
1002 for (; j < i + 16; j++)
1003 fprintf(f, " %s", j % 2 ? " " : "");
1005 /* ASCII values (if relevant), '.' otherwise */
1007 for (j = i; j < i + 16 && j < size; j++) {
1008 c = *(char *)(data + j);
1009 if (c < ' ' || c > '~')
1011 fprintf(f, "%c%s", c, j == i + 7 ? " " : "");
1019 print_run_output(void *data, unsigned int size, const char *fname,
1020 const char *json_key)
1028 if (!strcmp(fname, "-")) {
1031 jsonw_name(json_wtr, json_key);
1032 print_data_json(data, size);
1034 hex_print(data, size, f);
1039 f = fopen(fname, "w");
1041 p_err("failed to open %s: %s", fname, strerror(errno));
1045 nb_written = fwrite(data, 1, size, f);
1047 if (nb_written != size) {
1048 p_err("failed to write output data/ctx: %s", strerror(errno));
1055 static int alloc_run_data(void **data_ptr, unsigned int size_out)
1057 *data_ptr = calloc(size_out, 1);
1059 p_err("failed to allocate memory for output data/ctx: %s",
1067 static int do_run(int argc, char **argv)
1069 char *data_fname_in = NULL, *data_fname_out = NULL;
1070 char *ctx_fname_in = NULL, *ctx_fname_out = NULL;
1071 struct bpf_prog_test_run_attr test_attr = {0};
1072 const unsigned int default_size = SZ_32K;
1073 void *data_in = NULL, *data_out = NULL;
1074 void *ctx_in = NULL, *ctx_out = NULL;
1075 unsigned int repeat = 1;
1081 fd = prog_parse_fd(&argc, &argv);
1086 if (detect_common_prefix(*argv, "data_in", "data_out",
1087 "data_size_out", NULL))
1089 if (detect_common_prefix(*argv, "ctx_in", "ctx_out",
1090 "ctx_size_out", NULL))
1093 if (is_prefix(*argv, "data_in")) {
1098 data_fname_in = GET_ARG();
1099 if (check_single_stdin(data_fname_in, ctx_fname_in))
1101 } else if (is_prefix(*argv, "data_out")) {
1106 data_fname_out = GET_ARG();
1107 } else if (is_prefix(*argv, "data_size_out")) {
1114 test_attr.data_size_out = strtoul(*argv, &endptr, 0);
1116 p_err("can't parse %s as output data size",
1121 } else if (is_prefix(*argv, "ctx_in")) {
1126 ctx_fname_in = GET_ARG();
1127 if (check_single_stdin(data_fname_in, ctx_fname_in))
1129 } else if (is_prefix(*argv, "ctx_out")) {
1134 ctx_fname_out = GET_ARG();
1135 } else if (is_prefix(*argv, "ctx_size_out")) {
1142 test_attr.ctx_size_out = strtoul(*argv, &endptr, 0);
1144 p_err("can't parse %s as output context size",
1149 } else if (is_prefix(*argv, "repeat")) {
1156 repeat = strtoul(*argv, &endptr, 0);
1158 p_err("can't parse %s as repeat number",
1164 p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?",
1170 err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in);
1175 if (!test_attr.data_size_out)
1176 test_attr.data_size_out = default_size;
1177 err = alloc_run_data(&data_out, test_attr.data_size_out);
1182 err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in);
1187 if (!test_attr.ctx_size_out)
1188 test_attr.ctx_size_out = default_size;
1189 err = alloc_run_data(&ctx_out, test_attr.ctx_size_out);
1194 test_attr.prog_fd = fd;
1195 test_attr.repeat = repeat;
1196 test_attr.data_in = data_in;
1197 test_attr.data_out = data_out;
1198 test_attr.ctx_in = ctx_in;
1199 test_attr.ctx_out = ctx_out;
1201 err = bpf_prog_test_run_xattr(&test_attr);
1203 p_err("failed to run program: %s", strerror(errno));
1210 jsonw_start_object(json_wtr); /* root */
1212 /* Do not exit on errors occurring when printing output data/context,
1213 * we still want to print return value and duration for program run.
1215 if (test_attr.data_size_out)
1216 err += print_run_output(test_attr.data_out,
1217 test_attr.data_size_out,
1218 data_fname_out, "data_out");
1219 if (test_attr.ctx_size_out)
1220 err += print_run_output(test_attr.ctx_out,
1221 test_attr.ctx_size_out,
1222 ctx_fname_out, "ctx_out");
1225 jsonw_uint_field(json_wtr, "retval", test_attr.retval);
1226 jsonw_uint_field(json_wtr, "duration", test_attr.duration);
1227 jsonw_end_object(json_wtr); /* root */
1229 fprintf(stdout, "Return value: %u, duration%s: %uns\n",
1231 repeat > 1 ? " (average)" : "", test_attr.duration);
1246 static int load_with_options(int argc, char **argv, bool first_prog_only)
1248 enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC;
1249 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,
1250 .relaxed_maps = relaxed_maps,
1252 struct bpf_object_load_attr load_attr = { 0 };
1253 enum bpf_attach_type expected_attach_type;
1254 struct map_replace *map_replace = NULL;
1255 struct bpf_program *prog = NULL, *pos;
1256 unsigned int old_map_fds = 0;
1257 const char *pinmaps = NULL;
1258 struct bpf_object *obj;
1259 struct bpf_map *map;
1260 const char *pinfile;
1270 pinfile = GET_ARG();
1273 if (is_prefix(*argv, "type")) {
1278 if (common_prog_type != BPF_PROG_TYPE_UNSPEC) {
1279 p_err("program type already specified");
1280 goto err_free_reuse_maps;
1283 goto err_free_reuse_maps;
1285 /* Put a '/' at the end of type to appease libbpf */
1286 type = malloc(strlen(*argv) + 2);
1288 p_err("mem alloc failed");
1289 goto err_free_reuse_maps;
1292 strcat(type, *argv);
1295 err = libbpf_prog_type_by_name(type, &common_prog_type,
1296 &expected_attach_type);
1299 goto err_free_reuse_maps;
1302 } else if (is_prefix(*argv, "map")) {
1303 void *new_map_replace;
1304 char *endptr, *name;
1310 goto err_free_reuse_maps;
1312 if (is_prefix(*argv, "idx")) {
1315 idx = strtoul(*argv, &endptr, 0);
1317 p_err("can't parse %s as IDX", *argv);
1318 goto err_free_reuse_maps;
1321 } else if (is_prefix(*argv, "name")) {
1327 p_err("expected 'idx' or 'name', got: '%s'?",
1329 goto err_free_reuse_maps;
1333 fd = map_parse_fd(&argc, &argv);
1335 goto err_free_reuse_maps;
1337 new_map_replace = reallocarray(map_replace,
1339 sizeof(*map_replace));
1340 if (!new_map_replace) {
1341 p_err("mem alloc failed");
1342 goto err_free_reuse_maps;
1344 map_replace = new_map_replace;
1346 map_replace[old_map_fds].idx = idx;
1347 map_replace[old_map_fds].name = name;
1348 map_replace[old_map_fds].fd = fd;
1350 } else if (is_prefix(*argv, "dev")) {
1354 p_err("offload device already specified");
1355 goto err_free_reuse_maps;
1358 goto err_free_reuse_maps;
1360 ifindex = if_nametoindex(*argv);
1362 p_err("unrecognized netdevice '%s': %s",
1363 *argv, strerror(errno));
1364 goto err_free_reuse_maps;
1367 } else if (is_prefix(*argv, "pinmaps")) {
1371 goto err_free_reuse_maps;
1373 pinmaps = GET_ARG();
1375 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
1377 goto err_free_reuse_maps;
1383 obj = bpf_object__open_file(file, &open_opts);
1384 if (IS_ERR_OR_NULL(obj)) {
1385 p_err("failed to open object file");
1386 goto err_free_reuse_maps;
1389 bpf_object__for_each_program(pos, obj) {
1390 enum bpf_prog_type prog_type = common_prog_type;
1392 if (prog_type == BPF_PROG_TYPE_UNSPEC) {
1393 const char *sec_name = bpf_program__title(pos, false);
1395 err = libbpf_prog_type_by_name(sec_name, &prog_type,
1396 &expected_attach_type);
1401 bpf_program__set_ifindex(pos, ifindex);
1402 bpf_program__set_type(pos, prog_type);
1403 bpf_program__set_expected_attach_type(pos, expected_attach_type);
1406 qsort(map_replace, old_map_fds, sizeof(*map_replace),
1407 map_replace_compar);
1409 /* After the sort maps by name will be first on the list, because they
1410 * have idx == -1. Resolve them.
1413 while (j < old_map_fds && map_replace[j].name) {
1415 bpf_object__for_each_map(map, obj) {
1416 if (!strcmp(bpf_map__name(map), map_replace[j].name)) {
1417 map_replace[j].idx = i;
1422 if (map_replace[j].idx == -1) {
1423 p_err("unable to find map '%s'", map_replace[j].name);
1428 /* Resort if any names were resolved */
1430 qsort(map_replace, old_map_fds, sizeof(*map_replace),
1431 map_replace_compar);
1433 /* Set ifindex and name reuse */
1436 bpf_object__for_each_map(map, obj) {
1437 if (!bpf_map__is_offload_neutral(map))
1438 bpf_map__set_ifindex(map, ifindex);
1440 if (j < old_map_fds && idx == map_replace[j].idx) {
1441 err = bpf_map__reuse_fd(map, map_replace[j++].fd);
1443 p_err("unable to set up map reuse: %d", err);
1447 /* Next reuse wants to apply to the same map */
1448 if (j < old_map_fds && map_replace[j].idx == idx) {
1449 p_err("replacement for map idx %d specified more than once",
1457 if (j < old_map_fds) {
1458 p_err("map idx '%d' not used", map_replace[j].idx);
1462 load_attr.obj = obj;
1464 /* log_level1 + log_level2 + stats, but not stable UAPI */
1465 load_attr.log_level = 1 + 2 + 4;
1467 err = bpf_object__load_xattr(&load_attr);
1469 p_err("failed to load object file");
1473 err = mount_bpffs_for_pin(pinfile);
1477 if (first_prog_only) {
1478 prog = bpf_program__next(NULL, obj);
1480 p_err("object file doesn't contain any bpf program");
1484 err = bpf_obj_pin(bpf_program__fd(prog), pinfile);
1486 p_err("failed to pin program %s",
1487 bpf_program__title(prog, false));
1491 err = bpf_object__pin_programs(obj, pinfile);
1493 p_err("failed to pin all programs");
1499 err = bpf_object__pin_maps(obj, pinmaps);
1501 p_err("failed to pin all maps");
1507 jsonw_null(json_wtr);
1509 bpf_object__close(obj);
1510 for (i = 0; i < old_map_fds; i++)
1511 close(map_replace[i].fd);
1517 if (first_prog_only)
1520 bpf_object__unpin_programs(obj, pinfile);
1522 bpf_object__close(obj);
1523 err_free_reuse_maps:
1524 for (i = 0; i < old_map_fds; i++)
1525 close(map_replace[i].fd);
1530 static int do_load(int argc, char **argv)
1532 return load_with_options(argc, argv, true);
1535 static int do_loadall(int argc, char **argv)
1537 return load_with_options(argc, argv, false);
1540 static int do_help(int argc, char **argv)
1543 jsonw_null(json_wtr);
1548 "Usage: %s %s { show | list } [PROG]\n"
1549 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n"
1550 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n"
1551 " %s %s pin PROG FILE\n"
1552 " %s %s { load | loadall } OBJ PATH \\\n"
1553 " [type TYPE] [dev NAME] \\\n"
1554 " [map { idx IDX | name NAME } MAP]\\\n"
1555 " [pinmaps MAP_DIR]\n"
1556 " %s %s attach PROG ATTACH_TYPE [MAP]\n"
1557 " %s %s detach PROG ATTACH_TYPE [MAP]\n"
1558 " %s %s run PROG \\\n"
1559 " data_in FILE \\\n"
1560 " [data_out FILE [data_size_out L]] \\\n"
1561 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n"
1566 " " HELP_SPEC_MAP "\n"
1567 " " HELP_SPEC_PROGRAM "\n"
1568 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
1569 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
1570 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
1571 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
1572 " sk_reuseport | flow_dissector | cgroup/sysctl |\n"
1573 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
1574 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
1575 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n"
1576 " cgroup/recvmsg6 | cgroup/getsockopt |\n"
1577 " cgroup/setsockopt }\n"
1578 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n"
1579 " flow_dissector }\n"
1580 " " HELP_SPEC_OPTIONS "\n"
1582 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1583 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1584 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1585 bin_name, argv[-2]);
1590 static const struct cmd cmds[] = {
1591 { "show", do_show },
1592 { "list", do_show },
1593 { "help", do_help },
1594 { "dump", do_dump },
1596 { "load", do_load },
1597 { "loadall", do_loadall },
1598 { "attach", do_attach },
1599 { "detach", do_detach },
1600 { "tracelog", do_tracelog },
1605 int do_prog(int argc, char **argv)
1607 return cmd_select(cmds, argc, argv, do_help);