Skip to content

Commit 9f7fa22

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
selftests/bpf: Add bpf_testmod kernel module for testing
Add bpf_testmod module, which is conceptually out-of-tree module and provides ways for selftests/bpf to test various kernel module-related functionality: raw tracepoint, fentry/fexit/fmod_ret, etc. This module will be auto-loaded by test_progs test runner and expected by some of selftests to be present and loaded. Pahole currently isn't able to generate BTF for static functions in kernel modules, so make sure traced function is global. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 4f33a53 commit 9f7fa22

File tree

9 files changed

+198
-3
lines changed

9 files changed

+198
-3
lines changed

tools/testing/selftests/bpf/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ test_cpp
3535
/tools
3636
/runqslower
3737
/bench
38+
*.ko

tools/testing/selftests/bpf/Makefile

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \
8080
# Compile but not part of 'make run_tests'
8181
TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \
8282
flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
83-
test_lirc_mode2_user xdping test_cpp runqslower bench
83+
test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko
8484

8585
TEST_CUSTOM_PROGS = urandom_read
8686

@@ -104,6 +104,7 @@ OVERRIDE_TARGETS := 1
104104
override define CLEAN
105105
$(call msg,CLEAN)
106106
$(Q)$(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN)
107+
$(Q)$(MAKE) -C bpf_testmod clean
107108
endef
108109

109110
include ../lib.mk
@@ -136,6 +137,11 @@ $(OUTPUT)/urandom_read: urandom_read.c
136137
$(call msg,BINARY,,$@)
137138
$(Q)$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) -Wl,--build-id=sha1
138139

140+
$(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(wildcard bpf_testmod/Makefile bpf_testmod/*.[ch])
141+
$(call msg,MOD,,$@)
142+
$(Q)$(MAKE) $(submake_extras) -C bpf_testmod
143+
$(Q)cp bpf_testmod/bpf_testmod.ko $@
144+
139145
$(OUTPUT)/test_stub.o: test_stub.c $(BPFOBJ)
140146
$(call msg,CC,,$@)
141147
$(Q)$(CC) -c $(CFLAGS) -o $@ $<
@@ -388,7 +394,7 @@ TRUNNER_BPF_PROGS_DIR := progs
388394
TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \
389395
network_helpers.c testing_helpers.c \
390396
btf_helpers.c flow_dissector_load.h
391-
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read \
397+
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \
392398
ima_setup.sh \
393399
$(wildcard progs/btf_dump_test_case_*.c)
394400
TRUNNER_BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE
@@ -460,4 +466,4 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o $(OUTPUT)/testing_helpers.o \
460466
EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(SCRATCH_DIR) \
461467
prog_tests/tests.h map_tests/tests.h verifier/tests.h \
462468
feature \
463-
$(addprefix $(OUTPUT)/,*.o *.skel.h no_alu32 bpf_gcc)
469+
$(addprefix $(OUTPUT)/,*.o *.skel.h no_alu32 bpf_gcc bpf_testmod.ko)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.mod
2+
*.mod.c
3+
*.o
4+
.ko
5+
/Module.symvers
6+
/modules.order
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
BPF_TESTMOD_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
2+
KDIR ?= $(abspath $(BPF_TESTMOD_DIR)/../../../../..)
3+
4+
ifeq ($(V),1)
5+
Q =
6+
else
7+
Q = @
8+
endif
9+
10+
MODULES = bpf_testmod.ko
11+
12+
obj-m += bpf_testmod.o
13+
CFLAGS_bpf_testmod.o = -I$(src)
14+
15+
all:
16+
+$(Q)make -C $(KDIR) M=$(BPF_TESTMOD_DIR) modules
17+
18+
clean:
19+
+$(Q)make -C $(KDIR) M=$(BPF_TESTMOD_DIR) clean
20+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (c) 2020 Facebook */
3+
#undef TRACE_SYSTEM
4+
#define TRACE_SYSTEM bpf_testmod
5+
6+
#if !defined(_BPF_TESTMOD_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
7+
#define _BPF_TESTMOD_EVENTS_H
8+
9+
#include <linux/tracepoint.h>
10+
#include "bpf_testmod.h"
11+
12+
TRACE_EVENT(bpf_testmod_test_read,
13+
TP_PROTO(struct task_struct *task, struct bpf_testmod_test_read_ctx *ctx),
14+
TP_ARGS(task, ctx),
15+
TP_STRUCT__entry(
16+
__field(pid_t, pid)
17+
__array(char, comm, TASK_COMM_LEN)
18+
__field(loff_t, off)
19+
__field(size_t, len)
20+
),
21+
TP_fast_assign(
22+
__entry->pid = task->pid;
23+
memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
24+
__entry->off = ctx->off;
25+
__entry->len = ctx->len;
26+
),
27+
TP_printk("pid=%d comm=%s off=%llu len=%zu",
28+
__entry->pid, __entry->comm, __entry->off, __entry->len)
29+
);
30+
31+
#endif /* _BPF_TESTMOD_EVENTS_H */
32+
33+
#undef TRACE_INCLUDE_PATH
34+
#define TRACE_INCLUDE_PATH .
35+
#define TRACE_INCLUDE_FILE bpf_testmod-events
36+
#include <trace/define_trace.h>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2020 Facebook */
3+
#include <linux/error-injection.h>
4+
#include <linux/init.h>
5+
#include <linux/module.h>
6+
#include <linux/sysfs.h>
7+
#include <linux/tracepoint.h>
8+
#include "bpf_testmod.h"
9+
10+
#define CREATE_TRACE_POINTS
11+
#include "bpf_testmod-events.h"
12+
13+
noinline ssize_t
14+
bpf_testmod_test_read(struct file *file, struct kobject *kobj,
15+
struct bin_attribute *bin_attr,
16+
char *buf, loff_t off, size_t len)
17+
{
18+
struct bpf_testmod_test_read_ctx ctx = {
19+
.buf = buf,
20+
.off = off,
21+
.len = len,
22+
};
23+
24+
trace_bpf_testmod_test_read(current, &ctx);
25+
26+
return -EIO; /* always fail */
27+
}
28+
EXPORT_SYMBOL(bpf_testmod_test_read);
29+
ALLOW_ERROR_INJECTION(bpf_testmod_test_read, ERRNO);
30+
31+
static struct bin_attribute bin_attr_bpf_testmod_file __ro_after_init = {
32+
.attr = { .name = "bpf_testmod", .mode = 0444, },
33+
.read = bpf_testmod_test_read,
34+
};
35+
36+
static int bpf_testmod_init(void)
37+
{
38+
return sysfs_create_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file);
39+
}
40+
41+
static void bpf_testmod_exit(void)
42+
{
43+
return sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file);
44+
}
45+
46+
module_init(bpf_testmod_init);
47+
module_exit(bpf_testmod_exit);
48+
49+
MODULE_AUTHOR("Andrii Nakryiko");
50+
MODULE_DESCRIPTION("BPF selftests module");
51+
MODULE_LICENSE("Dual BSD/GPL");
52+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (c) 2020 Facebook */
3+
#ifndef _BPF_TESTMOD_H
4+
#define _BPF_TESTMOD_H
5+
6+
#include <linux/types.h>
7+
8+
struct bpf_testmod_test_read_ctx {
9+
char *buf;
10+
loff_t off;
11+
size_t len;
12+
};
13+
14+
#endif /* _BPF_TESTMOD_H */

tools/testing/selftests/bpf/test_progs.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,58 @@ int extract_build_id(char *build_id, size_t size)
360360
return -1;
361361
}
362362

363+
static int finit_module(int fd, const char *param_values, int flags)
364+
{
365+
return syscall(__NR_finit_module, fd, param_values, flags);
366+
}
367+
368+
static int delete_module(const char *name, int flags)
369+
{
370+
return syscall(__NR_delete_module, name, flags);
371+
}
372+
373+
static void unload_bpf_testmod(void)
374+
{
375+
if (delete_module("bpf_testmod", 0)) {
376+
if (errno == ENOENT) {
377+
if (env.verbosity > VERBOSE_NONE)
378+
fprintf(stdout, "bpf_testmod.ko is already unloaded.\n");
379+
return;
380+
}
381+
fprintf(env.stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno);
382+
exit(1);
383+
}
384+
if (env.verbosity > VERBOSE_NONE)
385+
fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n");
386+
}
387+
388+
static int load_bpf_testmod(void)
389+
{
390+
int fd;
391+
392+
/* ensure previous instance of the module is unloaded */
393+
unload_bpf_testmod();
394+
395+
if (env.verbosity > VERBOSE_NONE)
396+
fprintf(stdout, "Loading bpf_testmod.ko...\n");
397+
398+
fd = open("bpf_testmod.ko", O_RDONLY);
399+
if (fd < 0) {
400+
fprintf(env.stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno);
401+
return -ENOENT;
402+
}
403+
if (finit_module(fd, "", 0)) {
404+
fprintf(env.stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno);
405+
close(fd);
406+
return -EINVAL;
407+
}
408+
close(fd);
409+
410+
if (env.verbosity > VERBOSE_NONE)
411+
fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n");
412+
return 0;
413+
}
414+
363415
/* extern declarations for test funcs */
364416
#define DEFINE_TEST(name) extern void test_##name(void);
365417
#include <prog_tests/tests.h>
@@ -678,6 +730,11 @@ int main(int argc, char **argv)
678730

679731
save_netns();
680732
stdio_hijack();
733+
env.has_testmod = true;
734+
if (load_bpf_testmod()) {
735+
fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n");
736+
env.has_testmod = false;
737+
}
681738
for (i = 0; i < prog_test_cnt; i++) {
682739
struct prog_test_def *test = &prog_test_defs[i];
683740

@@ -722,6 +779,8 @@ int main(int argc, char **argv)
722779
if (test->need_cgroup_cleanup)
723780
cleanup_cgroup_environment();
724781
}
782+
if (env.has_testmod)
783+
unload_bpf_testmod();
725784
stdio_restore();
726785

727786
if (env.get_test_cnt) {

tools/testing/selftests/bpf/test_progs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ struct test_env {
6666
enum verbosity verbosity;
6767

6868
bool jit_enabled;
69+
bool has_testmod;
6970
bool get_test_cnt;
7071
bool list_test_names;
7172

0 commit comments

Comments
 (0)