mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 23:52:08 +02:00
selftests/bpf: Test BPF_PROG_ASSOC_STRUCT_OPS command
Test BPF_PROG_ASSOC_STRUCT_OPS command that associates a BPF program
with a struct_ops. The test follows the same logic in commit
ba7000f1c3 ("selftests/bpf: Test multi_st_ops and calling kfuncs from
different programs"), but instead of using map id to identify a specific
struct_ops, this test uses the new BPF command to associate a struct_ops
with a program.
The test consists of two sets of almost identical struct_ops maps and BPF
programs associated with the map. Their only difference is the unique
value returned by bpf_testmod_multi_st_ops::test_1().
The test first loads the programs and associates them with struct_ops
maps. Then, it exercises the BPF programs. They will in turn call kfunc
bpf_kfunc_multi_st_ops_test_1_prog_arg() to trigger test_1() of the
associated struct_ops map, and then check if the right unique value is
returned.
Signed-off-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20251203233748.668365-5-ameryhung@gmail.com
This commit is contained in:
parent
87cd177b14
commit
33a165f9c2
|
|
@ -0,0 +1,72 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <test_progs.h>
|
||||
#include "struct_ops_assoc.skel.h"
|
||||
|
||||
static void test_st_ops_assoc(void)
|
||||
{
|
||||
struct struct_ops_assoc *skel = NULL;
|
||||
int err, pid;
|
||||
|
||||
skel = struct_ops_assoc__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "struct_ops_assoc__open"))
|
||||
goto out;
|
||||
|
||||
/* cannot explicitly associate struct_ops program */
|
||||
err = bpf_program__assoc_struct_ops(skel->progs.test_1_a,
|
||||
skel->maps.st_ops_map_a, NULL);
|
||||
ASSERT_ERR(err, "bpf_program__assoc_struct_ops(test_1_a, st_ops_map_a)");
|
||||
|
||||
err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_a,
|
||||
skel->maps.st_ops_map_a, NULL);
|
||||
ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_a, st_ops_map_a)");
|
||||
|
||||
err = bpf_program__assoc_struct_ops(skel->progs.sys_enter_prog_a,
|
||||
skel->maps.st_ops_map_a, NULL);
|
||||
ASSERT_OK(err, "bpf_program__assoc_struct_ops(sys_enter_prog_a, st_ops_map_a)");
|
||||
|
||||
err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_b,
|
||||
skel->maps.st_ops_map_b, NULL);
|
||||
ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_b, st_ops_map_b)");
|
||||
|
||||
err = bpf_program__assoc_struct_ops(skel->progs.sys_enter_prog_b,
|
||||
skel->maps.st_ops_map_b, NULL);
|
||||
ASSERT_OK(err, "bpf_program__assoc_struct_ops(sys_enter_prog_b, st_ops_map_b)");
|
||||
|
||||
/* sys_enter_prog_a already associated with map_a */
|
||||
err = bpf_program__assoc_struct_ops(skel->progs.sys_enter_prog_a,
|
||||
skel->maps.st_ops_map_b, NULL);
|
||||
ASSERT_ERR(err, "bpf_program__assoc_struct_ops(sys_enter_prog_a, st_ops_map_b)");
|
||||
|
||||
err = struct_ops_assoc__attach(skel);
|
||||
if (!ASSERT_OK(err, "struct_ops_assoc__attach"))
|
||||
goto out;
|
||||
|
||||
/* run tracing prog that calls .test_1 and checks return */
|
||||
pid = getpid();
|
||||
skel->bss->test_pid = pid;
|
||||
sys_gettid();
|
||||
skel->bss->test_pid = 0;
|
||||
|
||||
ASSERT_EQ(skel->bss->test_err_a, 0, "skel->bss->test_err_a");
|
||||
ASSERT_EQ(skel->bss->test_err_b, 0, "skel->bss->test_err_b");
|
||||
|
||||
/* run syscall_prog that calls .test_1 and checks return */
|
||||
err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_a), NULL);
|
||||
ASSERT_OK(err, "bpf_prog_test_run_opts");
|
||||
|
||||
err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_b), NULL);
|
||||
ASSERT_OK(err, "bpf_prog_test_run_opts");
|
||||
|
||||
ASSERT_EQ(skel->bss->test_err_a, 0, "skel->bss->test_err_a");
|
||||
ASSERT_EQ(skel->bss->test_err_b, 0, "skel->bss->test_err_b");
|
||||
|
||||
out:
|
||||
struct_ops_assoc__destroy(skel);
|
||||
}
|
||||
|
||||
void test_struct_ops_assoc(void)
|
||||
{
|
||||
if (test__start_subtest("st_ops_assoc"))
|
||||
test_st_ops_assoc();
|
||||
}
|
||||
105
tools/testing/selftests/bpf/progs/struct_ops_assoc.c
Normal file
105
tools/testing/selftests/bpf/progs/struct_ops_assoc.c
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "bpf_misc.h"
|
||||
#include "../test_kmods/bpf_testmod.h"
|
||||
#include "../test_kmods/bpf_testmod_kfunc.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
int test_pid;
|
||||
|
||||
/* Programs associated with st_ops_map_a */
|
||||
|
||||
#define MAP_A_MAGIC 1234
|
||||
int test_err_a;
|
||||
|
||||
SEC("struct_ops")
|
||||
int BPF_PROG(test_1_a, struct st_ops_args *args)
|
||||
{
|
||||
return MAP_A_MAGIC;
|
||||
}
|
||||
|
||||
SEC("tp_btf/sys_enter")
|
||||
int BPF_PROG(sys_enter_prog_a, struct pt_regs *regs, long id)
|
||||
{
|
||||
struct st_ops_args args = {};
|
||||
struct task_struct *task;
|
||||
int ret;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
if (!test_pid || task->pid != test_pid)
|
||||
return 0;
|
||||
|
||||
ret = bpf_kfunc_multi_st_ops_test_1_impl(&args, NULL);
|
||||
if (ret != MAP_A_MAGIC)
|
||||
test_err_a++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
int syscall_prog_a(void *ctx)
|
||||
{
|
||||
struct st_ops_args args = {};
|
||||
int ret;
|
||||
|
||||
ret = bpf_kfunc_multi_st_ops_test_1_impl(&args, NULL);
|
||||
if (ret != MAP_A_MAGIC)
|
||||
test_err_a++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC(".struct_ops.link")
|
||||
struct bpf_testmod_multi_st_ops st_ops_map_a = {
|
||||
.test_1 = (void *)test_1_a,
|
||||
};
|
||||
|
||||
/* Programs associated with st_ops_map_b */
|
||||
|
||||
#define MAP_B_MAGIC 5678
|
||||
int test_err_b;
|
||||
|
||||
SEC("struct_ops")
|
||||
int BPF_PROG(test_1_b, struct st_ops_args *args)
|
||||
{
|
||||
return MAP_B_MAGIC;
|
||||
}
|
||||
|
||||
SEC("tp_btf/sys_enter")
|
||||
int BPF_PROG(sys_enter_prog_b, struct pt_regs *regs, long id)
|
||||
{
|
||||
struct st_ops_args args = {};
|
||||
struct task_struct *task;
|
||||
int ret;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
if (!test_pid || task->pid != test_pid)
|
||||
return 0;
|
||||
|
||||
ret = bpf_kfunc_multi_st_ops_test_1_impl(&args, NULL);
|
||||
if (ret != MAP_B_MAGIC)
|
||||
test_err_b++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
int syscall_prog_b(void *ctx)
|
||||
{
|
||||
struct st_ops_args args = {};
|
||||
int ret;
|
||||
|
||||
ret = bpf_kfunc_multi_st_ops_test_1_impl(&args, NULL);
|
||||
if (ret != MAP_B_MAGIC)
|
||||
test_err_b++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC(".struct_ops.link")
|
||||
struct bpf_testmod_multi_st_ops st_ops_map_b = {
|
||||
.test_1 = (void *)test_1_b,
|
||||
};
|
||||
|
|
@ -1134,6 +1134,7 @@ __bpf_kfunc int bpf_kfunc_st_ops_inc10(struct st_ops_args *args)
|
|||
}
|
||||
|
||||
__bpf_kfunc int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id);
|
||||
__bpf_kfunc int bpf_kfunc_multi_st_ops_test_1_impl(struct st_ops_args *args, void *aux_prog);
|
||||
|
||||
BTF_KFUNCS_START(bpf_testmod_check_kfunc_ids)
|
||||
BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc)
|
||||
|
|
@ -1176,6 +1177,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABL
|
|||
BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_pro_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABLE)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_st_ops_inc10, KF_TRUSTED_ARGS)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_multi_st_ops_test_1, KF_TRUSTED_ARGS)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_multi_st_ops_test_1_impl, KF_TRUSTED_ARGS)
|
||||
BTF_KFUNCS_END(bpf_testmod_check_kfunc_ids)
|
||||
|
||||
static int bpf_testmod_ops_init(struct btf *btf)
|
||||
|
|
@ -1637,6 +1639,7 @@ static struct bpf_testmod_multi_st_ops *multi_st_ops_find_nolock(u32 id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Call test_1() of the struct_ops map identified by the id */
|
||||
int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id)
|
||||
{
|
||||
struct bpf_testmod_multi_st_ops *st_ops;
|
||||
|
|
@ -1652,6 +1655,20 @@ int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Call test_1() of the associated struct_ops map */
|
||||
int bpf_kfunc_multi_st_ops_test_1_impl(struct st_ops_args *args, void *aux__prog)
|
||||
{
|
||||
struct bpf_prog_aux *prog_aux = (struct bpf_prog_aux *)aux__prog;
|
||||
struct bpf_testmod_multi_st_ops *st_ops;
|
||||
int ret = -1;
|
||||
|
||||
st_ops = (struct bpf_testmod_multi_st_ops *)bpf_prog_get_assoc_struct_ops(prog_aux);
|
||||
if (st_ops)
|
||||
ret = st_ops->test_1(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int multi_st_ops_reg(void *kdata, struct bpf_link *link)
|
||||
{
|
||||
struct bpf_testmod_multi_st_ops *st_ops =
|
||||
|
|
|
|||
|
|
@ -162,5 +162,6 @@ struct task_struct *bpf_kfunc_ret_rcu_test(void) __ksym;
|
|||
int *bpf_kfunc_ret_rcu_test_nostruct(int rdonly_buf_size) __ksym;
|
||||
|
||||
int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id) __ksym;
|
||||
int bpf_kfunc_multi_st_ops_test_1_impl(struct st_ops_args *args, void *aux__prog) __ksym;
|
||||
|
||||
#endif /* _BPF_TESTMOD_KFUNC_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user