History

Merge branch 'bpf-bpftool-improved-prog-load'

Jakub Kicinski says: ==================== This series starts with two minor clean ups to test_offload.py selftest script. The next 11 patches extend the abilities of bpftool prog load beyond the simple cgroup use cases. Three new parameters are added: - type - allows specifying program type, independent of how code sections are named; - map - allows reusing existing maps, instead of creating a new map on every program load; - dev - offload/binding to a device. A number of changes to libbpf is required to accomplish the task. The section - program type logic mapping is exposed. We should probably aim to use the libbpf program section naming everywhere. For reuse of maps we need to allow users to set FD for bpf map object in libbpf. Examples Load program my_xdp.o and pin it as /sys/fs/bpf/my_xdp, for xdp program type: $ bpftool prog load my_xdp.o /sys/fs/bpf/my_xdp \ type xdp As above but for offload: $ bpftool prog load my_xdp.o /sys/fs/bpf/my_xdp \ type xdp \ dev netdevsim0 Load program my_maps.o, but for the first map reuse map id 17, and for the map called "other_map" reuse pinned map /sys/fs/bpf/map0: $ bpftool prog load my_maps.o /sys/fs/bpf/prog \ map idx 0 id 17 \ map name other_map pinned /sys/fs/bpf/map0 v3: - fix return codes in patch 5; - rename libbpf_prog_type_by_string() -> libbpf_prog_type_by_name(); - fold file path into xattr in patch 8; - add patch 10; - use dup3() in patch 12; - depend on fd value in patch 12; - close old fd in patch 12. v2: - add compat for reallocarray(). ====================

Daniel Borkmann committed 8 years ago

Commit 671dffa2 parents d90c936 3ff5a4d18 files · +906 −108Browse files

Unified · Split

18 files
  1. tools/bpf/bpftool/Documentation/bpftool-prog.rst +31 −2
  2. tools/bpf/bpftool/Makefile +5 −1
  3. tools/bpf/bpftool/bash-completion/bpftool +88 −8
  4. tools/bpf/bpftool/main.h +19 −0
  5. tools/bpf/bpftool/map.c +2 −2
  6. tools/bpf/bpftool/prog.c +237 −8
  7. tools/bpf/bpftool/xlated_dumper.c +3 −3
  8. tools/build/feature/Makefile +4 −0
  9. tools/build/feature/test-reallocarray.c +8 −0
  10. tools/include/linux/compiler-gcc.h +4 −0
  11. tools/include/linux/overflow.h +278 −0
  12. tools/include/tools/libc_compat.h +20 −0
  13. tools/lib/bpf/Build +1 −1
  14. tools/lib/bpf/Makefile +5 −1
  15. tools/lib/bpf/libbpf.c +111 −77
  16. tools/lib/bpf/libbpf.h +11 −0
  17. tools/lib/bpf/libbpf_errno.c +74 −0
  18. tools/testing/selftests/bpf/test_offload.py +5 −5
tools/bpf/bpftool/Documentation/bpftool-prog.rst+31−2
@@ -24,10 +24,20 @@ MAP COMMANDS · 23 unmodified lines
2424 | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
2525 | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
2626 | **bpftool** **prog pin** *PROG* *FILE*
27−| **bpftool** **prog load** *OBJ* *FILE*
27+| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
2828 | **bpftool** **prog help**
2929 |
30+| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
3031 | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
32+| *TYPE* := {
33+| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** |
34+| **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** |
35+| **cgroup/sock** | **cgroup/dev** | **lwt_in** | **lwt_out** | **lwt_xmit** |
36+| **lwt_seg6local** | **sockops** | **sk_skb** | **sk_msg** | **lirc_mode2** |
37+| **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** |
38+| **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6**
39+| }
40+
3141
3242 DESCRIPTION
3343 ===========
@@ -64,8 +74,19 @@ DESCRIPTION · 30 unmodified lines
6474
6575 Note: *FILE* must be located in *bpffs* mount.
6676
67− **bpftool prog load** *OBJ* *FILE*
77+ **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
6878 Load bpf program from binary *OBJ* and pin as *FILE*.
79+ **type** is optional, if not specified program type will be
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.
88+ If **dev** *NAME* is specified program will be loaded onto
89+ given networking device (offload).
6990
7091 Note: *FILE* must be located in *bpffs* mount.
7192
@@ -159,6 +180,14 @@ EXAMPLES · 87 unmodified lines
159180 mov %rbx,0x0(%rbp)
160181 48 89 5d 00
161182
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+|
162191
163192 SEE ALSO
164193 ========
tools/bpf/bpftool/Makefile+5−1
@@ -52,7 +52,7 @@ INSTALL ?= install · 51 unmodified lines
5252 RM ?= rm -f
5353
5454 FEATURE_USER = .bpftool
55−FEATURE_TESTS = libbfd disassembler-four-args
55+FEATURE_TESTS = libbfd disassembler-four-args reallocarray
5656 FEATURE_DISPLAY = libbfd disassembler-four-args
5757
5858 check_feat := 1
@@ -75,6 +75,10 @@ ifeq ($(feature-disassembler-four-args), 1) · 16 unmodified lines
7575 CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
7676 endif
7777
78+ifeq ($(feature-reallocarray), 0)
79+CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
80+endif
81+
7882 include $(wildcard $(OUTPUT)*.d)
7983
8084 all: $(OUTPUT)bpftool
tools/bpf/bpftool/bash-completion/bpftool+88−8
@@ -99,6 +99,35 @@ _bpftool_get_prog_tags() · 98 unmodified lines
9999 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
100100 }
101101
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+
125+_sysfs_get_netdevs()
126+{
127+ COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
128+ "$cur" ) )
129+}
130+
102131 # For bpftool map update: retrieve type of the map to update.
103132 _bpftool_map_update_map_type()
104133 {
@@ -214,12 +243,14 @@ _bpftool() · 109 unmodified lines
214243 # Completion depends on object and command in use
215244 case $object in
216245 prog)
217− case $prev in
218− id)
219− _bpftool_get_prog_ids
220− return 0
221− ;;
222− esac
246+ if [[ $command != "load" ]]; then
247+ case $prev in
248+ id)
249+ _bpftool_get_prog_ids
250+ return 0
251+ ;;
252+ esac
253+ fi
223254
224255 local PROG_TYPE='id pinned tag'
225256 case $command in
@@ -262,8 +293,57 @@ _bpftool() · 36 unmodified lines
262293 return 0
263294 ;;
264295 load)
265− _filedir
266− return 0
296+ local obj
297+
298+ if [[ ${#words[@]} -lt 6 ]]; then
299+ _filedir
300+ return 0
301+ fi
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+
322+ case $prev in
323+ type)
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" -- \
325+ "$cur" ) )
326+ return 0
327+ ;;
328+ id)
329+ _bpftool_get_map_ids
330+ return 0
331+ ;;
332+ pinned)
333+ _filedir
334+ return 0
335+ ;;
336+ dev)
337+ _sysfs_get_netdevs
338+ return 0
339+ ;;
340+ *)
341+ COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
342+ _bpftool_once_attr 'type'
343+ _bpftool_once_attr 'dev'
344+ return 0
345+ ;;
346+ esac
267347 ;;
268348 *)
269349 [[ $prev == $object ]] && \
tools/bpf/bpftool/main.h+19−0
@@ -42,6 +42,7 @@ · 41 unmodified lines
4242 #include <linux/compiler.h>
4343 #include <linux/kernel.h>
4444 #include <linux/hashtable.h>
45+#include <tools/libc_compat.h>
4546
4647 #include "json_writer.h"
4748
@@ -50,6 +51,21 @@ · 2 unmodified lines
5051 #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })
5152 #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
5253 #define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; })
54+#define GET_ARG() ({ argc--; *argv++; })
55+#define REQ_ARGS(cnt) \
56+ ({ \
57+ int _cnt = (cnt); \
58+ bool _res; \
59+ \
60+ if (argc < _cnt) { \
61+ p_err("'%s' needs at least %d arguments, %d found", \
62+ argv[-1], _cnt, argc); \
63+ _res = false; \
64+ } else { \
65+ _res = true; \
66+ } \
67+ _res; \
68+ })
5369
5470 #define ERR_MAX_LEN 1024
5571
@@ -59,6 +75,8 @@ · 3 unmodified lines
5975 "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
6076 #define HELP_SPEC_OPTIONS \
6177 "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }"
78+#define HELP_SPEC_MAP \
79+ "MAP := { id MAP_ID | pinned FILE }"
6280
6381 enum bpf_obj_type {
6482 BPF_OBJ_UNKNOWN,
@@ -120,6 +138,7 @@ int do_cgroup(int argc, char **arg); · 55 unmodified lines
120138 int do_perf(int argc, char **arg);
121139
122140 int prog_parse_fd(int *argc, char ***argv);
141+int map_parse_fd(int *argc, char ***argv);
123142 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
124143
125144 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
tools/bpf/bpftool/map.c+2−2
@@ -93,7 +93,7 @@ static void *alloc_value(struct bpf_map_info *info) · 92 unmodified lines
9393 return malloc(info->value_size);
9494 }
9595
96−static int map_parse_fd(int *argc, char ***argv)
96+int map_parse_fd(int *argc, char ***argv)
9797 {
9898 int fd;
9999
@@ -824,7 +824,7 @@ static int do_help(int argc, char **argv) · 724 unmodified lines
824824 " %s %s event_pipe MAP [cpu N index M]\n"
825825 " %s %s help\n"
826826 "\n"
827− " MAP := { id MAP_ID | pinned FILE }\n"
827+ " " HELP_SPEC_MAP "\n"
828828 " DATA := { [hex] BYTES }\n"
829829 " " HELP_SPEC_PROGRAM "\n"
830830 " VALUE := { DATA | MAP | PROG }\n"
tools/bpf/bpftool/prog.c+237−8
@@ -31,6 +31,7 @@ · 30 unmodified lines
3131 * SOFTWARE.
3232 */
3333
34+#define _GNU_SOURCE
3435 #include <errno.h>
3536 #include <fcntl.h>
3637 #include <stdarg.h>
@@ -39,9 +40,12 @@ · 2 unmodified lines
3940 #include <string.h>
4041 #include <time.h>
4142 #include <unistd.h>
43+#include <net/if.h>
4244 #include <sys/types.h>
4345 #include <sys/stat.h>
4446
47+#include <linux/err.h>
48+
4549 #include <bpf.h>
4650 #include <libbpf.h>
4751
@@ -679,31 +683,247 @@ static int do_pin(int argc, char **argv) · 631 unmodified lines
679683 return err;
680684 }
681685
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+
682699 static int do_load(int argc, char **argv)
683700 {
701+ enum bpf_attach_type expected_attach_type;
702+ struct bpf_object_open_attr attr = {
703+ .prog_type = BPF_PROG_TYPE_UNSPEC,
704+ };
705+ struct map_replace *map_replace = NULL;
706+ unsigned int old_map_fds = 0;
707+ struct bpf_program *prog;
684708 struct bpf_object *obj;
685− int prog_fd;
686−
687− if (argc != 2)
688− usage();
709+ struct bpf_map *map;
710+ const char *pinfile;
711+ unsigned int i, j;
712+ __u32 ifindex = 0;
713+ int idx, err;
689714
690− if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
691− p_err("failed to load program");
715+ if (!REQ_ARGS(2))
692716 return -1;
717+ attr.file = GET_ARG();
718+ pinfile = GET_ARG();
719+
720+ while (argc) {
721+ if (is_prefix(*argv, "type")) {
722+ char *type;
723+
724+ NEXT_ARG();
725+
726+ if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) {
727+ p_err("program type already specified");
728+ goto err_free_reuse_maps;
729+ }
730+ if (!REQ_ARGS(1))
731+ goto err_free_reuse_maps;
732+
733+ /* Put a '/' at the end of type to appease libbpf */
734+ type = malloc(strlen(*argv) + 2);
735+ if (!type) {
736+ p_err("mem alloc failed");
737+ goto err_free_reuse_maps;
738+ }
739+ *type = 0;
740+ strcat(type, *argv);
741+ strcat(type, "/");
742+
743+ err = libbpf_prog_type_by_name(type, &attr.prog_type,
744+ &expected_attach_type);
745+ free(type);
746+ if (err < 0) {
747+ p_err("unknown program type '%s'", *argv);
748+ goto err_free_reuse_maps;
749+ }
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++;
795+ } else if (is_prefix(*argv, "dev")) {
796+ NEXT_ARG();
797+
798+ if (ifindex) {
799+ p_err("offload device already specified");
800+ goto err_free_reuse_maps;
801+ }
802+ if (!REQ_ARGS(1))
803+ goto err_free_reuse_maps;
804+
805+ ifindex = if_nametoindex(*argv);
806+ if (!ifindex) {
807+ p_err("unrecognized netdevice '%s': %s",
808+ *argv, strerror(errno));
809+ goto err_free_reuse_maps;
810+ }
811+ NEXT_ARG();
812+ } else {
813+ p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
814+ *argv);
815+ goto err_free_reuse_maps;
816+ }
817+ }
818+
819+ obj = bpf_object__open_xattr(&attr);
820+ if (IS_ERR_OR_NULL(obj)) {
821+ p_err("failed to open object file");
822+ goto err_free_reuse_maps;
823+ }
824+
825+ prog = bpf_program__next(NULL, obj);
826+ if (!prog) {
827+ p_err("object file doesn't contain any bpf program");
828+ goto err_close_obj;
829+ }
830+
831+ bpf_program__set_ifindex(prog, ifindex);
832+ if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
833+ const char *sec_name = bpf_program__title(prog, false);
834+
835+ err = libbpf_prog_type_by_name(sec_name, &attr.prog_type,
836+ &expected_attach_type);
837+ if (err < 0) {
838+ p_err("failed to guess program type based on section name %s\n",
839+ sec_name);
840+ goto err_close_obj;
841+ }
842+ }
843+ bpf_program__set_type(prog, attr.prog_type);
844+ bpf_program__set_expected_attach_type(prog, expected_attach_type);
845+
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) {
877+ if (!bpf_map__is_offload_neutral(map))
878+ bpf_map__set_ifindex(map, ifindex);
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+
902+ err = bpf_object__load(obj);
903+ if (err) {
904+ p_err("failed to load object file");
905+ goto err_close_obj;
693906 }
694907
695− if (do_pin_fd(prog_fd, argv[1]))
908+ if (do_pin_fd(bpf_program__fd(prog), pinfile))
696909 goto err_close_obj;
697910
698911 if (json_output)
699912 jsonw_null(json_wtr);
700913
701914 bpf_object__close(obj);
915+ for (i = 0; i < old_map_fds; i++)
916+ close(map_replace[i].fd);
917+ free(map_replace);
702918
703919 return 0;
704920
705921 err_close_obj:
706922 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);
707927 return -1;
708928 }
709929
@@ -719,10 +939,19 @@ static int do_help(int argc, char **argv) · 9 unmodified lines
719939 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
720940 " %s %s dump jited PROG [{ file FILE | opcodes }]\n"
721941 " %s %s pin PROG FILE\n"
722− " %s %s load OBJ FILE\n"
942+ " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n"
943+ " [map { idx IDX | name NAME } MAP]\n"
723944 " %s %s help\n"
724945 "\n"
946+ " " HELP_SPEC_MAP "\n"
725947 " " HELP_SPEC_PROGRAM "\n"
948+ " TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
949+ " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
950+ " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
951+ " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
952+ " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
953+ " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
954+ " cgroup/sendmsg4 | cgroup/sendmsg6 }\n"
726955 " " HELP_SPEC_OPTIONS "\n"
727956 "",
728957 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
tools/bpf/bpftool/xlated_dumper.c+3−3
@@ -35,6 +35,7 @@ · 34 unmodified lines
3535 * POSSIBILITY OF SUCH DAMAGE.
3636 */
3737
38+#define _GNU_SOURCE
3839 #include <stdarg.h>
3940 #include <stdio.h>
4041 #include <stdlib.h>
@@ -66,9 +67,8 @@ void kernel_syms_load(struct dump_data *dd) · 25 unmodified lines
6667 while (!feof(fp)) {
6768 if (!fgets(buff, sizeof(buff), fp))
6869 break;
69− tmp = realloc(dd->sym_mapping,
70− (dd->sym_count + 1) *
71− sizeof(*dd->sym_mapping));
70+ tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1,
71+ sizeof(*dd->sym_mapping));
7272 if (!tmp) {
7373 out:
7474 free(dd->sym_mapping);
tools/build/feature/Makefile+4−0
@@ -14,6 +14,7 @@ FILES= \ · 13 unmodified lines
1414 test-libaudit.bin \
1515 test-libbfd.bin \
1616 test-disassembler-four-args.bin \
17+ test-reallocarray.bin \
1718 test-liberty.bin \
1819 test-liberty-z.bin \
1920 test-cplus-demangle.bin \
@@ -204,6 +205,9 @@ $(OUTPUT)test-libbfd.bin: · 184 unmodified lines
204205 $(OUTPUT)test-disassembler-four-args.bin:
205206 $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
206207
208+$(OUTPUT)test-reallocarray.bin:
209+ $(BUILD)
210+
207211 $(OUTPUT)test-liberty.bin:
208212 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
209213
tools/build/feature/test-reallocarray.c+8−0
@@ -0,0 +1,8 @@
1+// SPDX-License-Identifier: GPL-2.0
2+#define _GNU_SOURCE
3+#include <stdlib.h>
4+
5+int main(void)
6+{
7+ return !!reallocarray(NULL, 1, 1);
8+}
tools/include/linux/compiler-gcc.h+4−0
@@ -36,3 +36,7 @@ · 35 unmodified lines
3636 #endif
3737 #define __printf(a, b) __attribute__((format(printf, a, b)))
3838 #define __scanf(a, b) __attribute__((format(scanf, a, b)))
39+
40+#if GCC_VERSION >= 50100
41+#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
42+#endif
tools/include/linux/overflow.h+278−0
@@ -0,0 +1,278 @@
1+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
2+#ifndef __LINUX_OVERFLOW_H
3+#define __LINUX_OVERFLOW_H
4+
5+#include <linux/compiler.h>
6+
7+/*
8+ * In the fallback code below, we need to compute the minimum and
9+ * maximum values representable in a given type. These macros may also
10+ * be useful elsewhere, so we provide them outside the
11+ * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block.
12+ *
13+ * It would seem more obvious to do something like
14+ *
15+ * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
16+ * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
17+ *
18+ * Unfortunately, the middle expressions, strictly speaking, have
19+ * undefined behaviour, and at least some versions of gcc warn about
20+ * the type_max expression (but not if -fsanitize=undefined is in
21+ * effect; in that case, the warning is deferred to runtime...).
22+ *
23+ * The slightly excessive casting in type_min is to make sure the
24+ * macros also produce sensible values for the exotic type _Bool. [The
25+ * overflow checkers only almost work for _Bool, but that's
26+ * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
27+ * _Bools. Besides, the gcc builtins don't allow _Bool* as third
28+ * argument.]
29+ *
30+ * Idea stolen from
31+ * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
32+ * credit to Christian Biere.
33+ */
34+#define is_signed_type(type) (((type)(-1)) < (type)1)
35+#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
36+#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
37+#define type_min(T) ((T)((T)-type_max(T)-(T)1))
38+
39+
40+#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
41+/*
42+ * For simplicity and code hygiene, the fallback code below insists on
43+ * a, b and *d having the same type (similar to the min() and max()
44+ * macros), whereas gcc's type-generic overflow checkers accept
45+ * different types. Hence we don't just make check_add_overflow an
46+ * alias for __builtin_add_overflow, but add type checks similar to
47+ * below.
48+ */
49+#define check_add_overflow(a, b, d) ({ \
50+ typeof(a) __a = (a); \
51+ typeof(b) __b = (b); \
52+ typeof(d) __d = (d); \
53+ (void) (&__a == &__b); \
54+ (void) (&__a == __d); \
55+ __builtin_add_overflow(__a, __b, __d); \
56+})
57+
58+#define check_sub_overflow(a, b, d) ({ \
59+ typeof(a) __a = (a); \
60+ typeof(b) __b = (b); \
61+ typeof(d) __d = (d); \
62+ (void) (&__a == &__b); \
63+ (void) (&__a == __d); \
64+ __builtin_sub_overflow(__a, __b, __d); \
65+})
66+
67+#define check_mul_overflow(a, b, d) ({ \
68+ typeof(a) __a = (a); \
69+ typeof(b) __b = (b); \
70+ typeof(d) __d = (d); \
71+ (void) (&__a == &__b); \
72+ (void) (&__a == __d); \
73+ __builtin_mul_overflow(__a, __b, __d); \
74+})
75+
76+#else
77+
78+
79+/* Checking for unsigned overflow is relatively easy without causing UB. */
80+#define __unsigned_add_overflow(a, b, d) ({ \
81+ typeof(a) __a = (a); \
82+ typeof(b) __b = (b); \
83+ typeof(d) __d = (d); \
84+ (void) (&__a == &__b); \
85+ (void) (&__a == __d); \
86+ *__d = __a + __b; \
87+ *__d < __a; \
88+})
89+#define __unsigned_sub_overflow(a, b, d) ({ \
90+ typeof(a) __a = (a); \
91+ typeof(b) __b = (b); \
92+ typeof(d) __d = (d); \
93+ (void) (&__a == &__b); \
94+ (void) (&__a == __d); \
95+ *__d = __a - __b; \
96+ __a < __b; \
97+})
98+/*
99+ * If one of a or b is a compile-time constant, this avoids a division.
100+ */
101+#define __unsigned_mul_overflow(a, b, d) ({ \
102+ typeof(a) __a = (a); \
103+ typeof(b) __b = (b); \
104+ typeof(d) __d = (d); \
105+ (void) (&__a == &__b); \
106+ (void) (&__a == __d); \
107+ *__d = __a * __b; \
108+ __builtin_constant_p(__b) ? \
109+ __b > 0 && __a > type_max(typeof(__a)) / __b : \
110+ __a > 0 && __b > type_max(typeof(__b)) / __a; \
111+})
112+
113+/*
114+ * For signed types, detecting overflow is much harder, especially if
115+ * we want to avoid UB. But the interface of these macros is such that
116+ * we must provide a result in *d, and in fact we must produce the
117+ * result promised by gcc's builtins, which is simply the possibly
118+ * wrapped-around value. Fortunately, we can just formally do the
119+ * operations in the widest relevant unsigned type (u64) and then
120+ * truncate the result - gcc is smart enough to generate the same code
121+ * with and without the (u64) casts.
122+ */
123+
124+/*
125+ * Adding two signed integers can overflow only if they have the same
126+ * sign, and overflow has happened iff the result has the opposite
127+ * sign.
128+ */
129+#define __signed_add_overflow(a, b, d) ({ \
130+ typeof(a) __a = (a); \
131+ typeof(b) __b = (b); \
132+ typeof(d) __d = (d); \
133+ (void) (&__a == &__b); \
134+ (void) (&__a == __d); \
135+ *__d = (u64)__a + (u64)__b; \
136+ (((~(__a ^ __b)) & (*__d ^ __a)) \
137+ & type_min(typeof(__a))) != 0; \
138+})
139+
140+/*
141+ * Subtraction is similar, except that overflow can now happen only
142+ * when the signs are opposite. In this case, overflow has happened if
143+ * the result has the opposite sign of a.
144+ */
145+#define __signed_sub_overflow(a, b, d) ({ \
146+ typeof(a) __a = (a); \
147+ typeof(b) __b = (b); \
148+ typeof(d) __d = (d); \
149+ (void) (&__a == &__b); \
150+ (void) (&__a == __d); \
151+ *__d = (u64)__a - (u64)__b; \
152+ ((((__a ^ __b)) & (*__d ^ __a)) \
153+ & type_min(typeof(__a))) != 0; \
154+})
155+
156+/*
157+ * Signed multiplication is rather hard. gcc always follows C99, so
158+ * division is truncated towards 0. This means that we can write the
159+ * overflow check like this:
160+ *
161+ * (a > 0 && (b > MAX/a || b < MIN/a)) ||
162+ * (a < -1 && (b > MIN/a || b < MAX/a) ||
163+ * (a == -1 && b == MIN)
164+ *
165+ * The redundant casts of -1 are to silence an annoying -Wtype-limits
166+ * (included in -Wextra) warning: When the type is u8 or u16, the
167+ * __b_c_e in check_mul_overflow obviously selects
168+ * __unsigned_mul_overflow, but unfortunately gcc still parses this
169+ * code and warns about the limited range of __b.
170+ */
171+
172+#define __signed_mul_overflow(a, b, d) ({ \
173+ typeof(a) __a = (a); \
174+ typeof(b) __b = (b); \
175+ typeof(d) __d = (d); \
176+ typeof(a) __tmax = type_max(typeof(a)); \
177+ typeof(a) __tmin = type_min(typeof(a)); \
178+ (void) (&__a == &__b); \
179+ (void) (&__a == __d); \
180+ *__d = (u64)__a * (u64)__b; \
181+ (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \
182+ (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \
183+ (__b == (typeof(__b))-1 && __a == __tmin); \
184+})
185+
186+
187+#define check_add_overflow(a, b, d) \
188+ __builtin_choose_expr(is_signed_type(typeof(a)), \
189+ __signed_add_overflow(a, b, d), \
190+ __unsigned_add_overflow(a, b, d))
191+
192+#define check_sub_overflow(a, b, d) \
193+ __builtin_choose_expr(is_signed_type(typeof(a)), \
194+ __signed_sub_overflow(a, b, d), \
195+ __unsigned_sub_overflow(a, b, d))
196+
197+#define check_mul_overflow(a, b, d) \
198+ __builtin_choose_expr(is_signed_type(typeof(a)), \
199+ __signed_mul_overflow(a, b, d), \
200+ __unsigned_mul_overflow(a, b, d))
201+
202+
203+#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
204+
205+/**
206+ * array_size() - Calculate size of 2-dimensional array.
207+ *
208+ * @a: dimension one
209+ * @b: dimension two
210+ *
211+ * Calculates size of 2-dimensional array: @a * @b.
212+ *
213+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
214+ * overflow.
215+ */
216+static inline __must_check size_t array_size(size_t a, size_t b)
217+{
218+ size_t bytes;
219+
220+ if (check_mul_overflow(a, b, &bytes))
221+ return SIZE_MAX;
222+
223+ return bytes;
224+}
225+
226+/**
227+ * array3_size() - Calculate size of 3-dimensional array.
228+ *
229+ * @a: dimension one
230+ * @b: dimension two
231+ * @c: dimension three
232+ *
233+ * Calculates size of 3-dimensional array: @a * @b * @c.
234+ *
235+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
236+ * overflow.
237+ */
238+static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
239+{
240+ size_t bytes;
241+
242+ if (check_mul_overflow(a, b, &bytes))
243+ return SIZE_MAX;
244+ if (check_mul_overflow(bytes, c, &bytes))
245+ return SIZE_MAX;
246+
247+ return bytes;
248+}
249+
250+static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
251+{
252+ size_t bytes;
253+
254+ if (check_mul_overflow(n, size, &bytes))
255+ return SIZE_MAX;
256+ if (check_add_overflow(bytes, c, &bytes))
257+ return SIZE_MAX;
258+
259+ return bytes;
260+}
261+
262+/**
263+ * struct_size() - Calculate size of structure with trailing array.
264+ * @p: Pointer to the structure.
265+ * @member: Name of the array member.
266+ * @n: Number of elements in the array.
267+ *
268+ * Calculates size of memory needed for structure @p followed by an
269+ * array of @n @member elements.
270+ *
271+ * Return: number of bytes needed or SIZE_MAX on overflow.
272+ */
273+#define struct_size(p, member, n) \
274+ __ab_c_size(n, \
275+ sizeof(*(p)->member) + __must_be_array((p)->member),\
276+ sizeof(*(p)))
277+
278+#endif /* __LINUX_OVERFLOW_H */
tools/include/tools/libc_compat.h+20−0
@@ -0,0 +1,20 @@
1+// SPDX-License-Identifier: GPL-2.0+
2+/* Copyright (C) 2018 Netronome Systems, Inc. */
3+
4+#ifndef __TOOLS_LIBC_COMPAT_H
5+#define __TOOLS_LIBC_COMPAT_H
6+
7+#include <stdlib.h>
8+#include <linux/overflow.h>
9+
10+#ifdef COMPAT_NEED_REALLOCARRAY
11+static inline void *reallocarray(void *ptr, size_t nmemb, size_t size)
12+{
13+ size_t bytes;
14+
15+ if (unlikely(check_mul_overflow(nmemb, size, &bytes)))
16+ return NULL;
17+ return realloc(ptr, bytes);
18+}
19+#endif
20+#endif
tools/lib/bpf/Build+1−1
@@ -1 +1 @@
1−libbpf-y := libbpf.o bpf.o nlattr.o btf.o
1+libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o
tools/lib/bpf/Makefile+5−1
@@ -66,7 +66,7 @@ ifndef VERBOSE · 65 unmodified lines
6666 endif
6767
6868 FEATURE_USER = .libbpf
69−FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf
69+FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf reallocarray
7070 FEATURE_DISPLAY = libelf bpf
7171
7272 INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf
@@ -120,6 +120,10 @@ ifeq ($(feature-libelf-getphdrnum), 1) · 47 unmodified lines
120120 override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
121121 endif
122122
123+ifeq ($(feature-reallocarray), 0)
124+ override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
125+endif
126+
123127 # Append required CFLAGS
124128 override CFLAGS += $(EXTRA_WARNINGS)
125129 override CFLAGS += -Werror -Wall
tools/lib/bpf/libbpf.c+111−77
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 * License along with this program; if not, see <http://www.gnu.org/licenses>
2323 */
2424
25+#define _GNU_SOURCE
2526 #include <stdlib.h>
2627 #include <stdio.h>
2728 #include <stdarg.h>
@@ -41,6 +42,7 @@ · 13 unmodified lines
4142 #include <sys/stat.h>
4243 #include <sys/types.h>
4344 #include <sys/vfs.h>
45+#include <tools/libc_compat.h>
4446 #include <libelf.h>
4547 #include <gelf.h>
4648
@@ -95,54 +97,6 @@ void libbpf_set_print(libbpf_print_fn_t warn, · 48 unmodified lines
9597
9698 #define STRERR_BUFSIZE 128
9799
98−#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
99−#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
100−#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
101−
102−static const char *libbpf_strerror_table[NR_ERRNO] = {
103− [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
104− [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
105− [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
106− [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
107− [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
108− [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
109− [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
110− [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
111− [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
112− [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
113− [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
114− [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
115−};
116−
117−int libbpf_strerror(int err, char *buf, size_t size)
118−{
119− if (!buf || !size)
120− return -1;
121−
122− err = err > 0 ? err : -err;
123−
124− if (err < __LIBBPF_ERRNO__START) {
125− int ret;
126−
127− ret = strerror_r(err, buf, size);
128− buf[size - 1] = '\0';
129− return ret;
130− }
131−
132− if (err < __LIBBPF_ERRNO__END) {
133− const char *msg;
134−
135− msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
136− snprintf(buf, size, "%s", msg);
137− buf[size - 1] = '\0';
138− return 0;
139− }
140−
141− snprintf(buf, size, "Unknown libbpf error %d", err);
142− buf[size - 1] = '\0';
143− return -1;
144−}
145−
146100 #define CHECK_ERR(action, err, out) do { \
147101 err = action; \
148102 if (err) \
@@ -369,7 +323,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, · 220 unmodified lines
369323 progs = obj->programs;
370324 nr_progs = obj->nr_programs;
371325
372− progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1));
326+ progs = reallocarray(progs, nr_progs + 1, sizeof(progs[0]));
373327 if (!progs) {
374328 /*
375329 * In this case the original obj->programs
@@ -870,8 +824,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) · 494 unmodified lines
870824 continue;
871825 }
872826
873− reloc = realloc(reloc,
874− sizeof(*obj->efile.reloc) * nr_reloc);
827+ reloc = reallocarray(reloc, nr_reloc,
828+ sizeof(*obj->efile.reloc));
875829 if (!reloc) {
876830 pr_warning("realloc failed\n");
877831 err = -ENOMEM;
@@ -1081,6 +1035,53 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) · 203 unmodified lines
10811035 return 0;
10821036 }
10831037
1038+int bpf_map__reuse_fd(struct bpf_map *map, int fd)
1039+{
1040+ struct bpf_map_info info = {};
1041+ __u32 len = sizeof(info);
1042+ int new_fd, err;
1043+ char *new_name;
1044+
1045+ err = bpf_obj_get_info_by_fd(fd, &info, &len);
1046+ if (err)
1047+ return err;
1048+
1049+ new_name = strdup(info.name);
1050+ if (!new_name)
1051+ return -errno;
1052+
1053+ new_fd = open("/", O_RDONLY | O_CLOEXEC);
1054+ if (new_fd < 0)
1055+ goto err_free_new_name;
1056+
1057+ new_fd = dup3(fd, new_fd, O_CLOEXEC);
1058+ if (new_fd < 0)
1059+ goto err_close_new_fd;
1060+
1061+ err = zclose(map->fd);
1062+ if (err)
1063+ goto err_close_new_fd;
1064+ free(map->name);
1065+
1066+ map->fd = new_fd;
1067+ map->name = new_name;
1068+ map->def.type = info.type;
1069+ map->def.key_size = info.key_size;
1070+ map->def.value_size = info.value_size;
1071+ map->def.max_entries = info.max_entries;
1072+ map->def.map_flags = info.map_flags;
1073+ map->btf_key_type_id = info.btf_key_type_id;
1074+ map->btf_value_type_id = info.btf_value_type_id;
1075+
1076+ return 0;
1077+
1078+err_close_new_fd:
1079+ close(new_fd);
1080+err_free_new_name:
1081+ free(new_name);
1082+ return -errno;
1083+}
1084+
10841085 static int
10851086 bpf_object__create_maps(struct bpf_object *obj)
10861087 {
@@ -1093,6 +1094,12 @@ bpf_object__create_maps(struct bpf_object *obj) · 6 unmodified lines
10931094 struct bpf_map_def *def = &map->def;
10941095 int *pfd = &map->fd;
10951096
1097+ if (map->fd >= 0) {
1098+ pr_debug("skip map create (preset) %s: fd=%d\n",
1099+ map->name, map->fd);
1100+ continue;
1101+ }
1102+
10961103 create_attr.name = map->name;
10971104 create_attr.map_ifindex = map->map_ifindex;
10981105 create_attr.map_type = def->type;
@@ -1163,7 +1170,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, · 64 unmodified lines
11631170 return -LIBBPF_ERRNO__RELOC;
11641171 }
11651172 new_cnt = prog->insns_cnt + text->insns_cnt;
1166− new_insn = realloc(prog->insns, new_cnt * sizeof(*insn));
1173+ new_insn = reallocarray(prog->insns, new_cnt, sizeof(*insn));
11671174 if (!new_insn) {
11681175 pr_warning("oom in prog realloc\n");
11691176 return -ENOMEM;
@@ -1520,15 +1527,26 @@ out: · 350 unmodified lines
15201527 return ERR_PTR(err);
15211528 }
15221529
1523−struct bpf_object *bpf_object__open(const char *path)
1530+struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
15241531 {
15251532 /* param validation */
1526− if (!path)
1533+ if (!attr->file)
15271534 return NULL;
15281535
1529− pr_debug("loading %s\n", path);
1536+ pr_debug("loading %s\n", attr->file);
1537+
1538+ return __bpf_object__open(attr->file, NULL, 0,
1539+ bpf_prog_type__needs_kver(attr->prog_type));
1540+}
1541+
1542+struct bpf_object *bpf_object__open(const char *path)
1543+{
1544+ struct bpf_object_open_attr attr = {
1545+ .file = path,
1546+ .prog_type = BPF_PROG_TYPE_UNSPEC,
1547+ };
15301548
1531− return __bpf_object__open(path, NULL, 0, true);
1549+ return bpf_object__open_xattr(&attr);
15321550 }
15331551
15341552 struct bpf_object *bpf_object__open_buffer(void *obj_buf,
@@ -2081,23 +2099,31 @@ static const struct { · 546 unmodified lines
20812099 #undef BPF_S_PROG_SEC
20822100 #undef BPF_SA_PROG_SEC
20832101
2084−static int bpf_program__identify_section(struct bpf_program *prog)
2102+int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
2103+ enum bpf_attach_type *expected_attach_type)
20852104 {
20862105 int i;
20872106
2088− if (!prog->section_name)
2089− goto err;
2090−
2091− for (i = 0; i < ARRAY_SIZE(section_names); i++)
2092− if (strncmp(prog->section_name, section_names[i].sec,
2093− section_names[i].len) == 0)
2094− return i;
2107+ if (!name)
2108+ return -EINVAL;
20952109
2096−err:
2097− pr_warning("failed to guess program type based on section name %s\n",
2098− prog->section_name);
2110+ for (i = 0; i < ARRAY_SIZE(section_names); i++) {
2111+ if (strncmp(name, section_names[i].sec, section_names[i].len))
2112+ continue;
2113+ *prog_type = section_names[i].prog_type;
2114+ *expected_attach_type = section_names[i].expected_attach_type;
2115+ return 0;
2116+ }
2117+ return -EINVAL;
2118+}
20992119
2100− return -1;
2120+static int
2121+bpf_program__identify_section(struct bpf_program *prog,
2122+ enum bpf_prog_type *prog_type,
2123+ enum bpf_attach_type *expected_attach_type)
2124+{
2125+ return libbpf_prog_type_by_name(prog->section_name, prog_type,
2126+ expected_attach_type);
21012127 }
21022128
21032129 int bpf_map__fd(struct bpf_map *map)
@@ -2146,6 +2172,11 @@ void *bpf_map__priv(struct bpf_map *map) · 42 unmodified lines
21462172 return map ? map->priv : ERR_PTR(-EINVAL);
21472173 }
21482174
2175+bool bpf_map__is_offload_neutral(struct bpf_map *map)
2176+{
2177+ return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY;
2178+}
2179+
21492180 void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
21502181 {
21512182 map->map_ifindex = ifindex;
@@ -2225,12 +2256,15 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type, · 73 unmodified lines
22252256 int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
22262257 struct bpf_object **pobj, int *prog_fd)
22272258 {
2259+ struct bpf_object_open_attr open_attr = {
2260+ .file = attr->file,
2261+ .prog_type = attr->prog_type,
2262+ };
22282263 struct bpf_program *prog, *first_prog = NULL;
22292264 enum bpf_attach_type expected_attach_type;
22302265 enum bpf_prog_type prog_type;
22312266 struct bpf_object *obj;
22322267 struct bpf_map *map;
2233− int section_idx;
22342268 int err;
22352269
22362270 if (!attr)
@@ -2238,8 +2272,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, · 1 unmodified line
22382272 if (!attr->file)
22392273 return -EINVAL;
22402274
2241− obj = __bpf_object__open(attr->file, NULL, 0,
2242− bpf_prog_type__needs_kver(attr->prog_type));
2275+ obj = bpf_object__open_xattr(&open_attr);
22432276 if (IS_ERR_OR_NULL(obj))
22442277 return -ENOENT;
22452278
@@ -2252,14 +2285,14 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, · 6 unmodified lines
22522285 prog->prog_ifindex = attr->ifindex;
22532286 expected_attach_type = attr->expected_attach_type;
22542287 if (prog_type == BPF_PROG_TYPE_UNSPEC) {
2255− section_idx = bpf_program__identify_section(prog);
2256− if (section_idx < 0) {
2288+ err = bpf_program__identify_section(prog, &prog_type,
2289+ &expected_attach_type);
2290+ if (err < 0) {
2291+ pr_warning("failed to guess program type based on section name %s\n",
2292+ prog->section_name);
22572293 bpf_object__close(obj);
22582294 return -EINVAL;
22592295 }
2260− prog_type = section_names[section_idx].prog_type;
2261− expected_attach_type =
2262− section_names[section_idx].expected_attach_type;
22632296 }
22642297
22652298 bpf_program__set_type(prog, prog_type);
@@ -2271,7 +2304,8 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, · 5 unmodified lines
22712304 }
22722305
22732306 bpf_map__for_each(map, obj) {
2274− map->map_ifindex = attr->ifindex;
2307+ if (!bpf_map__is_offload_neutral(map))
2308+ map->map_ifindex = attr->ifindex;
22752309 }
22762310
22772311 if (!first_prog) {
tools/lib/bpf/libbpf.h+11−0
@@ -66,7 +66,13 @@ void libbpf_set_print(libbpf_print_fn_t warn, · 65 unmodified lines
6666 /* Hide internal to user */
6767 struct bpf_object;
6868
69+struct bpf_object_open_attr {
70+ const char *file;
71+ enum bpf_prog_type prog_type;
72+};
73+
6974 struct bpf_object *bpf_object__open(const char *path);
75+struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr);
7076 struct bpf_object *bpf_object__open_buffer(void *obj_buf,
7177 size_t obj_buf_sz,
7278 const char *name);
@@ -92,6 +98,9 @@ int bpf_object__set_priv(struct bpf_object *obj, void *priv, · 19 unmodified lines
9298 bpf_object_clear_priv_t clear_priv);
9399 void *bpf_object__priv(struct bpf_object *prog);
94100
101+int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
102+ enum bpf_attach_type *expected_attach_type);
103+
95104 /* Accessors of bpf_program */
96105 struct bpf_program;
97106 struct bpf_program *bpf_program__next(struct bpf_program *prog,
@@ -252,6 +261,8 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); · 154 unmodified lines
252261 int bpf_map__set_priv(struct bpf_map *map, void *priv,
253262 bpf_map_clear_priv_t clear_priv);
254263 void *bpf_map__priv(struct bpf_map *map);
264+int bpf_map__reuse_fd(struct bpf_map *map, int fd);
265+bool bpf_map__is_offload_neutral(struct bpf_map *map);
255266 void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
256267 int bpf_map__pin(struct bpf_map *map, const char *path);
257268
tools/lib/bpf/libbpf_errno.c+74−0
@@ -0,0 +1,74 @@
1+// SPDX-License-Identifier: LGPL-2.1
2+
3+/*
4+ * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
5+ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
6+ * Copyright (C) 2015 Huawei Inc.
7+ * Copyright (C) 2017 Nicira, Inc.
8+ *
9+ * This program is free software; you can redistribute it and/or
10+ * modify it under the terms of the GNU Lesser General Public
11+ * License as published by the Free Software Foundation;
12+ * version 2.1 of the License (not later!)
13+ *
14+ * This program is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ * GNU Lesser General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU Lesser General Public
20+ * License along with this program; if not, see <http://www.gnu.org/licenses>
21+ */
22+
23+#include <stdio.h>
24+#include <string.h>
25+
26+#include "libbpf.h"
27+
28+#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
29+#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
30+#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
31+
32+static const char *libbpf_strerror_table[NR_ERRNO] = {
33+ [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
34+ [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
35+ [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
36+ [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
37+ [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
38+ [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
39+ [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
40+ [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
41+ [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
42+ [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
43+ [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
44+ [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
45+};
46+
47+int libbpf_strerror(int err, char *buf, size_t size)
48+{
49+ if (!buf || !size)
50+ return -1;
51+
52+ err = err > 0 ? err : -err;
53+
54+ if (err < __LIBBPF_ERRNO__START) {
55+ int ret;
56+
57+ ret = strerror_r(err, buf, size);
58+ buf[size - 1] = '\0';
59+ return ret;
60+ }
61+
62+ if (err < __LIBBPF_ERRNO__END) {
63+ const char *msg;
64+
65+ msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
66+ snprintf(buf, size, "%s", msg);
67+ buf[size - 1] = '\0';
68+ return 0;
69+ }
70+
71+ snprintf(buf, size, "Unknown libbpf error %d", err);
72+ buf[size - 1] = '\0';
73+ return -1;
74+}
tools/testing/selftests/bpf/test_offload.py+5−5
@@ -547,11 +547,11 @@ def check_extack(output, reference, args): · 546 unmodified lines
547547 if skip_extack:
548548 return
549549 lines = output.split("\n")
550− comp = len(lines) >= 2 and lines[1] == reference
550+ comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
551551 fail(not comp, "Missing or incorrect netlink extack message")
552552
553553 def check_extack_nsim(output, reference, args):
554− check_extack(output, "Error: netdevsim: " + reference, args)
554+ check_extack(output, "netdevsim: " + reference, args)
555555
556556 def check_no_extack(res, needle):
557557 fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
@@ -654,7 +654,7 @@ try: · 96 unmodified lines
654654 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
655655 fail=False, include_stderr=True)
656656 fail(ret == 0, "TC filter loaded without enabling TC offloads")
657− check_extack(err, "Error: TC offload is disabled on net device.", args)
657+ check_extack(err, "TC offload is disabled on net device.", args)
658658 sim.wait_for_flush()
659659
660660 sim.set_ethtool_tc_offloads(True)
@@ -694,7 +694,7 @@ try: · 33 unmodified lines
694694 skip_sw=True,
695695 fail=False, include_stderr=True)
696696 fail(ret == 0, "Offloaded a filter to chain other than 0")
697− check_extack(err, "Error: Driver supports only offload of chain 0.", args)
697+ check_extack(err, "Driver supports only offload of chain 0.", args)
698698 sim.tc_flush_filters()
699699
700700 start_test("Test TC replace...")
@@ -830,7 +830,7 @@ try: · 129 unmodified lines
830830 check_extack_nsim(err, "program loaded with different flags.", args)
831831 ret, _, err = sim.unset_xdp("", force=True,
832832 fail=False, include_stderr=True)
833− fail(ret == 0, "Removed program with a bad mode mode")
833+ fail(ret == 0, "Removed program with a bad mode")
834834 check_extack_nsim(err, "program loaded with different flags.", args)
835835
836836 start_test("Test MTU restrictions...")