bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).