* [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to
@ 2025-08-06 16:25 Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 1/3] bpf: Allow struct_ops to get map id by kdata Amery Hung
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Amery Hung @ 2025-08-06 16:25 UTC (permalink / raw)
To: bpf
Cc: netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, ameryhung, kernel-team
v1 -> v2
Add bpf_struct_ops_id() instead of using bpf_struct_ops_get()
Hi,
This patchset allows struct_ops implementors to get map id from kdata in
reg(), unreg() and update() so that they create an id to struct_ops
instance mapping. This in turn allows struct_ops kfuncs to refer to the
calling instance without passing a pointer to the struct_ops. The selftest
provides an end-to-end example.
Some struct_ops users extend themselves with other bpf programs, which
also need to call struct_ops kfuncs. For example, scx_layered uses
syscall bpf programs as a scx_layered specific control plane and uses
tracing programs to get additional information for scheduling [0].
The kfuncs may need to refer to the struct_ops instance and perform
jobs accordingly. To allow calling struct_ops kfuncs referring to
specific instances from different program types and context (e.g.,
struct_ops, tracing, async callbacks), the traditional way is to pass
the struct_ops pointer to kfuncs.
This patchset provides an alternative way, through a combination of
bpf map id and global variable. First, a struct_ops implementor will
use the map id of the struct_ops map as the id of an instance. Then,
it needs to maintain an id to instance mapping: inserting a new mapping
during reg() and removing it during unreg(). The map id can be acquired
by calling bpf_struct_ops_id().
[0] https://github.com/sched-ext/scx/blob/main/scheds/rust/scx_layered/src/bpf/main.bpf.c
Amery Hung (3):
bpf: Allow struct_ops to get map id by kdata
selftests/bpf: Add multi_st_ops that supports multiple instances
selftests/bpf: Test multi_st_ops and calling kfuncs from different
programs
include/linux/bpf.h | 1 +
kernel/bpf/bpf_struct_ops.c | 12 ++
.../test_struct_ops_id_ops_mapping.c | 77 +++++++++++++
.../bpf/progs/struct_ops_id_ops_mapping1.c | 59 ++++++++++
.../bpf/progs/struct_ops_id_ops_mapping2.c | 59 ++++++++++
.../selftests/bpf/test_kmods/bpf_testmod.c | 109 ++++++++++++++++++
.../selftests/bpf/test_kmods/bpf_testmod.h | 8 ++
.../bpf/test_kmods/bpf_testmod_kfunc.h | 2 +
8 files changed, 327 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c
create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c
create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf-next v2 1/3] bpf: Allow struct_ops to get map id by kdata
2025-08-06 16:25 [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to Amery Hung
@ 2025-08-06 16:25 ` Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 2/3] selftests/bpf: Add multi_st_ops that supports multiple instances Amery Hung
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Amery Hung @ 2025-08-06 16:25 UTC (permalink / raw)
To: bpf
Cc: netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, ameryhung, kernel-team
Add bpf_struct_ops_id() to enable struct_ops implementors to use
struct_ops map id as the unique id of a struct_ops in their subsystem.
A subsystem that wishes to create a mapping between id and struct_ops
instance pointer can update the mapping accordingly during
bpf_struct_ops::reg(), unreg(), and update().
Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
include/linux/bpf.h | 1 +
kernel/bpf/bpf_struct_ops.c | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index f9cd2164ed23..aa5347dee78c 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1975,6 +1975,7 @@ static inline void bpf_module_put(const void *data, struct module *owner)
module_put(owner);
}
int bpf_struct_ops_link_create(union bpf_attr *attr);
+u32 bpf_struct_ops_id(const void *kdata);
#ifdef CONFIG_NET
/* Define it here to avoid the use of forward declaration */
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 687a3e9c76f5..a41e6730edcf 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -1174,6 +1174,18 @@ void bpf_struct_ops_put(const void *kdata)
bpf_map_put(&st_map->map);
}
+u32 bpf_struct_ops_id(const void *kdata)
+{
+ struct bpf_struct_ops_value *kvalue;
+ struct bpf_struct_ops_map *st_map;
+
+ kvalue = container_of(kdata, struct bpf_struct_ops_value, data);
+ st_map = container_of(kvalue, struct bpf_struct_ops_map, kvalue);
+
+ return st_map->map.id;
+}
+EXPORT_SYMBOL_GPL(bpf_struct_ops_id);
+
static bool bpf_struct_ops_valid_to_reg(struct bpf_map *map)
{
struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH bpf-next v2 2/3] selftests/bpf: Add multi_st_ops that supports multiple instances
2025-08-06 16:25 [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 1/3] bpf: Allow struct_ops to get map id by kdata Amery Hung
@ 2025-08-06 16:25 ` Amery Hung
2025-08-06 23:16 ` Martin KaFai Lau
2025-08-06 16:25 ` [PATCH bpf-next v2 3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs Amery Hung
2025-08-06 23:20 ` [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to patchwork-bot+netdevbpf
3 siblings, 1 reply; 7+ messages in thread
From: Amery Hung @ 2025-08-06 16:25 UTC (permalink / raw)
To: bpf
Cc: netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, ameryhung, kernel-team
Current struct_ops in bpf_testmod only support attaching single instance.
Add multi_st_ops that supports multiple instances. The struct_ops uses map
id as the struct_ops id and will reject attachment with an existing id.
Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
.../selftests/bpf/test_kmods/bpf_testmod.c | 109 ++++++++++++++++++
.../selftests/bpf/test_kmods/bpf_testmod.h | 8 ++
.../bpf/test_kmods/bpf_testmod_kfunc.h | 2 +
3 files changed, 119 insertions(+)
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
index e9e918cdf31f..9ae31b1cbb13 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
@@ -1057,6 +1057,8 @@ __bpf_kfunc int bpf_kfunc_st_ops_inc10(struct st_ops_args *args)
return args->a;
}
+__bpf_kfunc int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id);
+
BTF_KFUNCS_START(bpf_testmod_check_kfunc_ids)
BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc)
BTF_ID_FLAGS(func, bpf_kfunc_call_test1)
@@ -1097,6 +1099,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_prologue, KF_TRUSTED_ARGS | KF_SLEEPABL
BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABLE)
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_KFUNCS_END(bpf_testmod_check_kfunc_ids)
static int bpf_testmod_ops_init(struct btf *btf)
@@ -1528,6 +1531,111 @@ static struct bpf_struct_ops testmod_st_ops = {
.owner = THIS_MODULE,
};
+struct hlist_head multi_st_ops_list;
+static DEFINE_SPINLOCK(multi_st_ops_lock);
+
+static int multi_st_ops_init(struct btf *btf)
+{
+ spin_lock_init(&multi_st_ops_lock);
+ INIT_HLIST_HEAD(&multi_st_ops_list);
+
+ return 0;
+}
+
+static int multi_st_ops_init_member(const struct btf_type *t,
+ const struct btf_member *member,
+ void *kdata, const void *udata)
+{
+ return 0;
+}
+
+static struct bpf_testmod_multi_st_ops *multi_st_ops_find_nolock(u32 id)
+{
+ struct bpf_testmod_multi_st_ops *st_ops;
+
+ hlist_for_each_entry(st_ops, &multi_st_ops_list, node) {
+ if (st_ops->id == id)
+ return st_ops;
+ }
+
+ return NULL;
+}
+
+int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id)
+{
+ struct bpf_testmod_multi_st_ops *st_ops;
+ unsigned long flags;
+ int ret = -1;
+
+ spin_lock_irqsave(&multi_st_ops_lock, flags);
+ st_ops = multi_st_ops_find_nolock(id);
+ if (st_ops)
+ ret = st_ops->test_1(args);
+ spin_unlock_irqrestore(&multi_st_ops_lock, flags);
+
+ return ret;
+}
+
+static int multi_st_ops_reg(void *kdata, struct bpf_link *link)
+{
+ struct bpf_testmod_multi_st_ops *st_ops =
+ (struct bpf_testmod_multi_st_ops *)kdata;
+ unsigned long flags;
+ int err = 0;
+ u32 id;
+
+ id = bpf_struct_ops_id(kdata);
+
+ spin_lock_irqsave(&multi_st_ops_lock, flags);
+ if (multi_st_ops_find_nolock(id)) {
+ pr_err("multi_st_ops(id:%d) has already been registered\n", id);
+ err = -EEXIST;
+ goto unlock;
+ }
+
+ st_ops->id = id;
+ hlist_add_head(&st_ops->node, &multi_st_ops_list);
+unlock:
+ spin_unlock_irqrestore(&multi_st_ops_lock, flags);
+
+ return err;
+}
+
+static void multi_st_ops_unreg(void *kdata, struct bpf_link *link)
+{
+ struct bpf_testmod_multi_st_ops *st_ops;
+ unsigned long flags;
+ u32 id;
+
+ id = bpf_struct_ops_id(kdata);
+
+ spin_lock_irqsave(&multi_st_ops_lock, flags);
+ st_ops = multi_st_ops_find_nolock(id);
+ if (st_ops)
+ hlist_del(&st_ops->node);
+ spin_unlock_irqrestore(&multi_st_ops_lock, flags);
+}
+
+static int bpf_testmod_multi_st_ops__test_1(struct st_ops_args *args)
+{
+ return 0;
+}
+
+static struct bpf_testmod_multi_st_ops multi_st_ops_cfi_stubs = {
+ .test_1 = bpf_testmod_multi_st_ops__test_1,
+};
+
+struct bpf_struct_ops testmod_multi_st_ops = {
+ .verifier_ops = &bpf_testmod_verifier_ops,
+ .init = multi_st_ops_init,
+ .init_member = multi_st_ops_init_member,
+ .reg = multi_st_ops_reg,
+ .unreg = multi_st_ops_unreg,
+ .cfi_stubs = &multi_st_ops_cfi_stubs,
+ .name = "bpf_testmod_multi_st_ops",
+ .owner = THIS_MODULE,
+};
+
extern int bpf_fentry_test1(int a);
static int bpf_testmod_init(void)
@@ -1550,6 +1658,7 @@ static int bpf_testmod_init(void)
ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2);
ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops3, bpf_testmod_ops3);
ret = ret ?: register_bpf_struct_ops(&testmod_st_ops, bpf_testmod_st_ops);
+ ret = ret ?: register_bpf_struct_ops(&testmod_multi_st_ops, bpf_testmod_multi_st_ops);
ret = ret ?: register_btf_id_dtor_kfuncs(bpf_testmod_dtors,
ARRAY_SIZE(bpf_testmod_dtors),
THIS_MODULE);
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
index c9fab51f16e2..b8001ba7c368 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
@@ -116,4 +116,12 @@ struct bpf_testmod_st_ops {
struct module *owner;
};
+#define BPF_TESTMOD_NAME_SZ 16
+
+struct bpf_testmod_multi_st_ops {
+ int (*test_1)(struct st_ops_args *args);
+ struct hlist_node node;
+ int id;
+};
+
#endif /* _BPF_TESTMOD_H */
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
index b58817938deb..286e7faa4754 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
@@ -159,4 +159,6 @@ void bpf_kfunc_trusted_task_test(struct task_struct *ptr) __ksym;
void bpf_kfunc_trusted_num_test(int *ptr) __ksym;
void bpf_kfunc_rcu_task_test(struct task_struct *ptr) __ksym;
+int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id) __ksym;
+
#endif /* _BPF_TESTMOD_KFUNC_H */
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH bpf-next v2 3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs
2025-08-06 16:25 [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 1/3] bpf: Allow struct_ops to get map id by kdata Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 2/3] selftests/bpf: Add multi_st_ops that supports multiple instances Amery Hung
@ 2025-08-06 16:25 ` Amery Hung
2025-08-06 23:20 ` Martin KaFai Lau
2025-08-06 23:20 ` [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to patchwork-bot+netdevbpf
3 siblings, 1 reply; 7+ messages in thread
From: Amery Hung @ 2025-08-06 16:25 UTC (permalink / raw)
To: bpf
Cc: netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, ameryhung, kernel-team
Test multi_st_ops and demonstrate how different bpf programs can call
a kfuncs that refers to the struct_ops instance in the same source file
by id. The id is defined as a global vairable and initialized before
attaching the skeleton. Kfuncs that take the id can hide the argument
with a macro to make it almost transparent to bpf program developers.
The test involves two struct_ops returning different values from
.test_1. In syscall and tracing programs, check if the correct value is
returned by a kfunc that calls .test_1.
Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
.../test_struct_ops_id_ops_mapping.c | 77 +++++++++++++++++++
.../bpf/progs/struct_ops_id_ops_mapping1.c | 59 ++++++++++++++
.../bpf/progs/struct_ops_id_ops_mapping2.c | 59 ++++++++++++++
3 files changed, 195 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c
create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c
create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c
diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c
new file mode 100644
index 000000000000..927524ac191d
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include "struct_ops_id_ops_mapping1.skel.h"
+#include "struct_ops_id_ops_mapping2.skel.h"
+
+static void test_st_ops_id_ops_mapping(void)
+{
+ struct struct_ops_id_ops_mapping1 *skel1 = NULL;
+ struct struct_ops_id_ops_mapping2 *skel2 = NULL;
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+ struct bpf_map_info info = {};
+ __u32 len = sizeof(info);
+ int err, pid, prog1_fd, prog2_fd;
+
+ skel1 = struct_ops_id_ops_mapping1__open_and_load();
+ if (!ASSERT_OK_PTR(skel1, "struct_ops_id_ops_mapping1__open"))
+ goto out;
+
+ skel2 = struct_ops_id_ops_mapping2__open_and_load();
+ if (!ASSERT_OK_PTR(skel2, "struct_ops_id_ops_mapping2__open"))
+ goto out;
+
+ err = bpf_map_get_info_by_fd(bpf_map__fd(skel1->maps.st_ops_map),
+ &info, &len);
+ if (!ASSERT_OK(err, "bpf_map_get_info_by_fd"))
+ goto out;
+
+ skel1->bss->st_ops_id = info.id;
+
+ err = bpf_map_get_info_by_fd(bpf_map__fd(skel2->maps.st_ops_map),
+ &info, &len);
+ if (!ASSERT_OK(err, "bpf_map_get_info_by_fd"))
+ goto out;
+
+ skel2->bss->st_ops_id = info.id;
+
+ err = struct_ops_id_ops_mapping1__attach(skel1);
+ if (!ASSERT_OK(err, "struct_ops_id_ops_mapping1__attach"))
+ goto out;
+
+ err = struct_ops_id_ops_mapping2__attach(skel2);
+ if (!ASSERT_OK(err, "struct_ops_id_ops_mapping2__attach"))
+ goto out;
+
+ /* run tracing prog that calls .test_1 and checks return */
+ pid = getpid();
+ skel1->bss->test_pid = pid;
+ skel2->bss->test_pid = pid;
+ sys_gettid();
+ skel1->bss->test_pid = 0;
+ skel2->bss->test_pid = 0;
+
+ /* run syscall_prog that calls .test_1 and checks return */
+ prog1_fd = bpf_program__fd(skel1->progs.syscall_prog);
+ err = bpf_prog_test_run_opts(prog1_fd, &topts);
+ ASSERT_OK(err, "bpf_prog_test_run_opts");
+
+ prog2_fd = bpf_program__fd(skel2->progs.syscall_prog);
+ err = bpf_prog_test_run_opts(prog2_fd, &topts);
+ ASSERT_OK(err, "bpf_prog_test_run_opts");
+
+ ASSERT_EQ(skel1->bss->test_err, 0, "skel1->bss->test_err");
+ ASSERT_EQ(skel2->bss->test_err, 0, "skel2->bss->test_err");
+
+out:
+ if (skel1)
+ struct_ops_id_ops_mapping1__destroy(skel1);
+ if (skel2)
+ struct_ops_id_ops_mapping2__destroy(skel2);
+}
+
+void test_struct_ops_id_ops_mapping(void)
+{
+ if (test__start_subtest("st_ops_id_ops_mapping"))
+ test_st_ops_id_ops_mapping();
+}
diff --git a/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c
new file mode 100644
index 000000000000..ad8bb546c9bf
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c
@@ -0,0 +1,59 @@
+// 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";
+
+#define bpf_kfunc_multi_st_ops_test_1(args) bpf_kfunc_multi_st_ops_test_1(args, st_ops_id)
+int st_ops_id;
+
+int test_pid;
+int test_err;
+
+#define MAP1_MAGIC 1234
+
+SEC("struct_ops")
+int BPF_PROG(test_1, struct st_ops_args *args)
+{
+ return MAP1_MAGIC;
+}
+
+SEC("tp_btf/sys_enter")
+int BPF_PROG(sys_enter, 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(&args);
+ if (ret != MAP1_MAGIC)
+ test_err++;
+
+ return 0;
+}
+
+SEC("syscall")
+int syscall_prog(void *ctx)
+{
+ struct st_ops_args args = {};
+ int ret;
+
+ ret = bpf_kfunc_multi_st_ops_test_1(&args);
+ if (ret != MAP1_MAGIC)
+ test_err++;
+
+ return 0;
+}
+
+SEC(".struct_ops.link")
+struct bpf_testmod_multi_st_ops st_ops_map = {
+ .test_1 = (void *)test_1,
+};
diff --git a/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c
new file mode 100644
index 000000000000..cea1a2f4b62f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c
@@ -0,0 +1,59 @@
+// 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";
+
+#define bpf_kfunc_multi_st_ops_test_1(args) bpf_kfunc_multi_st_ops_test_1(args, st_ops_id)
+int st_ops_id;
+
+int test_pid;
+int test_err;
+
+#define MAP2_MAGIC 4567
+
+SEC("struct_ops")
+int BPF_PROG(test_1, struct st_ops_args *args)
+{
+ return MAP2_MAGIC;
+}
+
+SEC("tp_btf/sys_enter")
+int BPF_PROG(sys_enter, 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(&args);
+ if (ret != MAP2_MAGIC)
+ test_err++;
+
+ return 0;
+}
+
+SEC("syscall")
+int syscall_prog(void *ctx)
+{
+ struct st_ops_args args = {};
+ int ret;
+
+ ret = bpf_kfunc_multi_st_ops_test_1(&args);
+ if (ret != MAP2_MAGIC)
+ test_err++;
+
+ return 0;
+}
+
+SEC(".struct_ops.link")
+struct bpf_testmod_multi_st_ops st_ops_map = {
+ .test_1 = (void *)test_1,
+};
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v2 2/3] selftests/bpf: Add multi_st_ops that supports multiple instances
2025-08-06 16:25 ` [PATCH bpf-next v2 2/3] selftests/bpf: Add multi_st_ops that supports multiple instances Amery Hung
@ 2025-08-06 23:16 ` Martin KaFai Lau
0 siblings, 0 replies; 7+ messages in thread
From: Martin KaFai Lau @ 2025-08-06 23:16 UTC (permalink / raw)
To: Amery Hung
Cc: bpf, netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, kernel-team
On 8/6/25 9:25 AM, Amery Hung wrote:
> +int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id)
> +{
> + struct bpf_testmod_multi_st_ops *st_ops;
> + unsigned long flags;
> + int ret = -1;
> +
> + spin_lock_irqsave(&multi_st_ops_lock, flags);
> + st_ops = multi_st_ops_find_nolock(id);
> + if (st_ops)
> + ret = st_ops->test_1(args);
test_1 cannot be NULL,
> + spin_unlock_irqrestore(&multi_st_ops_lock, flags);
> +
> + return ret;
> +}
> +
> +static int multi_st_ops_reg(void *kdata, struct bpf_link *link)
> +{
> + struct bpf_testmod_multi_st_ops *st_ops =
> + (struct bpf_testmod_multi_st_ops *)kdata;
> + unsigned long flags;
> + int err = 0;
> + u32 id;
> +
so I added a "if (!st_ops->test_1)" test.
> + id = bpf_struct_ops_id(kdata);
> +
> + spin_lock_irqsave(&multi_st_ops_lock, flags);
> + if (multi_st_ops_find_nolock(id)) {
> + pr_err("multi_st_ops(id:%d) has already been registered\n", id);
> + err = -EEXIST;
> + goto unlock;
> + }
> +
> + st_ops->id = id;
> + hlist_add_head(&st_ops->node, &multi_st_ops_list);
> +unlock:
> + spin_unlock_irqrestore(&multi_st_ops_lock, flags);
> +
> + return err;
> +}
[ ... ]
> diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
> index c9fab51f16e2..b8001ba7c368 100644
> --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
> +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
> @@ -116,4 +116,12 @@ struct bpf_testmod_st_ops {
> struct module *owner;
> };
>
> +#define BPF_TESTMOD_NAME_SZ 16
Not sure why it is here. I don't see it is used, so removed.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v2 3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs
2025-08-06 16:25 ` [PATCH bpf-next v2 3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs Amery Hung
@ 2025-08-06 23:20 ` Martin KaFai Lau
0 siblings, 0 replies; 7+ messages in thread
From: Martin KaFai Lau @ 2025-08-06 23:20 UTC (permalink / raw)
To: Amery Hung
Cc: netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, kernel-team, bpf
On 8/6/25 9:25 AM, Amery Hung wrote:
> +static void test_st_ops_id_ops_mapping(void)
> +{
> + struct struct_ops_id_ops_mapping1 *skel1 = NULL;
> + struct struct_ops_id_ops_mapping2 *skel2 = NULL;
> + LIBBPF_OPTS(bpf_test_run_opts, topts);
A default topts is not needed. Passing NULL is as good, so removed.
> + struct bpf_map_info info = {};
> + __u32 len = sizeof(info);
> + int err, pid, prog1_fd, prog2_fd;
> +
> + skel1 = struct_ops_id_ops_mapping1__open_and_load();
> + if (!ASSERT_OK_PTR(skel1, "struct_ops_id_ops_mapping1__open"))
> + goto out;
> +
> + skel2 = struct_ops_id_ops_mapping2__open_and_load();
> + if (!ASSERT_OK_PTR(skel2, "struct_ops_id_ops_mapping2__open"))
> + goto out;
> +
> + err = bpf_map_get_info_by_fd(bpf_map__fd(skel1->maps.st_ops_map),
> + &info, &len);
> + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd"))
> + goto out;
> +
> + skel1->bss->st_ops_id = info.id;
> +
> + err = bpf_map_get_info_by_fd(bpf_map__fd(skel2->maps.st_ops_map),
> + &info, &len);
> + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd"))
> + goto out;
> +
> + skel2->bss->st_ops_id = info.id;
> +
> + err = struct_ops_id_ops_mapping1__attach(skel1);
> + if (!ASSERT_OK(err, "struct_ops_id_ops_mapping1__attach"))
> + goto out;
> +
> + err = struct_ops_id_ops_mapping2__attach(skel2);
> + if (!ASSERT_OK(err, "struct_ops_id_ops_mapping2__attach"))
> + goto out;
> +
> + /* run tracing prog that calls .test_1 and checks return */
> + pid = getpid();
> + skel1->bss->test_pid = pid;
> + skel2->bss->test_pid = pid;
> + sys_gettid();
> + skel1->bss->test_pid = 0;
> + skel2->bss->test_pid = 0;
> +
> + /* run syscall_prog that calls .test_1 and checks return */
> + prog1_fd = bpf_program__fd(skel1->progs.syscall_prog);
> + err = bpf_prog_test_run_opts(prog1_fd, &topts);
> + ASSERT_OK(err, "bpf_prog_test_run_opts");
> +
> + prog2_fd = bpf_program__fd(skel2->progs.syscall_prog);
> + err = bpf_prog_test_run_opts(prog2_fd, &topts);
> + ASSERT_OK(err, "bpf_prog_test_run_opts");
> +
> + ASSERT_EQ(skel1->bss->test_err, 0, "skel1->bss->test_err");
> + ASSERT_EQ(skel2->bss->test_err, 0, "skel2->bss->test_err");
> +
> +out:
> + if (skel1)
> + struct_ops_id_ops_mapping1__destroy(skel1);
> + if (skel2)
NULL check on skel[12] is not needed, so removed.
Applied. Thanks.
> + struct_ops_id_ops_mapping2__destroy(skel2);
> +}
> +
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to
2025-08-06 16:25 [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to Amery Hung
` (2 preceding siblings ...)
2025-08-06 16:25 ` [PATCH bpf-next v2 3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs Amery Hung
@ 2025-08-06 23:20 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-08-06 23:20 UTC (permalink / raw)
To: Amery Hung
Cc: bpf, netdev, alexei.starovoitov, andrii, daniel, tj, memxor,
martin.lau, kernel-team
Hello:
This series was applied to bpf/bpf-next.git (master)
by Martin KaFai Lau <martin.lau@kernel.org>:
On Wed, 6 Aug 2025 09:25:37 -0700 you wrote:
> v1 -> v2
> Add bpf_struct_ops_id() instead of using bpf_struct_ops_get()
>
> Hi,
>
> This patchset allows struct_ops implementors to get map id from kdata in
> reg(), unreg() and update() so that they create an id to struct_ops
> instance mapping. This in turn allows struct_ops kfuncs to refer to the
> calling instance without passing a pointer to the struct_ops. The selftest
> provides an end-to-end example.
>
> [...]
Here is the summary with links:
- [bpf-next,v2,1/3] bpf: Allow struct_ops to get map id by kdata
https://git.kernel.org/bpf/bpf-next/c/d87a513d0937
- [bpf-next,v2,2/3] selftests/bpf: Add multi_st_ops that supports multiple instances
https://git.kernel.org/bpf/bpf-next/c/eeb52b6279cf
- [bpf-next,v2,3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs
https://git.kernel.org/bpf/bpf-next/c/ba7000f1c360
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-08-06 23:20 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-06 16:25 [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 1/3] bpf: Allow struct_ops to get map id by kdata Amery Hung
2025-08-06 16:25 ` [PATCH bpf-next v2 2/3] selftests/bpf: Add multi_st_ops that supports multiple instances Amery Hung
2025-08-06 23:16 ` Martin KaFai Lau
2025-08-06 16:25 ` [PATCH bpf-next v2 3/3] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs Amery Hung
2025-08-06 23:20 ` Martin KaFai Lau
2025-08-06 23:20 ` [PATCH bpf-next v2 0/3] Allow struct_ops to create map id to patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).