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
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*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* }
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
31 41
32DESCRIPTION42DESCRIPTION
33===========43===========
@@ -64,8 +74,19 @@ DESCRIPTION · 30 unmodified lines
64 74
65 Note: *FILE* must be located in *bpffs* mount.75 Note: *FILE* must be located in *bpffs* mount.
66 76
67 **bpftool prog load** *OBJ* *FILE*77 **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
68 Load bpf program from binary *OBJ* and pin as *FILE*.78 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).
69 90
70 Note: *FILE* must be located in *bpffs* mount.91 Note: *FILE* must be located in *bpffs* mount.
71 92
@@ -159,6 +180,14 @@ EXAMPLES · 87 unmodified lines
159 mov %rbx,0x0(%rbp)180 mov %rbx,0x0(%rbp)
160 48 89 5d 00181 48 89 5d 00
161 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|
162 191
163SEE ALSO192SEE ALSO
164========193========
tools/bpf/bpftool/Makefile+5−1
@@ -52,7 +52,7 @@ INSTALL ?= install · 51 unmodified lines
52RM ?= rm -f52RM ?= rm -f
53 53
54FEATURE_USER = .bpftool54FEATURE_USER = .bpftool
55FEATURE_TESTS = libbfd disassembler-four-args55FEATURE_TESTS = libbfd disassembler-four-args reallocarray
56FEATURE_DISPLAY = libbfd disassembler-four-args56FEATURE_DISPLAY = libbfd disassembler-four-args
57 57
58check_feat := 158check_feat := 1
@@ -75,6 +75,10 @@ ifeq ($(feature-disassembler-four-args), 1) · 16 unmodified lines
75CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE75CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
76endif76endif
77 77
78ifeq ($(feature-reallocarray), 0)
79CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
80endif
81
78include $(wildcard $(OUTPUT)*.d)82include $(wildcard $(OUTPUT)*.d)
79 83
80all: $(OUTPUT)bpftool84all: $(OUTPUT)bpftool
tools/bpf/bpftool/bash-completion/bpftool+88−8
@@ -99,6 +99,35 @@ _bpftool_get_prog_tags() · 98 unmodified lines
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
125_sysfs_get_netdevs()
126{
127 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
128 "$cur" ) )
129}
130
102# For bpftool map update: retrieve type of the map to update.131# For bpftool map update: retrieve type of the map to update.
103_bpftool_map_update_map_type()132_bpftool_map_update_map_type()
104{133{
@@ -214,12 +243,14 @@ _bpftool() · 109 unmodified lines
214 # Completion depends on object and command in use243 # Completion depends on object and command in use
215 case $object in244 case $object in
216 prog)245 prog)
217 case $prev in246 if [[ $command != "load" ]]; then
218 id)247 case $prev in
219 _bpftool_get_prog_ids248 id)
220 return 0249 _bpftool_get_prog_ids
221 ;;250 return 0
222 esac251 ;;
252 esac
253 fi
223 254
224 local PROG_TYPE='id pinned tag'255 local PROG_TYPE='id pinned tag'
225 case $command in256 case $command in
@@ -262,8 +293,57 @@ _bpftool() · 36 unmodified lines
262 return 0293 return 0
263 ;;294 ;;
264 load)295 load)
265 _filedir296 local obj
266 return 0297
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
267 ;;347 ;;
268 *)348 *)
269 [[ $prev == $object ]] && \349 [[ $prev == $object ]] && \
tools/bpf/bpftool/main.h+19−0
@@ -42,6 +42,7 @@ · 41 unmodified lines
42#include <linux/compiler.h>42#include <linux/compiler.h>
43#include <linux/kernel.h>43#include <linux/kernel.h>
44#include <linux/hashtable.h>44#include <linux/hashtable.h>
45#include <tools/libc_compat.h>
45 46
46#include "json_writer.h"47#include "json_writer.h"
47 48
@@ -50,6 +51,21 @@ · 2 unmodified lines
50#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })51#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })
51#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })52#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
52#define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; })53#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 })
53 69
54#define ERR_MAX_LEN 102470#define ERR_MAX_LEN 1024
55 71
@@ -59,6 +75,8 @@ · 3 unmodified lines
59 "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"75 "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
60#define HELP_SPEC_OPTIONS \76#define HELP_SPEC_OPTIONS \
61 "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 }"
62 80
63enum bpf_obj_type {81enum bpf_obj_type {
64 BPF_OBJ_UNKNOWN,82 BPF_OBJ_UNKNOWN,
@@ -120,6 +138,7 @@ int do_cgroup(int argc, char **arg); · 55 unmodified lines
120int do_perf(int argc, char **arg);138int do_perf(int argc, char **arg);
121 139
122int prog_parse_fd(int *argc, char ***argv);140int prog_parse_fd(int *argc, char ***argv);
141int map_parse_fd(int *argc, char ***argv);
123int 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);
124 143
125void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,144void 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
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) · 724 unmodified lines
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"
tools/bpf/bpftool/prog.c+237−8
@@ -31,6 +31,7 @@ · 30 unmodified lines
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>
@@ -39,9 +40,12 @@ · 2 unmodified lines
39#include <string.h>40#include <string.h>
40#include <time.h>41#include <time.h>
41#include <unistd.h>42#include <unistd.h>
43#include <net/if.h>
42#include <sys/types.h>44#include <sys/types.h>
43#include <sys/stat.h>45#include <sys/stat.h>
44 46
47#include <linux/err.h>
48
45#include <bpf.h>49#include <bpf.h>
46#include <libbpf.h>50#include <libbpf.h>
47 51
@@ -679,31 +683,247 @@ static int do_pin(int argc, char **argv) · 631 unmodified lines
679 return err;683 return err;
680}684}
681 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
682static int do_load(int argc, char **argv)699static int do_load(int argc, char **argv)
683{700{
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;
684 struct bpf_object *obj;708 struct bpf_object *obj;
685 int prog_fd;709 struct bpf_map *map;
686 710 const char *pinfile;
687 if (argc != 2)711 unsigned int i, j;
688 usage();712 __u32 ifindex = 0;
713 int idx, err;
689 714
690 if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {715 if (!REQ_ARGS(2))
691 p_err("failed to load program");
692 return -1;716 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;
693 }906 }
694 907
695 if (do_pin_fd(prog_fd, argv[1]))908 if (do_pin_fd(bpf_program__fd(prog), pinfile))
696 goto err_close_obj;909 goto err_close_obj;
697 910
698 if (json_output)911 if (json_output)
699 jsonw_null(json_wtr);912 jsonw_null(json_wtr);
700 913
701 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);
702 918
703 return 0;919 return 0;
704 920
705err_close_obj:921err_close_obj:
706 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);
707 return -1;927 return -1;
708}928}
709 929
@@ -719,10 +939,19 @@ static int do_help(int argc, char **argv) · 9 unmodified lines
719 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"939 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
720 " %s %s dump jited PROG [{ file FILE | opcodes }]\n"940 " %s %s dump jited PROG [{ file FILE | opcodes }]\n"
721 " %s %s pin PROG FILE\n"941 " %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"
723 " %s %s help\n"944 " %s %s help\n"
724 "\n"945 "\n"
946 " " HELP_SPEC_MAP "\n"
725 " " HELP_SPEC_PROGRAM "\n"947 " " 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"
726 " " HELP_SPEC_OPTIONS "\n"955 " " HELP_SPEC_OPTIONS "\n"
727 "",956 "",
728 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],957 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
35 * POSSIBILITY OF SUCH DAMAGE.35 * POSSIBILITY OF SUCH DAMAGE.
36 */36 */
37 37
38#define _GNU_SOURCE
38#include <stdarg.h>39#include <stdarg.h>
39#include <stdio.h>40#include <stdio.h>
40#include <stdlib.h>41#include <stdlib.h>
@@ -66,9 +67,8 @@ void kernel_syms_load(struct dump_data *dd) · 25 unmodified lines
66 while (!feof(fp)) {67 while (!feof(fp)) {
67 if (!fgets(buff, sizeof(buff), fp))68 if (!fgets(buff, sizeof(buff), fp))
68 break;69 break;
69 tmp = realloc(dd->sym_mapping,70 tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1,
70 (dd->sym_count + 1) *71 sizeof(*dd->sym_mapping));
71 sizeof(*dd->sym_mapping));
72 if (!tmp) {72 if (!tmp) {
73out:73out:
74 free(dd->sym_mapping);74 free(dd->sym_mapping);
tools/build/feature/Makefile+4−0
@@ -14,6 +14,7 @@ FILES= \ · 13 unmodified lines
14 test-libaudit.bin \14 test-libaudit.bin \
15 test-libbfd.bin \15 test-libbfd.bin \
16 test-disassembler-four-args.bin \16 test-disassembler-four-args.bin \
17 test-reallocarray.bin \
17 test-liberty.bin \18 test-liberty.bin \
18 test-liberty-z.bin \19 test-liberty-z.bin \
19 test-cplus-demangle.bin \20 test-cplus-demangle.bin \
@@ -204,6 +205,9 @@ $(OUTPUT)test-libbfd.bin: · 184 unmodified lines
204$(OUTPUT)test-disassembler-four-args.bin:205$(OUTPUT)test-disassembler-four-args.bin:
205 $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes206 $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
206 207
208$(OUTPUT)test-reallocarray.bin:
209 $(BUILD)
210
207$(OUTPUT)test-liberty.bin:211$(OUTPUT)test-liberty.bin:
208 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty212 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
209 213
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
5int 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
36#endif36#endif
37#define __printf(a, b) __attribute__((format(printf, a, b)))37#define __printf(a, b) __attribute__((format(printf, a, b)))
38#define __scanf(a, b) __attribute__((format(scanf, a, b)))38#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 */
216static 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 */
238static 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
250static 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
11static 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 @@
1libbpf-y := libbpf.o bpf.o nlattr.o btf.o1libbpf-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
66endif66endif
67 67
68FEATURE_USER = .libbpf68FEATURE_USER = .libbpf
69FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf69FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf reallocarray
70FEATURE_DISPLAY = libelf bpf70FEATURE_DISPLAY = libelf bpf
71 71
72INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf72INCLUDES = -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
120 override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT120 override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
121endif121endif
122 122
123ifeq ($(feature-reallocarray), 0)
124 override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
125endif
126
123# Append required CFLAGS127# Append required CFLAGS
124override CFLAGS += $(EXTRA_WARNINGS)128override CFLAGS += $(EXTRA_WARNINGS)
125override CFLAGS += -Werror -Wall129override CFLAGS += -Werror -Wall
tools/lib/bpf/libbpf.c+111−77
@@ -22,6 +22,7 @@ · 21 unmodified lines
22 * License along with this program; if not, see <http://www.gnu.org/licenses>22 * License along with this program; if not, see <http://www.gnu.org/licenses>
23 */23 */
24 24
25#define _GNU_SOURCE
25#include <stdlib.h>26#include <stdlib.h>
26#include <stdio.h>27#include <stdio.h>
27#include <stdarg.h>28#include <stdarg.h>
@@ -41,6 +42,7 @@ · 13 unmodified lines
41#include <sys/stat.h>42#include <sys/stat.h>
42#include <sys/types.h>43#include <sys/types.h>
43#include <sys/vfs.h>44#include <sys/vfs.h>
45#include <tools/libc_compat.h>
44#include <libelf.h>46#include <libelf.h>
45#include <gelf.h>47#include <gelf.h>
46 48
@@ -95,54 +97,6 @@ void libbpf_set_print(libbpf_print_fn_t warn, · 48 unmodified lines
95 97
96#define STRERR_BUFSIZE 12898#define STRERR_BUFSIZE 128
97 99
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
102static 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
117int 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
146#define CHECK_ERR(action, err, out) do { \100#define CHECK_ERR(action, err, out) do { \
147 err = action; \101 err = action; \
148 if (err) \102 if (err) \
@@ -369,7 +323,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, · 220 unmodified lines
369 progs = obj->programs;323 progs = obj->programs;
370 nr_progs = obj->nr_programs;324 nr_progs = obj->nr_programs;
371 325
372 progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1));326 progs = reallocarray(progs, nr_progs + 1, sizeof(progs[0]));
373 if (!progs) {327 if (!progs) {
374 /*328 /*
375 * In this case the original obj->programs329 * In this case the original obj->programs
@@ -870,8 +824,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) · 494 unmodified lines
870 continue;824 continue;
871 }825 }
872 826
873 reloc = realloc(reloc,827 reloc = reallocarray(reloc, nr_reloc,
874 sizeof(*obj->efile.reloc) * nr_reloc);828 sizeof(*obj->efile.reloc));
875 if (!reloc) {829 if (!reloc) {
876 pr_warning("realloc failed\n");830 pr_warning("realloc failed\n");
877 err = -ENOMEM;831 err = -ENOMEM;
@@ -1081,6 +1035,53 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) · 203 unmodified lines
1081 return 0;1035 return 0;
1082}1036}
1083 1037
1038int 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
1078err_close_new_fd:
1079 close(new_fd);
1080err_free_new_name:
1081 free(new_name);
1082 return -errno;
1083}
1084
1084static int1085static int
1085bpf_object__create_maps(struct bpf_object *obj)1086bpf_object__create_maps(struct bpf_object *obj)
1086{1087{
@@ -1093,6 +1094,12 @@ bpf_object__create_maps(struct bpf_object *obj) · 6 unmodified lines
1093 struct bpf_map_def *def = &map->def;1094 struct bpf_map_def *def = &map->def;
1094 int *pfd = &map->fd;1095 int *pfd = &map->fd;
1095 1096
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
1096 create_attr.name = map->name;1103 create_attr.name = map->name;
1097 create_attr.map_ifindex = map->map_ifindex;1104 create_attr.map_ifindex = map->map_ifindex;
1098 create_attr.map_type = def->type;1105 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
1163 return -LIBBPF_ERRNO__RELOC;1170 return -LIBBPF_ERRNO__RELOC;
1164 }1171 }
1165 new_cnt = prog->insns_cnt + text->insns_cnt;1172 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));
1167 if (!new_insn) {1174 if (!new_insn) {
1168 pr_warning("oom in prog realloc\n");1175 pr_warning("oom in prog realloc\n");
1169 return -ENOMEM;1176 return -ENOMEM;
@@ -1520,15 +1527,26 @@ out: · 350 unmodified lines
1520 return ERR_PTR(err);1527 return ERR_PTR(err);
1521}1528}
1522 1529
1523struct bpf_object *bpf_object__open(const char *path)1530struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
1524{1531{
1525 /* param validation */1532 /* param validation */
1526 if (!path)1533 if (!attr->file)
1527 return NULL;1534 return NULL;
1528 1535
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
1542struct 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 };
1530 1548
1531 return __bpf_object__open(path, NULL, 0, true);1549 return bpf_object__open_xattr(&attr);
1532}1550}
1533 1551
1534struct bpf_object *bpf_object__open_buffer(void *obj_buf,1552struct bpf_object *bpf_object__open_buffer(void *obj_buf,
@@ -2081,23 +2099,31 @@ static const struct { · 546 unmodified lines
2081#undef BPF_S_PROG_SEC2099#undef BPF_S_PROG_SEC
2082#undef BPF_SA_PROG_SEC2100#undef BPF_SA_PROG_SEC
2083 2101
2084static int bpf_program__identify_section(struct bpf_program *prog)2102int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
2103 enum bpf_attach_type *expected_attach_type)
2085{2104{
2086 int i;2105 int i;
2087 2106
2088 if (!prog->section_name)2107 if (!name)
2089 goto err;2108 return -EINVAL;
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;
2095 2109
2096err:2110 for (i = 0; i < ARRAY_SIZE(section_names); i++) {
2097 pr_warning("failed to guess program type based on section name %s\n",2111 if (strncmp(name, section_names[i].sec, section_names[i].len))
2098 prog->section_name);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}
2099 2119
2100 return -1;2120static int
2121bpf_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);
2101}2127}
2102 2128
2103int bpf_map__fd(struct bpf_map *map)2129int bpf_map__fd(struct bpf_map *map)
@@ -2146,6 +2172,11 @@ void *bpf_map__priv(struct bpf_map *map) · 42 unmodified lines
2146 return map ? map->priv : ERR_PTR(-EINVAL);2172 return map ? map->priv : ERR_PTR(-EINVAL);
2147}2173}
2148 2174
2175bool bpf_map__is_offload_neutral(struct bpf_map *map)
2176{
2177 return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY;
2178}
2179
2149void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)2180void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
2150{2181{
2151 map->map_ifindex = ifindex;2182 map->map_ifindex = ifindex;
@@ -2225,12 +2256,15 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type, · 73 unmodified lines
2225int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,2256int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
2226 struct bpf_object **pobj, int *prog_fd)2257 struct bpf_object **pobj, int *prog_fd)
2227{2258{
2259 struct bpf_object_open_attr open_attr = {
2260 .file = attr->file,
2261 .prog_type = attr->prog_type,
2262 };
2228 struct bpf_program *prog, *first_prog = NULL;2263 struct bpf_program *prog, *first_prog = NULL;
2229 enum bpf_attach_type expected_attach_type;2264 enum bpf_attach_type expected_attach_type;
2230 enum bpf_prog_type prog_type;2265 enum bpf_prog_type prog_type;
2231 struct bpf_object *obj;2266 struct bpf_object *obj;
2232 struct bpf_map *map;2267 struct bpf_map *map;
2233 int section_idx;
2234 int err;2268 int err;
2235 2269
2236 if (!attr)2270 if (!attr)
@@ -2238,8 +2272,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, · 1 unmodified line
2238 if (!attr->file)2272 if (!attr->file)
2239 return -EINVAL;2273 return -EINVAL;
2240 2274
2241 obj = __bpf_object__open(attr->file, NULL, 0,2275 obj = bpf_object__open_xattr(&open_attr);
2242 bpf_prog_type__needs_kver(attr->prog_type));
2243 if (IS_ERR_OR_NULL(obj))2276 if (IS_ERR_OR_NULL(obj))
2244 return -ENOENT;2277 return -ENOENT;
2245 2278
@@ -2252,14 +2285,14 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, · 6 unmodified lines
2252 prog->prog_ifindex = attr->ifindex;2285 prog->prog_ifindex = attr->ifindex;
2253 expected_attach_type = attr->expected_attach_type;2286 expected_attach_type = attr->expected_attach_type;
2254 if (prog_type == BPF_PROG_TYPE_UNSPEC) {2287 if (prog_type == BPF_PROG_TYPE_UNSPEC) {
2255 section_idx = bpf_program__identify_section(prog);2288 err = bpf_program__identify_section(prog, &prog_type,
2256 if (section_idx < 0) {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);
2257 bpf_object__close(obj);2293 bpf_object__close(obj);
2258 return -EINVAL;2294 return -EINVAL;
2259 }2295 }
2260 prog_type = section_names[section_idx].prog_type;
2261 expected_attach_type =
2262 section_names[section_idx].expected_attach_type;
2263 }2296 }
2264 2297
2265 bpf_program__set_type(prog, prog_type);2298 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
2271 }2304 }
2272 2305
2273 bpf_map__for_each(map, obj) {2306 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;
2275 }2309 }
2276 2310
2277 if (!first_prog) {2311 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
66/* Hide internal to user */66/* Hide internal to user */
67struct bpf_object;67struct bpf_object;
68 68
69struct bpf_object_open_attr {
70 const char *file;
71 enum bpf_prog_type prog_type;
72};
73
69struct bpf_object *bpf_object__open(const char *path);74struct bpf_object *bpf_object__open(const char *path);
75struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr);
70struct bpf_object *bpf_object__open_buffer(void *obj_buf,76struct bpf_object *bpf_object__open_buffer(void *obj_buf,
71 size_t obj_buf_sz,77 size_t obj_buf_sz,
72 const char *name);78 const char *name);
@@ -92,6 +98,9 @@ int bpf_object__set_priv(struct bpf_object *obj, void *priv, · 19 unmodified lines
92 bpf_object_clear_priv_t clear_priv);98 bpf_object_clear_priv_t clear_priv);
93void *bpf_object__priv(struct bpf_object *prog);99void *bpf_object__priv(struct bpf_object *prog);
94 100
101int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
102 enum bpf_attach_type *expected_attach_type);
103
95/* Accessors of bpf_program */104/* Accessors of bpf_program */
96struct bpf_program;105struct bpf_program;
97struct bpf_program *bpf_program__next(struct bpf_program *prog,106struct 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
252int bpf_map__set_priv(struct bpf_map *map, void *priv,261int bpf_map__set_priv(struct bpf_map *map, void *priv,
253 bpf_map_clear_priv_t clear_priv);262 bpf_map_clear_priv_t clear_priv);
254void *bpf_map__priv(struct bpf_map *map);263void *bpf_map__priv(struct bpf_map *map);
264int bpf_map__reuse_fd(struct bpf_map *map, int fd);
265bool bpf_map__is_offload_neutral(struct bpf_map *map);
255void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);266void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
256int bpf_map__pin(struct bpf_map *map, const char *path);267int bpf_map__pin(struct bpf_map *map, const char *path);
257 268
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
32static 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
47int 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
547 if skip_extack:547 if skip_extack:
548 return548 return
549 lines = output.split("\n")549 lines = output.split("\n")
550 comp = len(lines) >= 2 and lines[1] == reference550 comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
551 fail(not comp, "Missing or incorrect netlink extack message")551 fail(not comp, "Missing or incorrect netlink extack message")
552 552
553def check_extack_nsim(output, reference, args):553def check_extack_nsim(output, reference, args):
554 check_extack(output, "Error: netdevsim: " + reference, args)554 check_extack(output, "netdevsim: " + reference, args)
555 555
556def check_no_extack(res, needle):556def check_no_extack(res, needle):
557 fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),557 fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
@@ -654,7 +654,7 @@ try: · 96 unmodified lines
654 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,654 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
655 fail=False, include_stderr=True)655 fail=False, include_stderr=True)
656 fail(ret == 0, "TC filter loaded without enabling TC offloads")656 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)
658 sim.wait_for_flush()658 sim.wait_for_flush()
659 659
660 sim.set_ethtool_tc_offloads(True)660 sim.set_ethtool_tc_offloads(True)
@@ -694,7 +694,7 @@ try: · 33 unmodified lines
694 skip_sw=True,694 skip_sw=True,
695 fail=False, include_stderr=True)695 fail=False, include_stderr=True)
696 fail(ret == 0, "Offloaded a filter to chain other than 0")696 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)
698 sim.tc_flush_filters()698 sim.tc_flush_filters()
699 699
700 start_test("Test TC replace...")700 start_test("Test TC replace...")
@@ -830,7 +830,7 @@ try: · 129 unmodified lines
830 check_extack_nsim(err, "program loaded with different flags.", args)830 check_extack_nsim(err, "program loaded with different flags.", args)
831 ret, _, err = sim.unset_xdp("", force=True,831 ret, _, err = sim.unset_xdp("", force=True,
832 fail=False, include_stderr=True)832 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")
834 check_extack_nsim(err, "program loaded with different flags.", args)834 check_extack_nsim(err, "program loaded with different flags.", args)
835 835
836 start_test("Test MTU restrictions...")836 start_test("Test MTU restrictions...")