selftests/bpf: Test subskeleton functionality

This patch changes the selftests/bpf Makefile to also generate
a subskel.h for every skel.h it would have normally generated.

Separately, it also introduces a new subskeleton test which tests
library objects, externs, weak symbols, kconfigs, and user maps.

Signed-off-by: Delyan Kratunov <delyank@fb.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/1bd24956940bbbfe169bb34f7f87b11df52ef011.1647473511.git.delyank@fb.com
This commit is contained in:
Delyan Kratunov 2022-03-16 23:37:31 +00:00 committed by Andrii Nakryiko
parent 00389c58ff
commit 3cccbaa033
6 changed files with 194 additions and 2 deletions

View File

@ -31,6 +31,7 @@ test_tcp_check_syncookie_user
test_sysctl
xdping
test_cpp
*.subskel.h
*.skel.h
*.lskel.h
/no_alu32

View File

@ -327,7 +327,13 @@ endef
SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
linked_vars.skel.h linked_maps.skel.h
linked_vars.skel.h linked_maps.skel.h \
test_subskeleton.skel.h test_subskeleton_lib.skel.h
# In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
# but that's created as a side-effect of the skel.h generation.
test_subskeleton.skel.h-deps := test_subskeleton_lib2.o test_subskeleton_lib.o test_subskeleton.o
test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.o test_subskeleton_lib.o
LSKELS := kfunc_call_test.c fentry_test.c fexit_test.c fexit_sleep.c \
test_ringbuf.c atomics.c trace_printk.c trace_vprintk.c \
@ -405,6 +411,7 @@ $(TRUNNER_BPF_SKELS): %.skel.h: %.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)
$(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
$(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.o=)) > $$@
$(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.o=)) > $$(@:.skel.h=.subskel.h)
$(TRUNNER_BPF_LSKELS): %.lskel.h: %.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
@ -422,6 +429,7 @@ $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_BPF_OBJS) $(BPFTOOL) | $(TRUNNER_OUTPUT)
$(Q)diff $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
$(Q)$$(BPFTOOL) gen skeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$@
$(Q)$$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h)
endif
# ensure we set up tests.h header generation rule just once
@ -559,6 +567,6 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \
prog_tests/tests.h map_tests/tests.h verifier/tests.h \
feature bpftool \
$(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h no_alu32 bpf_gcc bpf_testmod.ko)
$(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h no_alu32 bpf_gcc bpf_testmod.ko)
.PHONY: docs docs-clean

View File

@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <test_progs.h>
#include "test_subskeleton.skel.h"
#include "test_subskeleton_lib.subskel.h"
static void subskeleton_lib_setup(struct bpf_object *obj)
{
struct test_subskeleton_lib *lib = test_subskeleton_lib__open(obj);
if (!ASSERT_OK_PTR(lib, "open subskeleton"))
return;
*lib->rodata.var1 = 1;
*lib->data.var2 = 2;
lib->bss.var3->var3_1 = 3;
lib->bss.var3->var3_2 = 4;
test_subskeleton_lib__destroy(lib);
}
static int subskeleton_lib_subresult(struct bpf_object *obj)
{
struct test_subskeleton_lib *lib = test_subskeleton_lib__open(obj);
int result;
if (!ASSERT_OK_PTR(lib, "open subskeleton"))
return -EINVAL;
result = *lib->bss.libout1;
ASSERT_EQ(result, 1 + 2 + 3 + 4 + 5 + 6, "lib subresult");
ASSERT_OK_PTR(lib->progs.lib_perf_handler, "lib_perf_handler");
ASSERT_STREQ(bpf_program__name(lib->progs.lib_perf_handler),
"lib_perf_handler", "program name");
ASSERT_OK_PTR(lib->maps.map1, "map1");
ASSERT_STREQ(bpf_map__name(lib->maps.map1), "map1", "map name");
ASSERT_EQ(*lib->data.var5, 5, "__weak var5");
ASSERT_EQ(*lib->data.var6, 6, "extern var6");
ASSERT_TRUE(*lib->kconfig.CONFIG_BPF_SYSCALL, "CONFIG_BPF_SYSCALL");
test_subskeleton_lib__destroy(lib);
return result;
}
void test_subskeleton(void)
{
int err, result;
struct test_subskeleton *skel;
skel = test_subskeleton__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;
skel->rodata->rovar1 = 10;
skel->rodata->var1 = 1;
subskeleton_lib_setup(skel->obj);
err = test_subskeleton__load(skel);
if (!ASSERT_OK(err, "skel_load"))
goto cleanup;
err = test_subskeleton__attach(skel);
if (!ASSERT_OK(err, "skel_attach"))
goto cleanup;
/* trigger tracepoint */
usleep(1);
result = subskeleton_lib_subresult(skel->obj) * 10;
ASSERT_EQ(skel->bss->out1, result, "unexpected calculation");
cleanup:
test_subskeleton__destroy(skel);
}

View File

@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <stdbool.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
/* volatile to force a read, compiler may assume 0 otherwise */
const volatile int rovar1;
int out1;
/* Override weak symbol in test_subskeleton_lib */
int var5 = 5;
extern volatile bool CONFIG_BPF_SYSCALL __kconfig;
extern int lib_routine(void);
SEC("raw_tp/sys_enter")
int handler1(const void *ctx)
{
(void) CONFIG_BPF_SYSCALL;
out1 = lib_routine() * rovar1;
return 0;
}
char LICENSE[] SEC("license") = "GPL";

View File

@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <stdbool.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
/* volatile to force a read */
const volatile int var1;
volatile int var2 = 1;
struct {
int var3_1;
__s64 var3_2;
} var3;
int libout1;
extern volatile bool CONFIG_BPF_SYSCALL __kconfig;
int var4[4];
__weak int var5 SEC(".data");
/* Fully contained within library extern-and-definition */
extern int var6;
int var7 SEC(".data.custom");
int (*fn_ptr)(void);
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, __u32);
__uint(max_entries, 16);
} map1 SEC(".maps");
extern struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, __u32);
__uint(max_entries, 16);
} map2 SEC(".maps");
int lib_routine(void)
{
__u32 key = 1, value = 2;
(void) CONFIG_BPF_SYSCALL;
bpf_map_update_elem(&map2, &key, &value, BPF_ANY);
libout1 = var1 + var2 + var3.var3_1 + var3.var3_2 + var5 + var6;
return libout1;
}
SEC("perf_event")
int lib_perf_handler(struct pt_regs *ctx)
{
return 0;
}
char LICENSE[] SEC("license") = "GPL";

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
int var6 = 6;
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, __u32);
__uint(max_entries, 16);
} map2 SEC(".maps");
char LICENSE[] SEC("license") = "GPL";