Skip to content

Commit

Permalink
Merge branch 'revamp-test_progs'
Browse files Browse the repository at this point in the history
Andrii Nakryiko says:

====================
This patch set makes a number of changes to test_progs selftest, which is
a collection of many other tests (and sometimes sub-tests as well), to provide
better testing experience and allow to start convering many individual test
programs under selftests/bpf into a single and convenient test runner.

Patch #1 fixes issue with Makefile, which makes prog_tests/test.h compiled as
a C code. This fix allows to change how test.h is generated, providing ability
to have more control on what and how tests are run.

Patch #2 changes how test.h is auto-generated, which allows to have test
definitions, instead of just running test functions. This gives ability to do
more complicated test run policies.

Patch #3 adds `-t <test-name>` and `-n <test-num>` selectors to run only
subset of tests.

Patch #4 changes libbpf_set_print() to return previously set print callback,
allowing to temporarily replace current print callback and then set it back.
This is necessary for some tests that want more control over libbpf logging.

Patch #5 sets up and takes over libbpf logging from individual tests to
test_prog runner, adding -vv verbosity to capture debug output from libbpf.
This is useful when debugging failing tests.

Patch #6 furthers test output management and buffers it by default, emitting
log output only if test fails. This give succinct and clean default test
output. It's possible to bypass this behavior with -v flag, which will turn
off test output buffering.

Patch #7 adds support for sub-tests. It also enhances -t and -n selectors to
both support ability to specify sub-test selectors, as well as enhancing
number selector to accept sets of test, instead of just individual test
number.

Patch #8 converts bpf_verif_scale.c test to use sub-test APIs.

Patch #9 converts send_signal.c tests to use sub-test APIs.

v2->v3:
  - fix buffered output rare unitialized value bug (Alexei);
  - fix buffered output va_list reuse bug (Alexei);
  - fix buffered output truncation due to interleaving zero terminators;

v1->v2:
  - drop libbpf_swap_print, instead return previous function from
    libbpf_set_print (Stanislav);
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Alexei Starovoitov committed Jul 28, 2019
2 parents 943e398 + b207edf commit 475e31f
Show file tree
Hide file tree
Showing 16 changed files with 502 additions and 104 deletions.
5 changes: 4 additions & 1 deletion tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ static int __base_pr(enum libbpf_print_level level, const char *format,

static libbpf_print_fn_t __libbpf_pr = __base_pr;

void libbpf_set_print(libbpf_print_fn_t fn)
libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn)
{
libbpf_print_fn_t old_print_fn = __libbpf_pr;

__libbpf_pr = fn;
return old_print_fn;
}

__printf(2, 3)
Expand Down
2 changes: 1 addition & 1 deletion tools/lib/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ enum libbpf_print_level {
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
const char *, va_list ap);

LIBBPF_API void libbpf_set_print(libbpf_print_fn_t fn);
LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);

/* Hide internal to user */
struct bpf_object;
Expand Down
14 changes: 4 additions & 10 deletions tools/testing/selftests/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -235,18 +235,12 @@ PROG_TESTS_H := $(PROG_TESTS_DIR)/tests.h
PROG_TESTS_FILES := $(wildcard prog_tests/*.c)
test_progs.c: $(PROG_TESTS_H)
$(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS)
$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_H) $(PROG_TESTS_FILES)
$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_FILES) | $(PROG_TESTS_H)
$(PROG_TESTS_H): $(PROG_TESTS_FILES) | $(PROG_TESTS_DIR)
$(shell ( cd prog_tests/; \
echo '/* Generated header, do not edit */'; \
echo '#ifdef DECLARE'; \
ls *.c 2> /dev/null | \
sed -e 's@\([^\.]*\)\.c@extern void test_\1(void);@'; \
echo '#endif'; \
echo '#ifdef CALL'; \
ls *.c 2> /dev/null | \
sed -e 's@\([^\.]*\)\.c@test_\1();@'; \
echo '#endif' \
sed -e 's@\([^\.]*\)\.c@DEFINE_TEST(\1)@'; \
) > $(PROG_TESTS_H))

MAP_TESTS_DIR = $(OUTPUT)/map_tests
Expand All @@ -256,7 +250,7 @@ MAP_TESTS_H := $(MAP_TESTS_DIR)/tests.h
MAP_TESTS_FILES := $(wildcard map_tests/*.c)
test_maps.c: $(MAP_TESTS_H)
$(OUTPUT)/test_maps: CFLAGS += $(TEST_MAPS_CFLAGS)
$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_H) $(MAP_TESTS_FILES)
$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_FILES) | $(MAP_TESTS_H)
$(MAP_TESTS_H): $(MAP_TESTS_FILES) | $(MAP_TESTS_DIR)
$(shell ( cd map_tests/; \
echo '/* Generated header, do not edit */'; \
Expand All @@ -277,7 +271,7 @@ VERIFIER_TESTS_H := $(VERIFIER_TESTS_DIR)/tests.h
VERIFIER_TEST_FILES := $(wildcard verifier/*.c)
test_verifier.c: $(VERIFIER_TESTS_H)
$(OUTPUT)/test_verifier: CFLAGS += $(TEST_VERIFIER_CFLAGS)
$(OUTPUT)/test_verifier: test_verifier.c $(VERIFIER_TESTS_H)
$(OUTPUT)/test_verifier: test_verifier.c | $(VERIFIER_TEST_FILES) $(VERIFIER_TESTS_H)
$(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR)
$(shell ( cd verifier/; \
echo '/* Generated header, do not edit */'; \
Expand Down
6 changes: 3 additions & 3 deletions tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ void test_bpf_obj_id(void)
if (CHECK(err ||
prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER ||
info_len != sizeof(struct bpf_prog_info) ||
(jit_enabled && !prog_infos[i].jited_prog_len) ||
(jit_enabled &&
(env.jit_enabled && !prog_infos[i].jited_prog_len) ||
(env.jit_enabled &&
!memcmp(jited_insns, zeros, sizeof(zeros))) ||
!prog_infos[i].xlated_prog_len ||
!memcmp(xlated_insns, zeros, sizeof(zeros)) ||
Expand All @@ -121,7 +121,7 @@ void test_bpf_obj_id(void)
err, errno, i,
prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER,
info_len, sizeof(struct bpf_prog_info),
jit_enabled,
env.jit_enabled,
prog_infos[i].jited_prog_len,
prog_infos[i].xlated_prog_len,
!!memcmp(jited_insns, zeros, sizeof(zeros)),
Expand Down
90 changes: 53 additions & 37 deletions tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
static int libbpf_debug_print(enum libbpf_print_level level,
const char *format, va_list args)
{
if (level != LIBBPF_DEBUG)
return vfprintf(stderr, format, args);
if (level != LIBBPF_DEBUG) {
test__vprintf(format, args);
return 0;
}

if (!strstr(format, "verifier log"))
return 0;
return vfprintf(stderr, "%s", args);
test__vprintf("%s", args);
return 0;
}

static int check_load(const char *file, enum bpf_prog_type type)
Expand All @@ -30,71 +33,84 @@ static int check_load(const char *file, enum bpf_prog_type type)
return err;
}

struct scale_test_def {
const char *file;
enum bpf_prog_type attach_type;
bool fails;
};

void test_bpf_verif_scale(void)
{
const char *sched_cls[] = {
"./test_verif_scale1.o", "./test_verif_scale2.o", "./test_verif_scale3.o",
};
const char *raw_tp[] = {
struct scale_test_def tests[] = {
{ "loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT, true /* fails */ },

{ "test_verif_scale1.o", BPF_PROG_TYPE_SCHED_CLS },
{ "test_verif_scale2.o", BPF_PROG_TYPE_SCHED_CLS },
{ "test_verif_scale3.o", BPF_PROG_TYPE_SCHED_CLS },

/* full unroll by llvm */
"./pyperf50.o", "./pyperf100.o", "./pyperf180.o",
{ "pyperf50.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "pyperf100.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "pyperf180.o", BPF_PROG_TYPE_RAW_TRACEPOINT },

/* partial unroll. llvm will unroll loop ~150 times.
* C loop count -> 600.
* Asm loop count -> 4.
* 16k insns in loop body.
* Total of 5 such loops. Total program size ~82k insns.
*/
"./pyperf600.o",
{ "pyperf600.o", BPF_PROG_TYPE_RAW_TRACEPOINT },

/* no unroll at all.
* C loop count -> 600.
* ASM loop count -> 600.
* ~110 insns in loop body.
* Total of 5 such loops. Total program size ~1500 insns.
*/
"./pyperf600_nounroll.o",
{ "pyperf600_nounroll.o", BPF_PROG_TYPE_RAW_TRACEPOINT },

"./loop1.o", "./loop2.o",
{ "loop1.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "loop2.o", BPF_PROG_TYPE_RAW_TRACEPOINT },

/* partial unroll. 19k insn in a loop.
* Total program size 20.8k insn.
* ~350k processed_insns
*/
"./strobemeta.o",
{ "strobemeta.o", BPF_PROG_TYPE_RAW_TRACEPOINT },

/* no unroll, tiny loops */
"./strobemeta_nounroll1.o",
"./strobemeta_nounroll2.o",
};
const char *cg_sysctl[] = {
"./test_sysctl_loop1.o", "./test_sysctl_loop2.o",
};
int err, i;
{ "strobemeta_nounroll1.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "strobemeta_nounroll2.o", BPF_PROG_TYPE_RAW_TRACEPOINT },

if (verifier_stats)
libbpf_set_print(libbpf_debug_print);
{ "test_sysctl_loop1.o", BPF_PROG_TYPE_CGROUP_SYSCTL },
{ "test_sysctl_loop2.o", BPF_PROG_TYPE_CGROUP_SYSCTL },

err = check_load("./loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT);
printf("test_scale:loop3:%s\n", err ? (error_cnt--, "OK") : "FAIL");
{ "test_xdp_loop.o", BPF_PROG_TYPE_XDP },
{ "test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL },
};
libbpf_print_fn_t old_print_fn = NULL;
int err, i;

for (i = 0; i < ARRAY_SIZE(sched_cls); i++) {
err = check_load(sched_cls[i], BPF_PROG_TYPE_SCHED_CLS);
printf("test_scale:%s:%s\n", sched_cls[i], err ? "FAIL" : "OK");
if (env.verifier_stats) {
test__force_log();
old_print_fn = libbpf_set_print(libbpf_debug_print);
}

for (i = 0; i < ARRAY_SIZE(raw_tp); i++) {
err = check_load(raw_tp[i], BPF_PROG_TYPE_RAW_TRACEPOINT);
printf("test_scale:%s:%s\n", raw_tp[i], err ? "FAIL" : "OK");
}
for (i = 0; i < ARRAY_SIZE(tests); i++) {
const struct scale_test_def *test = &tests[i];

if (!test__start_subtest(test->file))
continue;

for (i = 0; i < ARRAY_SIZE(cg_sysctl); i++) {
err = check_load(cg_sysctl[i], BPF_PROG_TYPE_CGROUP_SYSCTL);
printf("test_scale:%s:%s\n", cg_sysctl[i], err ? "FAIL" : "OK");
err = check_load(test->file, test->attach_type);
if (test->fails) { /* expected to fail */
if (err)
error_cnt--;
else
error_cnt++;
}
}
err = check_load("./test_xdp_loop.o", BPF_PROG_TYPE_XDP);
printf("test_scale:test_xdp_loop:%s\n", err ? "FAIL" : "OK");

err = check_load("./test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL);
printf("test_scale:test_seg6_loop:%s\n", err ? "FAIL" : "OK");
if (env.verifier_stats)
libbpf_set_print(old_print_fn);
}
4 changes: 2 additions & 2 deletions tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static void get_stack_print_output(void *ctx, int cpu, void *data, __u32 size)
* just assume it is good if the stack is not empty.
* This could be improved in the future.
*/
if (jit_enabled) {
if (env.jit_enabled) {
found = num_stack > 0;
} else {
for (i = 0; i < num_stack; i++) {
Expand All @@ -58,7 +58,7 @@ static void get_stack_print_output(void *ctx, int cpu, void *data, __u32 size)
}
} else {
num_stack = e->kern_stack_size / sizeof(__u64);
if (jit_enabled) {
if (env.jit_enabled) {
good_kern_stack = num_stack > 0;
} else {
for (i = 0; i < num_stack; i++) {
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/prog_tests/l4lb_all.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static void test_l4lb(const char *file)
}
if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
error_cnt++;
printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
test__printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
}
out:
bpf_object__close(obj);
Expand Down
10 changes: 5 additions & 5 deletions tools/testing/selftests/bpf/prog_tests/map_lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ static void *parallel_map_access(void *arg)
for (i = 0; i < 10000; i++) {
err = bpf_map_lookup_elem_flags(map_fd, &key, vars, BPF_F_LOCK);
if (err) {
printf("lookup failed\n");
test__printf("lookup failed\n");
error_cnt++;
goto out;
}
if (vars[0] != 0) {
printf("lookup #%d var[0]=%d\n", i, vars[0]);
test__printf("lookup #%d var[0]=%d\n", i, vars[0]);
error_cnt++;
goto out;
}
rnd = vars[1];
for (j = 2; j < 17; j++) {
if (vars[j] == rnd)
continue;
printf("lookup #%d var[1]=%d var[%d]=%d\n",
i, rnd, j, vars[j]);
test__printf("lookup #%d var[1]=%d var[%d]=%d\n",
i, rnd, j, vars[j]);
error_cnt++;
goto out;
}
Expand All @@ -43,7 +43,7 @@ void test_map_lock(void)

err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd);
if (err) {
printf("test_map_lock:bpf_prog_load errno %d\n", errno);
test__printf("test_map_lock:bpf_prog_load errno %d\n", errno);
goto close_prog;
}
map_fd[0] = bpf_find_map(__func__, obj, "hash_map");
Expand Down
15 changes: 4 additions & 11 deletions tools/testing/selftests/bpf/prog_tests/reference_tracking.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>

static int libbpf_debug_print(enum libbpf_print_level level,
const char *format, va_list args)
{
if (level == LIBBPF_DEBUG)
return 0;

return vfprintf(stderr, format, args);
}

void test_reference_tracking(void)
{
const char *file = "./test_sk_lookup_kern.o";
Expand All @@ -36,9 +27,11 @@ void test_reference_tracking(void)

/* Expect verifier failure if test name has 'fail' */
if (strstr(title, "fail") != NULL) {
libbpf_set_print(NULL);
libbpf_print_fn_t old_print_fn;

old_print_fn = libbpf_set_print(NULL);
err = !bpf_program__load(prog, "GPL", 0);
libbpf_set_print(libbpf_debug_print);
libbpf_set_print(old_print_fn);
} else {
err = bpf_program__load(prog, "GPL", 0);
}
Expand Down
17 changes: 8 additions & 9 deletions tools/testing/selftests/bpf/prog_tests/send_signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ static int test_send_signal_nmi(void)
-1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
if (pmu_fd == -1) {
if (errno == ENOENT) {
printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
__func__);
test__printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
__func__);
return 0;
}
/* Let the test fail with a more informative message */
Expand All @@ -219,11 +219,10 @@ void test_send_signal(void)
{
int ret = 0;

ret |= test_send_signal_tracepoint();
ret |= test_send_signal_perf();
ret |= test_send_signal_nmi();
if (!ret)
printf("test_send_signal:OK\n");
else
printf("test_send_signal:FAIL\n");
if (test__start_subtest("send_signal_tracepoint"))
ret |= test_send_signal_tracepoint();
if (test__start_subtest("send_signal_perf"))
ret |= test_send_signal_perf();
if (test__start_subtest("send_signal_nmi"))
ret |= test_send_signal_nmi();
}
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/prog_tests/spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ void test_spinlock(void)

err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd);
if (err) {
printf("test_spin_lock:bpf_prog_load errno %d\n", errno);
test__printf("test_spin_lock:bpf_prog_load errno %d\n", errno);
goto close_prog;
}
for (i = 0; i < 4; i++)
Expand Down
4 changes: 2 additions & 2 deletions tools/testing/selftests/bpf/prog_tests/stacktrace_build_id.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ void test_stacktrace_build_id(void)
if (build_id_matches < 1 && retry--) {
bpf_link__destroy(link);
bpf_object__close(obj);
printf("%s:WARN:Didn't find expected build ID from the map, retrying\n",
__func__);
test__printf("%s:WARN:Didn't find expected build ID from the map, retrying\n",
__func__);
goto retry;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ void test_stacktrace_build_id_nmi(void)
if (build_id_matches < 1 && retry--) {
bpf_link__destroy(link);
bpf_object__close(obj);
printf("%s:WARN:Didn't find expected build ID from the map, retrying\n",
__func__);
test__printf("%s:WARN:Didn't find expected build ID from the map, retrying\n",
__func__);
goto retry;
}

Expand Down
3 changes: 2 additions & 1 deletion tools/testing/selftests/bpf/prog_tests/xdp_noinline.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ void test_xdp_noinline(void)
}
if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
error_cnt++;
printf("test_xdp_noinline:FAIL:stats %lld %lld\n", bytes, pkts);
test__printf("test_xdp_noinline:FAIL:stats %lld %lld\n",
bytes, pkts);
}
out:
bpf_object__close(obj);
Expand Down
Loading

0 comments on commit 475e31f

Please sign in to comment.