History

Merge branch 'bpf-libbpf-relo-fix-and-tests'

Jesper Dangaard Brouer says: ==================== While playing with using libbpf for the Suricata project, we had issues LLVM >= 4.0.1 generating ELF files that could not be loaded with libbpf (tools/lib/bpf/). During the troubleshooting phase, I wrote a test program and improved the debugging output in libbpf. I turned this into a selftests program, and it also serves as a code example for libbpf in itself. I discovered that there are at least three ELF load issues with libbpf. I left them as TODO comments in (tools/testing/selftests/bpf) test_libbpf.sh. I've only fixed the load issue with eh_frames, and other types of relo-section that does not have exec flags. We can work on the other issues later. ====================

Daniel Borkmann committed 8 years ago

Commit d977ae52 parents 69fe98e e3d91b05 files · +253 −16Browse files

Unified · Split

5 files
  1. tools/include/uapi/linux/bpf_common.h +4 −3
  2. tools/lib/bpf/libbpf.c +39 −12
  3. tools/testing/selftests/bpf/Makefile +11 −1
  4. tools/testing/selftests/bpf/test_libbpf.sh +49 −0
  5. tools/testing/selftests/bpf/test_libbpf_open.c +150 −0
tools/include/uapi/linux/bpf_common.h+4−3
@@ -15,9 +15,10 @@ · 14 unmodified lines
1515
1616 /* ld/ldx fields */
1717 #define BPF_SIZE(code) ((code) & 0x18)
18−#define BPF_W 0x00
19−#define BPF_H 0x08
20−#define BPF_B 0x10
18+#define BPF_W 0x00 /* 32-bit */
19+#define BPF_H 0x08 /* 16-bit */
20+#define BPF_B 0x10 /* 8-bit */
21+/* eBPF BPF_DW 0x18 64-bit */
2122 #define BPF_MODE(code) ((code) & 0xe0)
2223 #define BPF_IMM 0x00
2324 #define BPF_ABS 0x20
tools/lib/bpf/libbpf.c+39−12
@@ -319,8 +319,8 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx, · 318 unmodified lines
319319
320320 prog->section_name = strdup(section_name);
321321 if (!prog->section_name) {
322− pr_warning("failed to alloc name for prog under section %s\n",
323− section_name);
322+ pr_warning("failed to alloc name for prog under section(%d) %s\n",
323+ idx, section_name);
324324 goto errout;
325325 }
326326
@@ -742,6 +742,24 @@ bpf_object__init_maps(struct bpf_object *obj) · 415 unmodified lines
742742 return 0;
743743 }
744744
745+static bool section_have_execinstr(struct bpf_object *obj, int idx)
746+{
747+ Elf_Scn *scn;
748+ GElf_Shdr sh;
749+
750+ scn = elf_getscn(obj->efile.elf, idx);
751+ if (!scn)
752+ return false;
753+
754+ if (gelf_getshdr(scn, &sh) != &sh)
755+ return false;
756+
757+ if (sh.sh_flags & SHF_EXECINSTR)
758+ return true;
759+
760+ return false;
761+}
762+
745763 static int bpf_object__elf_collect(struct bpf_object *obj)
746764 {
747765 Elf *elf = obj->efile.elf;
@@ -763,29 +781,29 @@ static int bpf_object__elf_collect(struct bpf_object *obj) · 15 unmodified lines
763781
764782 idx++;
765783 if (gelf_getshdr(scn, &sh) != &sh) {
766− pr_warning("failed to get section header from %s\n",
767− obj->path);
784+ pr_warning("failed to get section(%d) header from %s\n",
785+ idx, obj->path);
768786 err = -LIBBPF_ERRNO__FORMAT;
769787 goto out;
770788 }
771789
772790 name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name);
773791 if (!name) {
774− pr_warning("failed to get section name from %s\n",
775− obj->path);
792+ pr_warning("failed to get section(%d) name from %s\n",
793+ idx, obj->path);
776794 err = -LIBBPF_ERRNO__FORMAT;
777795 goto out;
778796 }
779797
780798 data = elf_getdata(scn, 0);
781799 if (!data) {
782− pr_warning("failed to get section data from %s(%s)\n",
783− name, obj->path);
800+ pr_warning("failed to get section(%d) data from %s(%s)\n",
801+ idx, name, obj->path);
784802 err = -LIBBPF_ERRNO__FORMAT;
785803 goto out;
786804 }
787− pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n",
788− name, (unsigned long)data->d_size,
805+ pr_debug("section(%d) %s, size %ld, link %d, flags %lx, type=%d\n",
806+ idx, name, (unsigned long)data->d_size,
789807 (int)sh.sh_link, (unsigned long)sh.sh_flags,
790808 (int)sh.sh_type);
791809
@@ -825,6 +843,14 @@ static int bpf_object__elf_collect(struct bpf_object *obj) · 33 unmodified lines
825843 } else if (sh.sh_type == SHT_REL) {
826844 void *reloc = obj->efile.reloc;
827845 int nr_reloc = obj->efile.nr_reloc + 1;
846+ int sec = sh.sh_info; /* points to other section */
847+
848+ /* Only do relo for section with exec instructions */
849+ if (!section_have_execinstr(obj, sec)) {
850+ pr_debug("skip relo %s(%d) for section(%d)\n",
851+ name, idx, sec);
852+ continue;
853+ }
828854
829855 reloc = realloc(reloc,
830856 sizeof(*obj->efile.reloc) * nr_reloc);
@@ -840,6 +866,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) · 9 unmodified lines
840866 obj->efile.reloc[n].shdr = sh;
841867 obj->efile.reloc[n].data = data;
842868 }
869+ } else {
870+ pr_debug("skip section(%d) %s\n", idx, name);
843871 }
844872 if (err)
845873 goto out;
@@ -1119,8 +1147,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) · 273 unmodified lines
11191147
11201148 prog = bpf_object__find_prog_by_idx(obj, idx);
11211149 if (!prog) {
1122− pr_warning("relocation failed: no %d section\n",
1123− idx);
1150+ pr_warning("relocation failed: no section(%d)\n", idx);
11241151 return -LIBBPF_ERRNO__RELOC;
11251152 }
11261153
tools/testing/selftests/bpf/Makefile+11−1
@@ -13,6 +13,7 @@ endif · 12 unmodified lines
1313 CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
1414 LDLIBS += -lcap -lelf -lrt -lpthread
1515
16+# Order correspond to 'make run_tests' order
1617 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
1718 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user
1819
@@ -22,15 +23,24 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test · 3 unmodified lines
2223 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \
2324 sample_map_ret0.o test_tcpbpf_kern.o
2425
25−TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \
26+# Order correspond to 'make run_tests' order
27+TEST_PROGS := test_kmod.sh \
28+ test_libbpf.sh \
29+ test_xdp_redirect.sh \
30+ test_xdp_meta.sh \
2631 test_offload.py
2732
33+# Compile but not part of 'make run_tests'
34+TEST_GEN_PROGS_EXTENDED = test_libbpf_open
35+
2836 include ../lib.mk
2937
3038 BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c
3139
3240 $(TEST_GEN_PROGS): $(BPFOBJ)
3341
42+$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
43+
3444 .PHONY: force
3545
3646 # force a rebuild of BPFOBJ when its dependencies are updated
tools/testing/selftests/bpf/test_libbpf.sh+49−0
@@ -0,0 +1,49 @@
1+#!/bin/sh
2+# SPDX-License-Identifier: GPL-2.0
3+
4+export TESTNAME=test_libbpf
5+
6+# Determine selftest success via shell exit code
7+exit_handler()
8+{
9+ if (( $? == 0 )); then
10+ echo "selftests: $TESTNAME [PASS]";
11+ else
12+ echo "$TESTNAME: failed at file $LAST_LOADED" 1>&2
13+ echo "selftests: $TESTNAME [FAILED]";
14+ fi
15+}
16+
17+libbpf_open_file()
18+{
19+ LAST_LOADED=$1
20+ if [ -n "$VERBOSE" ]; then
21+ ./test_libbpf_open $1
22+ else
23+ ./test_libbpf_open --quiet $1
24+ fi
25+}
26+
27+# Exit script immediately (well catched by trap handler) if any
28+# program/thing exits with a non-zero status.
29+set -e
30+
31+# (Use 'trap -l' to list meaning of numbers)
32+trap exit_handler 0 2 3 6 9
33+
34+libbpf_open_file test_l4lb.o
35+
36+# TODO: fix libbpf to load noinline functions
37+# [warning] libbpf: incorrect bpf_call opcode
38+#libbpf_open_file test_l4lb_noinline.o
39+
40+# TODO: fix test_xdp_meta.c to load with libbpf
41+# [warning] libbpf: test_xdp_meta.o doesn't provide kernel version
42+#libbpf_open_file test_xdp_meta.o
43+
44+# TODO: fix libbpf to handle .eh_frame
45+# [warning] libbpf: relocation failed: no section(10)
46+#libbpf_open_file ../../../../samples/bpf/tracex3_kern.o
47+
48+# Success
49+exit 0
tools/testing/selftests/bpf/test_libbpf_open.c+150−0
@@ -0,0 +1,150 @@
1+/* SPDX-License-Identifier: GPL-2.0
2+ * Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc.
3+ */
4+static const char *__doc__ =
5+ "Libbpf test program for loading BPF ELF object files";
6+
7+#include <stdlib.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <stdarg.h>
11+#include <bpf/libbpf.h>
12+#include <getopt.h>
13+
14+static const struct option long_options[] = {
15+ {"help", no_argument, NULL, 'h' },
16+ {"debug", no_argument, NULL, 'D' },
17+ {"quiet", no_argument, NULL, 'q' },
18+ {0, 0, NULL, 0 }
19+};
20+
21+static void usage(char *argv[])
22+{
23+ int i;
24+
25+ printf("\nDOCUMENTATION:\n%s\n\n", __doc__);
26+ printf(" Usage: %s (options-see-below) BPF_FILE\n", argv[0]);
27+ printf(" Listing options:\n");
28+ for (i = 0; long_options[i].name != 0; i++) {
29+ printf(" --%-12s", long_options[i].name);
30+ printf(" short-option: -%c",
31+ long_options[i].val);
32+ printf("\n");
33+ }
34+ printf("\n");
35+}
36+
37+#define DEFINE_PRINT_FN(name, enabled) \
38+static int libbpf_##name(const char *fmt, ...) \
39+{ \
40+ va_list args; \
41+ int ret; \
42+ \
43+ va_start(args, fmt); \
44+ if (enabled) { \
45+ fprintf(stderr, "[" #name "] "); \
46+ ret = vfprintf(stderr, fmt, args); \
47+ } \
48+ va_end(args); \
49+ return ret; \
50+}
51+DEFINE_PRINT_FN(warning, 1)
52+DEFINE_PRINT_FN(info, 1)
53+DEFINE_PRINT_FN(debug, 1)
54+
55+#define EXIT_FAIL_LIBBPF EXIT_FAILURE
56+#define EXIT_FAIL_OPTION 2
57+
58+int test_walk_progs(struct bpf_object *obj, bool verbose)
59+{
60+ struct bpf_program *prog;
61+ int cnt = 0;
62+
63+ bpf_object__for_each_program(prog, obj) {
64+ cnt++;
65+ if (verbose)
66+ printf("Prog (count:%d) section_name: %s\n", cnt,
67+ bpf_program__title(prog, false));
68+ }
69+ return 0;
70+}
71+
72+int test_walk_maps(struct bpf_object *obj, bool verbose)
73+{
74+ struct bpf_map *map;
75+ int cnt = 0;
76+
77+ bpf_map__for_each(map, obj) {
78+ cnt++;
79+ if (verbose)
80+ printf("Map (count:%d) name: %s\n", cnt,
81+ bpf_map__name(map));
82+ }
83+ return 0;
84+}
85+
86+int test_open_file(char *filename, bool verbose)
87+{
88+ struct bpf_object *bpfobj = NULL;
89+ long err;
90+
91+ if (verbose)
92+ printf("Open BPF ELF-file with libbpf: %s\n", filename);
93+
94+ /* Load BPF ELF object file and check for errors */
95+ bpfobj = bpf_object__open(filename);
96+ err = libbpf_get_error(bpfobj);
97+ if (err) {
98+ char err_buf[128];
99+ libbpf_strerror(err, err_buf, sizeof(err_buf));
100+ if (verbose)
101+ printf("Unable to load eBPF objects in file '%s': %s\n",
102+ filename, err_buf);
103+ return EXIT_FAIL_LIBBPF;
104+ }
105+ test_walk_progs(bpfobj, verbose);
106+ test_walk_maps(bpfobj, verbose);
107+
108+ if (verbose)
109+ printf("Close BPF ELF-file with libbpf: %s\n",
110+ bpf_object__name(bpfobj));
111+ bpf_object__close(bpfobj);
112+
113+ return 0;
114+}
115+
116+int main(int argc, char **argv)
117+{
118+ char filename[1024] = { 0 };
119+ bool verbose = 1;
120+ int longindex = 0;
121+ int opt;
122+
123+ libbpf_set_print(libbpf_warning, libbpf_info, NULL);
124+
125+ /* Parse commands line args */
126+ while ((opt = getopt_long(argc, argv, "hDq",
127+ long_options, &longindex)) != -1) {
128+ switch (opt) {
129+ case 'D':
130+ libbpf_set_print(libbpf_warning, libbpf_info,
131+ libbpf_debug);
132+ break;
133+ case 'q': /* Use in scripting mode */
134+ verbose = 0;
135+ break;
136+ case 'h':
137+ default:
138+ usage(argv);
139+ return EXIT_FAIL_OPTION;
140+ }
141+ }
142+ if (optind >= argc) {
143+ usage(argv);
144+ printf("ERROR: Expected BPF_FILE argument after options\n");
145+ return EXIT_FAIL_OPTION;
146+ }
147+ snprintf(filename, sizeof(filename), "%s", argv[optind]);
148+
149+ return test_open_file(filename, verbose);
150+}