diff options
-rw-r--r-- | tools/bpf/bpftool/Documentation/bpftool-prog.rst | 20 | ||||
-rw-r--r-- | tools/bpf/bpftool/bash-completion/bpftool | 67 | ||||
-rw-r--r-- | tools/bpf/bpftool/main.h | 3 | ||||
-rw-r--r-- | tools/bpf/bpftool/map.c | 4 | ||||
-rw-r--r-- | tools/bpf/bpftool/prog.c | 148 |
5 files changed, 219 insertions, 23 deletions
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index e53e1ad2caf0..64156a16d530 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst | |||
@@ -24,9 +24,10 @@ MAP COMMANDS | |||
24 | | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] | 24 | | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] |
25 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | 25 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] |
26 | | **bpftool** **prog pin** *PROG* *FILE* | 26 | | **bpftool** **prog pin** *PROG* *FILE* |
27 | | **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**dev** *NAME*] | 27 | | **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] |
28 | | **bpftool** **prog help** | 28 | | **bpftool** **prog help** |
29 | | | 29 | | |
30 | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | ||
30 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } | 31 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } |
31 | | *TYPE* := { | 32 | | *TYPE* := { |
32 | | **socket** | **kprobe** | **kretprobe** | **classifier** | **action** | | 33 | | **socket** | **kprobe** | **kretprobe** | **classifier** | **action** | |
@@ -73,10 +74,17 @@ DESCRIPTION | |||
73 | 74 | ||
74 | Note: *FILE* must be located in *bpffs* mount. | 75 | Note: *FILE* must be located in *bpffs* mount. |
75 | 76 | ||
76 | **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**dev** *NAME*] | 77 | **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] |
77 | Load bpf program from binary *OBJ* and pin as *FILE*. | 78 | Load bpf program from binary *OBJ* and pin as *FILE*. |
78 | **type** is optional, if not specified program type will be | 79 | **type** is optional, if not specified program type will be |
79 | inferred from section names. | 80 | inferred from section names. |
81 | By default bpftool will create new maps as declared in the ELF | ||
82 | object being loaded. **map** parameter allows for the reuse | ||
83 | of existing maps. It can be specified multiple times, each | ||
84 | time for a different map. *IDX* refers to index of the map | ||
85 | to be replaced in the ELF file counting from 0, while *NAME* | ||
86 | allows to replace a map by name. *MAP* specifies the map to | ||
87 | use, referring to it by **id** or through a **pinned** file. | ||
80 | If **dev** *NAME* is specified program will be loaded onto | 88 | If **dev** *NAME* is specified program will be loaded onto |
81 | given networking device (offload). | 89 | given networking device (offload). |
82 | 90 | ||
@@ -172,6 +180,14 @@ EXAMPLES | |||
172 | mov %rbx,0x0(%rbp) | 180 | mov %rbx,0x0(%rbp) |
173 | 48 89 5d 00 | 181 | 48 89 5d 00 |
174 | 182 | ||
183 | | | ||
184 | | **# bpftool prog load xdp1_kern.o /sys/fs/bpf/xdp1 type xdp map name rxcnt id 7** | ||
185 | | **# bpftool prog show pinned /sys/fs/bpf/xdp1** | ||
186 | | 9: xdp name xdp_prog1 tag 539ec6ce11b52f98 gpl | ||
187 | | loaded_at 2018-06-25T16:17:31-0700 uid 0 | ||
188 | | xlated 488B jited 336B memlock 4096B map_ids 7 | ||
189 | | **# rm /sys/fs/bpf/xdp1** | ||
190 | | | ||
175 | 191 | ||
176 | SEE ALSO | 192 | SEE ALSO |
177 | ======== | 193 | ======== |
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index caf8711993be..598066c40191 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool | |||
@@ -99,6 +99,29 @@ _bpftool_get_prog_tags() | |||
99 | command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) | 99 | command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) |
100 | } | 100 | } |
101 | 101 | ||
102 | _bpftool_get_obj_map_names() | ||
103 | { | ||
104 | local obj | ||
105 | |||
106 | obj=$1 | ||
107 | |||
108 | maps=$(objdump -j maps -t $obj 2>/dev/null | \ | ||
109 | command awk '/g . maps/ {print $NF}') | ||
110 | |||
111 | COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) ) | ||
112 | } | ||
113 | |||
114 | _bpftool_get_obj_map_idxs() | ||
115 | { | ||
116 | local obj | ||
117 | |||
118 | obj=$1 | ||
119 | |||
120 | nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps') | ||
121 | |||
122 | COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) ) | ||
123 | } | ||
124 | |||
102 | _sysfs_get_netdevs() | 125 | _sysfs_get_netdevs() |
103 | { | 126 | { |
104 | COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \ | 127 | COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \ |
@@ -220,12 +243,14 @@ _bpftool() | |||
220 | # Completion depends on object and command in use | 243 | # Completion depends on object and command in use |
221 | case $object in | 244 | case $object in |
222 | prog) | 245 | prog) |
223 | case $prev in | 246 | if [[ $command != "load" ]]; then |
224 | id) | 247 | case $prev in |
225 | _bpftool_get_prog_ids | 248 | id) |
226 | return 0 | 249 | _bpftool_get_prog_ids |
227 | ;; | 250 | return 0 |
228 | esac | 251 | ;; |
252 | esac | ||
253 | fi | ||
229 | 254 | ||
230 | local PROG_TYPE='id pinned tag' | 255 | local PROG_TYPE='id pinned tag' |
231 | case $command in | 256 | case $command in |
@@ -268,22 +293,52 @@ _bpftool() | |||
268 | return 0 | 293 | return 0 |
269 | ;; | 294 | ;; |
270 | load) | 295 | load) |
296 | local obj | ||
297 | |||
271 | if [[ ${#words[@]} -lt 6 ]]; then | 298 | if [[ ${#words[@]} -lt 6 ]]; then |
272 | _filedir | 299 | _filedir |
273 | return 0 | 300 | return 0 |
274 | fi | 301 | fi |
275 | 302 | ||
303 | obj=${words[3]} | ||
304 | |||
305 | if [[ ${words[-4]} == "map" ]]; then | ||
306 | COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) | ||
307 | return 0 | ||
308 | fi | ||
309 | if [[ ${words[-3]} == "map" ]]; then | ||
310 | if [[ ${words[-2]} == "idx" ]]; then | ||
311 | _bpftool_get_obj_map_idxs $obj | ||
312 | elif [[ ${words[-2]} == "name" ]]; then | ||
313 | _bpftool_get_obj_map_names $obj | ||
314 | fi | ||
315 | return 0 | ||
316 | fi | ||
317 | if [[ ${words[-2]} == "map" ]]; then | ||
318 | COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) ) | ||
319 | return 0 | ||
320 | fi | ||
321 | |||
276 | case $prev in | 322 | case $prev in |
277 | type) | 323 | type) |
278 | COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \ | 324 | COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \ |
279 | "$cur" ) ) | 325 | "$cur" ) ) |
280 | return 0 | 326 | return 0 |
281 | ;; | 327 | ;; |
328 | id) | ||
329 | _bpftool_get_map_ids | ||
330 | return 0 | ||
331 | ;; | ||
332 | pinned) | ||
333 | _filedir | ||
334 | return 0 | ||
335 | ;; | ||
282 | dev) | 336 | dev) |
283 | _sysfs_get_netdevs | 337 | _sysfs_get_netdevs |
284 | return 0 | 338 | return 0 |
285 | ;; | 339 | ;; |
286 | *) | 340 | *) |
341 | COMPREPLY=( $( compgen -W "map" -- "$cur" ) ) | ||
287 | _bpftool_once_attr 'type' | 342 | _bpftool_once_attr 'type' |
288 | _bpftool_once_attr 'dev' | 343 | _bpftool_once_attr 'dev' |
289 | return 0 | 344 | return 0 |
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 1e02e4031693..41004bb2644a 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h | |||
@@ -75,6 +75,8 @@ | |||
75 | "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" | 75 | "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" |
76 | #define HELP_SPEC_OPTIONS \ | 76 | #define HELP_SPEC_OPTIONS \ |
77 | "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" | 77 | "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" |
78 | #define HELP_SPEC_MAP \ | ||
79 | "MAP := { id MAP_ID | pinned FILE }" | ||
78 | 80 | ||
79 | enum bpf_obj_type { | 81 | enum bpf_obj_type { |
80 | BPF_OBJ_UNKNOWN, | 82 | BPF_OBJ_UNKNOWN, |
@@ -136,6 +138,7 @@ int do_cgroup(int argc, char **arg); | |||
136 | int do_perf(int argc, char **arg); | 138 | int do_perf(int argc, char **arg); |
137 | 139 | ||
138 | int prog_parse_fd(int *argc, char ***argv); | 140 | int prog_parse_fd(int *argc, char ***argv); |
141 | int map_parse_fd(int *argc, char ***argv); | ||
139 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); | 142 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); |
140 | 143 | ||
141 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 144 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 5989e1575ae4..e2baec1122fb 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c | |||
@@ -93,7 +93,7 @@ static void *alloc_value(struct bpf_map_info *info) | |||
93 | return malloc(info->value_size); | 93 | return malloc(info->value_size); |
94 | } | 94 | } |
95 | 95 | ||
96 | static int map_parse_fd(int *argc, char ***argv) | 96 | int map_parse_fd(int *argc, char ***argv) |
97 | { | 97 | { |
98 | int fd; | 98 | int fd; |
99 | 99 | ||
@@ -824,7 +824,7 @@ static int do_help(int argc, char **argv) | |||
824 | " %s %s event_pipe MAP [cpu N index M]\n" | 824 | " %s %s event_pipe MAP [cpu N index M]\n" |
825 | " %s %s help\n" | 825 | " %s %s help\n" |
826 | "\n" | 826 | "\n" |
827 | " MAP := { id MAP_ID | pinned FILE }\n" | 827 | " " HELP_SPEC_MAP "\n" |
828 | " DATA := { [hex] BYTES }\n" | 828 | " DATA := { [hex] BYTES }\n" |
829 | " " HELP_SPEC_PROGRAM "\n" | 829 | " " HELP_SPEC_PROGRAM "\n" |
830 | " VALUE := { DATA | MAP | PROG }\n" | 830 | " VALUE := { DATA | MAP | PROG }\n" |
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 2bdd5ecd1aad..dce960d22106 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c | |||
@@ -31,6 +31,7 @@ | |||
31 | * SOFTWARE. | 31 | * SOFTWARE. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #define _GNU_SOURCE | ||
34 | #include <errno.h> | 35 | #include <errno.h> |
35 | #include <fcntl.h> | 36 | #include <fcntl.h> |
36 | #include <stdarg.h> | 37 | #include <stdarg.h> |
@@ -682,18 +683,34 @@ static int do_pin(int argc, char **argv) | |||
682 | return err; | 683 | return err; |
683 | } | 684 | } |
684 | 685 | ||
686 | struct map_replace { | ||
687 | int idx; | ||
688 | int fd; | ||
689 | char *name; | ||
690 | }; | ||
691 | |||
692 | int map_replace_compar(const void *p1, const void *p2) | ||
693 | { | ||
694 | const struct map_replace *a = p1, *b = p2; | ||
695 | |||
696 | return a->idx - b->idx; | ||
697 | } | ||
698 | |||
685 | static int do_load(int argc, char **argv) | 699 | static int do_load(int argc, char **argv) |
686 | { | 700 | { |
687 | enum bpf_attach_type expected_attach_type; | 701 | enum bpf_attach_type expected_attach_type; |
688 | struct bpf_object_open_attr attr = { | 702 | struct bpf_object_open_attr attr = { |
689 | .prog_type = BPF_PROG_TYPE_UNSPEC, | 703 | .prog_type = BPF_PROG_TYPE_UNSPEC, |
690 | }; | 704 | }; |
705 | struct map_replace *map_replace = NULL; | ||
706 | unsigned int old_map_fds = 0; | ||
691 | struct bpf_program *prog; | 707 | struct bpf_program *prog; |
692 | struct bpf_object *obj; | 708 | struct bpf_object *obj; |
693 | struct bpf_map *map; | 709 | struct bpf_map *map; |
694 | const char *pinfile; | 710 | const char *pinfile; |
711 | unsigned int i, j; | ||
695 | __u32 ifindex = 0; | 712 | __u32 ifindex = 0; |
696 | int err; | 713 | int idx, err; |
697 | 714 | ||
698 | if (!REQ_ARGS(2)) | 715 | if (!REQ_ARGS(2)) |
699 | return -1; | 716 | return -1; |
@@ -708,16 +725,16 @@ static int do_load(int argc, char **argv) | |||
708 | 725 | ||
709 | if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { | 726 | if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { |
710 | p_err("program type already specified"); | 727 | p_err("program type already specified"); |
711 | return -1; | 728 | goto err_free_reuse_maps; |
712 | } | 729 | } |
713 | if (!REQ_ARGS(1)) | 730 | if (!REQ_ARGS(1)) |
714 | return -1; | 731 | goto err_free_reuse_maps; |
715 | 732 | ||
716 | /* Put a '/' at the end of type to appease libbpf */ | 733 | /* Put a '/' at the end of type to appease libbpf */ |
717 | type = malloc(strlen(*argv) + 2); | 734 | type = malloc(strlen(*argv) + 2); |
718 | if (!type) { | 735 | if (!type) { |
719 | p_err("mem alloc failed"); | 736 | p_err("mem alloc failed"); |
720 | return -1; | 737 | goto err_free_reuse_maps; |
721 | } | 738 | } |
722 | *type = 0; | 739 | *type = 0; |
723 | strcat(type, *argv); | 740 | strcat(type, *argv); |
@@ -728,37 +745,81 @@ static int do_load(int argc, char **argv) | |||
728 | free(type); | 745 | free(type); |
729 | if (err < 0) { | 746 | if (err < 0) { |
730 | p_err("unknown program type '%s'", *argv); | 747 | p_err("unknown program type '%s'", *argv); |
731 | return err; | 748 | goto err_free_reuse_maps; |
732 | } | 749 | } |
733 | NEXT_ARG(); | 750 | NEXT_ARG(); |
751 | } else if (is_prefix(*argv, "map")) { | ||
752 | char *endptr, *name; | ||
753 | int fd; | ||
754 | |||
755 | NEXT_ARG(); | ||
756 | |||
757 | if (!REQ_ARGS(4)) | ||
758 | goto err_free_reuse_maps; | ||
759 | |||
760 | if (is_prefix(*argv, "idx")) { | ||
761 | NEXT_ARG(); | ||
762 | |||
763 | idx = strtoul(*argv, &endptr, 0); | ||
764 | if (*endptr) { | ||
765 | p_err("can't parse %s as IDX", *argv); | ||
766 | goto err_free_reuse_maps; | ||
767 | } | ||
768 | name = NULL; | ||
769 | } else if (is_prefix(*argv, "name")) { | ||
770 | NEXT_ARG(); | ||
771 | |||
772 | name = *argv; | ||
773 | idx = -1; | ||
774 | } else { | ||
775 | p_err("expected 'idx' or 'name', got: '%s'?", | ||
776 | *argv); | ||
777 | goto err_free_reuse_maps; | ||
778 | } | ||
779 | NEXT_ARG(); | ||
780 | |||
781 | fd = map_parse_fd(&argc, &argv); | ||
782 | if (fd < 0) | ||
783 | goto err_free_reuse_maps; | ||
784 | |||
785 | map_replace = reallocarray(map_replace, old_map_fds + 1, | ||
786 | sizeof(*map_replace)); | ||
787 | if (!map_replace) { | ||
788 | p_err("mem alloc failed"); | ||
789 | goto err_free_reuse_maps; | ||
790 | } | ||
791 | map_replace[old_map_fds].idx = idx; | ||
792 | map_replace[old_map_fds].name = name; | ||
793 | map_replace[old_map_fds].fd = fd; | ||
794 | old_map_fds++; | ||
734 | } else if (is_prefix(*argv, "dev")) { | 795 | } else if (is_prefix(*argv, "dev")) { |
735 | NEXT_ARG(); | 796 | NEXT_ARG(); |
736 | 797 | ||
737 | if (ifindex) { | 798 | if (ifindex) { |
738 | p_err("offload device already specified"); | 799 | p_err("offload device already specified"); |
739 | return -1; | 800 | goto err_free_reuse_maps; |
740 | } | 801 | } |
741 | if (!REQ_ARGS(1)) | 802 | if (!REQ_ARGS(1)) |
742 | return -1; | 803 | goto err_free_reuse_maps; |
743 | 804 | ||
744 | ifindex = if_nametoindex(*argv); | 805 | ifindex = if_nametoindex(*argv); |
745 | if (!ifindex) { | 806 | if (!ifindex) { |
746 | p_err("unrecognized netdevice '%s': %s", | 807 | p_err("unrecognized netdevice '%s': %s", |
747 | *argv, strerror(errno)); | 808 | *argv, strerror(errno)); |
748 | return -1; | 809 | goto err_free_reuse_maps; |
749 | } | 810 | } |
750 | NEXT_ARG(); | 811 | NEXT_ARG(); |
751 | } else { | 812 | } else { |
752 | p_err("expected no more arguments, 'type' or 'dev', got: '%s'?", | 813 | p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", |
753 | *argv); | 814 | *argv); |
754 | return -1; | 815 | goto err_free_reuse_maps; |
755 | } | 816 | } |
756 | } | 817 | } |
757 | 818 | ||
758 | obj = bpf_object__open_xattr(&attr); | 819 | obj = bpf_object__open_xattr(&attr); |
759 | if (IS_ERR_OR_NULL(obj)) { | 820 | if (IS_ERR_OR_NULL(obj)) { |
760 | p_err("failed to open object file"); | 821 | p_err("failed to open object file"); |
761 | return -1; | 822 | goto err_free_reuse_maps; |
762 | } | 823 | } |
763 | 824 | ||
764 | prog = bpf_program__next(NULL, obj); | 825 | prog = bpf_program__next(NULL, obj); |
@@ -782,10 +843,62 @@ static int do_load(int argc, char **argv) | |||
782 | bpf_program__set_type(prog, attr.prog_type); | 843 | bpf_program__set_type(prog, attr.prog_type); |
783 | bpf_program__set_expected_attach_type(prog, expected_attach_type); | 844 | bpf_program__set_expected_attach_type(prog, expected_attach_type); |
784 | 845 | ||
785 | bpf_map__for_each(map, obj) | 846 | qsort(map_replace, old_map_fds, sizeof(*map_replace), |
847 | map_replace_compar); | ||
848 | |||
849 | /* After the sort maps by name will be first on the list, because they | ||
850 | * have idx == -1. Resolve them. | ||
851 | */ | ||
852 | j = 0; | ||
853 | while (j < old_map_fds && map_replace[j].name) { | ||
854 | i = 0; | ||
855 | bpf_map__for_each(map, obj) { | ||
856 | if (!strcmp(bpf_map__name(map), map_replace[j].name)) { | ||
857 | map_replace[j].idx = i; | ||
858 | break; | ||
859 | } | ||
860 | i++; | ||
861 | } | ||
862 | if (map_replace[j].idx == -1) { | ||
863 | p_err("unable to find map '%s'", map_replace[j].name); | ||
864 | goto err_close_obj; | ||
865 | } | ||
866 | j++; | ||
867 | } | ||
868 | /* Resort if any names were resolved */ | ||
869 | if (j) | ||
870 | qsort(map_replace, old_map_fds, sizeof(*map_replace), | ||
871 | map_replace_compar); | ||
872 | |||
873 | /* Set ifindex and name reuse */ | ||
874 | j = 0; | ||
875 | idx = 0; | ||
876 | bpf_map__for_each(map, obj) { | ||
786 | if (!bpf_map__is_offload_neutral(map)) | 877 | if (!bpf_map__is_offload_neutral(map)) |
787 | bpf_map__set_ifindex(map, ifindex); | 878 | bpf_map__set_ifindex(map, ifindex); |
788 | 879 | ||
880 | if (j < old_map_fds && idx == map_replace[j].idx) { | ||
881 | err = bpf_map__reuse_fd(map, map_replace[j++].fd); | ||
882 | if (err) { | ||
883 | p_err("unable to set up map reuse: %d", err); | ||
884 | goto err_close_obj; | ||
885 | } | ||
886 | |||
887 | /* Next reuse wants to apply to the same map */ | ||
888 | if (j < old_map_fds && map_replace[j].idx == idx) { | ||
889 | p_err("replacement for map idx %d specified more than once", | ||
890 | idx); | ||
891 | goto err_close_obj; | ||
892 | } | ||
893 | } | ||
894 | |||
895 | idx++; | ||
896 | } | ||
897 | if (j < old_map_fds) { | ||
898 | p_err("map idx '%d' not used", map_replace[j].idx); | ||
899 | goto err_close_obj; | ||
900 | } | ||
901 | |||
789 | err = bpf_object__load(obj); | 902 | err = bpf_object__load(obj); |
790 | if (err) { | 903 | if (err) { |
791 | p_err("failed to load object file"); | 904 | p_err("failed to load object file"); |
@@ -799,11 +912,18 @@ static int do_load(int argc, char **argv) | |||
799 | jsonw_null(json_wtr); | 912 | jsonw_null(json_wtr); |
800 | 913 | ||
801 | bpf_object__close(obj); | 914 | bpf_object__close(obj); |
915 | for (i = 0; i < old_map_fds; i++) | ||
916 | close(map_replace[i].fd); | ||
917 | free(map_replace); | ||
802 | 918 | ||
803 | return 0; | 919 | return 0; |
804 | 920 | ||
805 | err_close_obj: | 921 | err_close_obj: |
806 | bpf_object__close(obj); | 922 | bpf_object__close(obj); |
923 | err_free_reuse_maps: | ||
924 | for (i = 0; i < old_map_fds; i++) | ||
925 | close(map_replace[i].fd); | ||
926 | free(map_replace); | ||
807 | return -1; | 927 | return -1; |
808 | } | 928 | } |
809 | 929 | ||
@@ -819,9 +939,11 @@ static int do_help(int argc, char **argv) | |||
819 | " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" | 939 | " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" |
820 | " %s %s dump jited PROG [{ file FILE | opcodes }]\n" | 940 | " %s %s dump jited PROG [{ file FILE | opcodes }]\n" |
821 | " %s %s pin PROG FILE\n" | 941 | " %s %s pin PROG FILE\n" |
822 | " %s %s load OBJ FILE [type TYPE] [dev NAME]\n" | 942 | " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" |
943 | " [map { idx IDX | name NAME } MAP]\n" | ||
823 | " %s %s help\n" | 944 | " %s %s help\n" |
824 | "\n" | 945 | "\n" |
946 | " " HELP_SPEC_MAP "\n" | ||
825 | " " HELP_SPEC_PROGRAM "\n" | 947 | " " HELP_SPEC_PROGRAM "\n" |
826 | " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" | 948 | " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" |
827 | " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" | 949 | " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" |