Skip to contentSkip to conversation

Registering struct_ops types from modules.

RFC Superseded [email protected] 3 participants 3 messages Sep 7, 2023 – Sep 8, 2023

Subsystems (4)

v1 of 17 Superseded Latest is v17 →

lore
Share & tools
lore
#0 lore raw

RFC 1/1 Registering struct_ops types from modules.

From: Kui-Feng Lee <[email protected]>

Resend to remove noise!

Given the current constraints of the current implementation, struct_ops cannot be registered dynamically. This presents a significant limitation for modules like fuse-bpf, which seeks to implement a new struct_ops type. To address this issue, here it proposes the introduction of a new API. This API will enable the registering of new struct_ops types from modules.

The following code is an example of how to implement a new struct_ops type in a module with the proposed API. It adds a new type bpf_testmod_ops in the bpf_testmod module. And, call register_bpf_struct_ops() and unregister_bpf_struct_ops() when init and exit the module.

A module may forget or be unable to call unregister_bpf_struct_ops(). That may cause tragedies. So, the bpf_struct_ops subsystem should handle it automatically, as a fallback, when the module registered a struct_ops type is unloaded.

---
 .../selftests/bpf/bpf_testmod/bpf_testmod.c   | 58 +++++++++++++++++++
 .../selftests/bpf/bpf_testmod/bpf_testmod.h   |  5 ++
 .../bpf/prog_tests/test_struct_ops_module.c   | 49 ++++++++++++++++
 .../selftests/bpf/progs/struct_ops_module.c   | 27 +++++++++
 9 files changed, 170 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c
 create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_module.c
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +58 -0
index cefc5dd72573..5687ad53a093 100644
@@ -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/error-injection.h>
@@ -517,11 +518,62 @@ 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)
 
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+
+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 0;
+}
+
+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)
+{
+	return 0;
+}
+
+static void bpf_dummy_unreg(void *kdata)
+{
+}
+
+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,
+	.name = "bpf_testmod_ops",
+};
+
+static struct bpf_struct_ops_mod bpf_testmod_struct_ops = {
+	.owner = THIS_MODULE,
+	.st_ops = &bpf_bpf_testmod_ops,
+};
+
+#endif /* CONFIG_DEBUG_INFO_BTF_MODULES */
+
 extern int bpf_fentry_test1(int a);
 
 static int bpf_testmod_init(void)
@@ -532,6 +584,9 @@ 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);
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+	ret = ret ?: register_bpf_struct_ops(&bpf_testmod_struct_ops);
+#endif
 	if (ret < 0)
 		return ret;
 	if (bpf_fentry_test1(0) < 0)
@@ -541,6 +596,9 @@ static int bpf_testmod_init(void)
 
 static void bpf_testmod_exit(void)
 {
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+	unregister_bpf_struct_ops(&bpf_testmod_struct_ops);
+#endif
 	return sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file);
 }
 
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h +5 -0
index f32793efe095..ca5435751c79 100644
@@ -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 */
tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c new file +49 -0

49 lines not on this page · raw message

tools/testing/selftests/bpf/progs/struct_ops_module.c new file +27 -0
new file mode 100644
index 000000000000..e77d29ae29a1
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 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";
+
+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)
+{
+	return a + b;
+}
+
+SEC(".struct_ops.link")
+struct bpf_testmod_ops testmod_1 = {
+	.test_1 = (void *)test_1,
+	.test_2 = (void *)test_2,
+};
+
Signature · 1 line
2.34.1
#1 lore raw
Quoted 12 lines · On Thu, Sep 7, 2023 at 1:32 PM <[email protected]> wrote:

From: Kui-Feng Lee <[email protected]>

Resend to remove noise!

Given the current constraints of the current implementation, struct_ops cannot be registered dynamically. This presents a significant limitation for modules like fuse-bpf, which seeks to implement a new struct_ops type. To address this issue, here it proposes the introduction of a new API. This API will enable the registering of new struct_ops types from modules.

Quoted 4 lines

The following code is an example of how to implement a new struct_ops type in a module with the proposed API. It adds a new type bpf_testmod_ops in the bpf_testmod module. And, call register_bpf_struct_ops() and unregister_bpf_struct_ops() when init and exit the module.

register_bpf_struct_ops() api implementation is missing in the diff.

#2 lore raw
Quoted 13 lines · Alexei Starovoitov
Quoted 12 lines · On Thu, Sep 7, 2023 at 1:32 PM <[email protected]> wrote:

From: Kui-Feng Lee <[email protected]>

Resend to remove noise!

Given the current constraints of the current implementation, struct_ops cannot be registered dynamically. This presents a significant limitation for modules like fuse-bpf, which seeks to implement a new struct_ops type. To address this issue, here it proposes the introduction of a new API. This API will enable the registering of new struct_ops types from modules.

Quoted 6 lines
Quoted 4 lines

The following code is an example of how to implement a new struct_ops type in a module with the proposed API. It adds a new type bpf_testmod_ops in the bpf_testmod module. And, call register_bpf_struct_ops() and unregister_bpf_struct_ops() when init and exit the module.

register_bpf_struct_ops() api implementation is missing in the diff.

Sorry for the confusion!
The purpose of this RFC to check how people think about the API itself.