selftests/bpf: test case for register_bpf_struct_ops().
Create a new struct_ops type called bpf_testmod_ops within the bpf_testmod module. When a struct_ops object is registered, the bpf_testmod module will invoke test_2 from the module. Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com> Link: https://lore.kernel.org/r/20240119225005.668602-15-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
parent
7c81c2490c
commit
0253e0590e
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020 Facebook */
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/btf_ids.h>
|
||||
#include <linux/delay.h>
|
||||
@ -521,11 +522,75 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset)
|
||||
BTF_SET8_END(bpf_testmod_check_kfunc_ids)
|
||||
|
||||
static int bpf_testmod_ops_init(struct btf *btf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool bpf_testmod_ops_is_valid_access(int off, int size,
|
||||
enum bpf_access_type type,
|
||||
const struct bpf_prog *prog,
|
||||
struct bpf_insn_access_aux *info)
|
||||
{
|
||||
return bpf_tracing_btf_ctx_access(off, size, type, prog, info);
|
||||
}
|
||||
|
||||
static int bpf_testmod_ops_init_member(const struct btf_type *t,
|
||||
const struct btf_member *member,
|
||||
void *kdata, const void *udata)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = {
|
||||
.owner = THIS_MODULE,
|
||||
.set = &bpf_testmod_check_kfunc_ids,
|
||||
};
|
||||
|
||||
static const struct bpf_verifier_ops bpf_testmod_verifier_ops = {
|
||||
.is_valid_access = bpf_testmod_ops_is_valid_access,
|
||||
};
|
||||
|
||||
static int bpf_dummy_reg(void *kdata)
|
||||
{
|
||||
struct bpf_testmod_ops *ops = kdata;
|
||||
int r;
|
||||
|
||||
r = ops->test_2(4, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bpf_dummy_unreg(void *kdata)
|
||||
{
|
||||
}
|
||||
|
||||
static int bpf_testmod_test_1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_testmod_test_2(int a, int b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpf_testmod_ops __bpf_testmod_ops = {
|
||||
.test_1 = bpf_testmod_test_1,
|
||||
.test_2 = bpf_testmod_test_2,
|
||||
};
|
||||
|
||||
struct bpf_struct_ops bpf_bpf_testmod_ops = {
|
||||
.verifier_ops = &bpf_testmod_verifier_ops,
|
||||
.init = bpf_testmod_ops_init,
|
||||
.init_member = bpf_testmod_ops_init_member,
|
||||
.reg = bpf_dummy_reg,
|
||||
.unreg = bpf_dummy_unreg,
|
||||
.cfi_stubs = &__bpf_testmod_ops,
|
||||
.name = "bpf_testmod_ops",
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
extern int bpf_fentry_test1(int a);
|
||||
|
||||
static int bpf_testmod_init(void)
|
||||
@ -536,6 +601,7 @@ static int bpf_testmod_init(void)
|
||||
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_testmod_kfunc_set);
|
||||
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_testmod_kfunc_set);
|
||||
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set);
|
||||
ret = ret ?: register_bpf_struct_ops(&bpf_bpf_testmod_ops, bpf_testmod_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bpf_fentry_test1(0) < 0)
|
||||
|
@ -28,4 +28,9 @@ struct bpf_iter_testmod_seq {
|
||||
int cnt;
|
||||
};
|
||||
|
||||
struct bpf_testmod_ops {
|
||||
int (*test_1)(void);
|
||||
int (*test_2)(int a, int b);
|
||||
};
|
||||
|
||||
#endif /* _BPF_TESTMOD_H */
|
||||
|
@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
|
||||
#include <test_progs.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "struct_ops_module.skel.h"
|
||||
|
||||
static void check_map_info(struct bpf_map_info *info)
|
||||
{
|
||||
struct bpf_btf_info btf_info;
|
||||
char btf_name[256];
|
||||
u32 btf_info_len = sizeof(btf_info);
|
||||
int err, fd;
|
||||
|
||||
fd = bpf_btf_get_fd_by_id(info->btf_vmlinux_id);
|
||||
if (!ASSERT_GE(fd, 0, "get_value_type_btf_obj_fd"))
|
||||
return;
|
||||
|
||||
memset(&btf_info, 0, sizeof(btf_info));
|
||||
btf_info.name = ptr_to_u64(btf_name);
|
||||
btf_info.name_len = sizeof(btf_name);
|
||||
err = bpf_btf_get_info_by_fd(fd, &btf_info, &btf_info_len);
|
||||
if (!ASSERT_OK(err, "get_value_type_btf_obj_info"))
|
||||
goto cleanup;
|
||||
|
||||
if (!ASSERT_EQ(strcmp(btf_name, "bpf_testmod"), 0, "get_value_type_btf_obj_name"))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void test_struct_ops_load(void)
|
||||
{
|
||||
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
|
||||
struct struct_ops_module *skel;
|
||||
struct bpf_map_info info = {};
|
||||
struct bpf_link *link;
|
||||
int err;
|
||||
u32 len;
|
||||
|
||||
skel = struct_ops_module__open_opts(&opts);
|
||||
if (!ASSERT_OK_PTR(skel, "struct_ops_module_open"))
|
||||
return;
|
||||
|
||||
err = struct_ops_module__load(skel);
|
||||
if (!ASSERT_OK(err, "struct_ops_module_load"))
|
||||
goto cleanup;
|
||||
|
||||
len = sizeof(info);
|
||||
err = bpf_map_get_info_by_fd(bpf_map__fd(skel->maps.testmod_1), &info,
|
||||
&len);
|
||||
if (!ASSERT_OK(err, "bpf_map_get_info_by_fd"))
|
||||
goto cleanup;
|
||||
|
||||
link = bpf_map__attach_struct_ops(skel->maps.testmod_1);
|
||||
ASSERT_OK_PTR(link, "attach_test_mod_1");
|
||||
|
||||
/* test_2() will be called from bpf_dummy_reg() in bpf_testmod.c */
|
||||
ASSERT_EQ(skel->bss->test_2_result, 7, "test_2_result");
|
||||
|
||||
bpf_link__destroy(link);
|
||||
|
||||
check_map_info(&info);
|
||||
|
||||
cleanup:
|
||||
struct_ops_module__destroy(skel);
|
||||
}
|
||||
|
||||
void serial_test_struct_ops_module(void)
|
||||
{
|
||||
if (test__start_subtest("test_struct_ops_load"))
|
||||
test_struct_ops_load();
|
||||
}
|
||||
|
30
tools/testing/selftests/bpf/progs/struct_ops_module.c
Normal file
30
tools/testing/selftests/bpf/progs/struct_ops_module.c
Normal file
@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "../bpf_testmod/bpf_testmod.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
int test_2_result = 0;
|
||||
|
||||
SEC("struct_ops/test_1")
|
||||
int BPF_PROG(test_1)
|
||||
{
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
||||
SEC("struct_ops/test_2")
|
||||
int BPF_PROG(test_2, int a, int b)
|
||||
{
|
||||
test_2_result = a + b;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
SEC(".struct_ops.link")
|
||||
struct bpf_testmod_ops testmod_1 = {
|
||||
.test_1 = (void *)test_1,
|
||||
.test_2 = (void *)test_2,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user