-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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. ==================== Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
- Loading branch information
Showing
5 changed files
with
253 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#!/bin/sh | ||
# SPDX-License-Identifier: GPL-2.0 | ||
|
||
export TESTNAME=test_libbpf | ||
|
||
# Determine selftest success via shell exit code | ||
exit_handler() | ||
{ | ||
if (( $? == 0 )); then | ||
echo "selftests: $TESTNAME [PASS]"; | ||
else | ||
echo "$TESTNAME: failed at file $LAST_LOADED" 1>&2 | ||
echo "selftests: $TESTNAME [FAILED]"; | ||
fi | ||
} | ||
|
||
libbpf_open_file() | ||
{ | ||
LAST_LOADED=$1 | ||
if [ -n "$VERBOSE" ]; then | ||
./test_libbpf_open $1 | ||
else | ||
./test_libbpf_open --quiet $1 | ||
fi | ||
} | ||
|
||
# Exit script immediately (well catched by trap handler) if any | ||
# program/thing exits with a non-zero status. | ||
set -e | ||
|
||
# (Use 'trap -l' to list meaning of numbers) | ||
trap exit_handler 0 2 3 6 9 | ||
|
||
libbpf_open_file test_l4lb.o | ||
|
||
# TODO: fix libbpf to load noinline functions | ||
# [warning] libbpf: incorrect bpf_call opcode | ||
#libbpf_open_file test_l4lb_noinline.o | ||
|
||
# TODO: fix test_xdp_meta.c to load with libbpf | ||
# [warning] libbpf: test_xdp_meta.o doesn't provide kernel version | ||
#libbpf_open_file test_xdp_meta.o | ||
|
||
# TODO: fix libbpf to handle .eh_frame | ||
# [warning] libbpf: relocation failed: no section(10) | ||
#libbpf_open_file ../../../../samples/bpf/tracex3_kern.o | ||
|
||
# Success | ||
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 | ||
* Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc. | ||
*/ | ||
static const char *__doc__ = | ||
"Libbpf test program for loading BPF ELF object files"; | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdarg.h> | ||
#include <bpf/libbpf.h> | ||
#include <getopt.h> | ||
|
||
static const struct option long_options[] = { | ||
{"help", no_argument, NULL, 'h' }, | ||
{"debug", no_argument, NULL, 'D' }, | ||
{"quiet", no_argument, NULL, 'q' }, | ||
{0, 0, NULL, 0 } | ||
}; | ||
|
||
static void usage(char *argv[]) | ||
{ | ||
int i; | ||
|
||
printf("\nDOCUMENTATION:\n%s\n\n", __doc__); | ||
printf(" Usage: %s (options-see-below) BPF_FILE\n", argv[0]); | ||
printf(" Listing options:\n"); | ||
for (i = 0; long_options[i].name != 0; i++) { | ||
printf(" --%-12s", long_options[i].name); | ||
printf(" short-option: -%c", | ||
long_options[i].val); | ||
printf("\n"); | ||
} | ||
printf("\n"); | ||
} | ||
|
||
#define DEFINE_PRINT_FN(name, enabled) \ | ||
static int libbpf_##name(const char *fmt, ...) \ | ||
{ \ | ||
va_list args; \ | ||
int ret; \ | ||
\ | ||
va_start(args, fmt); \ | ||
if (enabled) { \ | ||
fprintf(stderr, "[" #name "] "); \ | ||
ret = vfprintf(stderr, fmt, args); \ | ||
} \ | ||
va_end(args); \ | ||
return ret; \ | ||
} | ||
DEFINE_PRINT_FN(warning, 1) | ||
DEFINE_PRINT_FN(info, 1) | ||
DEFINE_PRINT_FN(debug, 1) | ||
|
||
#define EXIT_FAIL_LIBBPF EXIT_FAILURE | ||
#define EXIT_FAIL_OPTION 2 | ||
|
||
int test_walk_progs(struct bpf_object *obj, bool verbose) | ||
{ | ||
struct bpf_program *prog; | ||
int cnt = 0; | ||
|
||
bpf_object__for_each_program(prog, obj) { | ||
cnt++; | ||
if (verbose) | ||
printf("Prog (count:%d) section_name: %s\n", cnt, | ||
bpf_program__title(prog, false)); | ||
} | ||
return 0; | ||
} | ||
|
||
int test_walk_maps(struct bpf_object *obj, bool verbose) | ||
{ | ||
struct bpf_map *map; | ||
int cnt = 0; | ||
|
||
bpf_map__for_each(map, obj) { | ||
cnt++; | ||
if (verbose) | ||
printf("Map (count:%d) name: %s\n", cnt, | ||
bpf_map__name(map)); | ||
} | ||
return 0; | ||
} | ||
|
||
int test_open_file(char *filename, bool verbose) | ||
{ | ||
struct bpf_object *bpfobj = NULL; | ||
long err; | ||
|
||
if (verbose) | ||
printf("Open BPF ELF-file with libbpf: %s\n", filename); | ||
|
||
/* Load BPF ELF object file and check for errors */ | ||
bpfobj = bpf_object__open(filename); | ||
err = libbpf_get_error(bpfobj); | ||
if (err) { | ||
char err_buf[128]; | ||
libbpf_strerror(err, err_buf, sizeof(err_buf)); | ||
if (verbose) | ||
printf("Unable to load eBPF objects in file '%s': %s\n", | ||
filename, err_buf); | ||
return EXIT_FAIL_LIBBPF; | ||
} | ||
test_walk_progs(bpfobj, verbose); | ||
test_walk_maps(bpfobj, verbose); | ||
|
||
if (verbose) | ||
printf("Close BPF ELF-file with libbpf: %s\n", | ||
bpf_object__name(bpfobj)); | ||
bpf_object__close(bpfobj); | ||
|
||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
char filename[1024] = { 0 }; | ||
bool verbose = 1; | ||
int longindex = 0; | ||
int opt; | ||
|
||
libbpf_set_print(libbpf_warning, libbpf_info, NULL); | ||
|
||
/* Parse commands line args */ | ||
while ((opt = getopt_long(argc, argv, "hDq", | ||
long_options, &longindex)) != -1) { | ||
switch (opt) { | ||
case 'D': | ||
libbpf_set_print(libbpf_warning, libbpf_info, | ||
libbpf_debug); | ||
break; | ||
case 'q': /* Use in scripting mode */ | ||
verbose = 0; | ||
break; | ||
case 'h': | ||
default: | ||
usage(argv); | ||
return EXIT_FAIL_OPTION; | ||
} | ||
} | ||
if (optind >= argc) { | ||
usage(argv); | ||
printf("ERROR: Expected BPF_FILE argument after options\n"); | ||
return EXIT_FAIL_OPTION; | ||
} | ||
snprintf(filename, sizeof(filename), "%s", argv[optind]); | ||
|
||
return test_open_file(filename, verbose); | ||
} |