summaryrefslogtreecommitdiffstats
path: root/tools/bpf
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2018-07-10 17:43:07 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-07-11 16:13:34 -0400
commit3ff5a4dc5d890963e669fc99cc62ee07d1da24e8 (patch)
tree227ec4a474eaa03236f5ce8df1df25d890846ee4 /tools/bpf
parent26736eb9a483715c2e971a8866f55fbb156903e2 (diff)
tools: bpftool: allow reuse of maps with bpftool prog load
Add map parameter to prog load which will allow reuse of existing maps instead of creating new ones. We need feature detection and compat code for reallocarray, since it's not available in many libc versions. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools/bpf')
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-prog.rst20
-rw-r--r--tools/bpf/bpftool/bash-completion/bpftool67
-rw-r--r--tools/bpf/bpftool/main.h3
-rw-r--r--tools/bpf/bpftool/map.c4
-rw-r--r--tools/bpf/bpftool/prog.c148
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
176SEE ALSO 192SEE 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
79enum bpf_obj_type { 81enum bpf_obj_type {
80 BPF_OBJ_UNKNOWN, 82 BPF_OBJ_UNKNOWN,
@@ -136,6 +138,7 @@ int do_cgroup(int argc, char **arg);
136int do_perf(int argc, char **arg); 138int do_perf(int argc, char **arg);
137 139
138int prog_parse_fd(int *argc, char ***argv); 140int prog_parse_fd(int *argc, char ***argv);
141int map_parse_fd(int *argc, char ***argv);
139int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); 142int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
140 143
141void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 144void 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
96static int map_parse_fd(int *argc, char ***argv) 96int 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
686struct map_replace {
687 int idx;
688 int fd;
689 char *name;
690};
691
692int 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
685static int do_load(int argc, char **argv) 699static 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
805err_close_obj: 921err_close_obj:
806 bpf_object__close(obj); 922 bpf_object__close(obj);
923err_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"