--- v1
+++ v4
@@ -1,115 +1,95 @@
-Currently the test of BPF STRUCT_OPS depends on the specific bpf
-implementation of tcp_congestion_ops, but it can not cover all
-basic functionalities (e.g, return value handling), so introduce
-a dummy BPF STRUCT_OPS for test purpose.
-
-Loading a bpf_dummy_ops implementation from userspace is prohibited,
-and its only purpose is to run BPF_PROG_TYPE_STRUCT_OPS program
-through bpf(BPF_PROG_TEST_RUN).
+Factor out a helper bpf_struct_ops_prepare_trampoline() to prepare
+trampoline for BPF_PROG_TYPE_STRUCT_OPS prog. It will be used by
+.test_run callback in following patch.
Signed-off-by: Hou Tao <houtao1@huawei.com>
+Acked-by: Martin KaFai Lau <kafai@fb.com>
---
- include/linux/bpf_dummy_ops.h | 14 ++++++++++
- kernel/bpf/bpf_struct_ops_types.h | 2 ++
- net/bpf/Makefile | 3 +++
- net/bpf/bpf_dummy_struct_ops.c | 44 +++++++++++++++++++++++++++++++
- 4 files changed, 63 insertions(+)
- create mode 100644 include/linux/bpf_dummy_ops.h
- create mode 100644 net/bpf/bpf_dummy_struct_ops.c
+ include/linux/bpf.h | 4 ++++
+ kernel/bpf/bpf_struct_ops.c | 29 +++++++++++++++++++----------
+ 2 files changed, 23 insertions(+), 10 deletions(-)
-diff --git a/include/linux/bpf_dummy_ops.h b/include/linux/bpf_dummy_ops.h
-new file mode 100644
-index 000000000000..a594ae830eba
---- /dev/null
-+++ b/include/linux/bpf_dummy_ops.h
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+/*
-+ * Copyright (C) 2021. Huawei Technologies Co., Ltd
-+ */
-+#ifndef _BPF_DUMMY_OPS_H
-+#define _BPF_DUMMY_OPS_H
+diff --git a/include/linux/bpf.h b/include/linux/bpf.h
+index 31421c74ba08..3d2cf94a72ce 100644
+--- a/include/linux/bpf.h
++++ b/include/linux/bpf.h
+@@ -999,6 +999,10 @@ bool bpf_struct_ops_get(const void *kdata);
+ void bpf_struct_ops_put(const void *kdata);
+ int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key,
+ void *value);
++int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_progs *tprogs,
++ struct bpf_prog *prog,
++ const struct btf_func_model *model,
++ void *image, void *image_end);
+ static inline bool bpf_try_module_get(const void *data, struct module *owner)
+ {
+ if (owner == BPF_MODULE_OWNER)
+diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
+index 9abcc33f02cf..44be101f2562 100644
+--- a/kernel/bpf/bpf_struct_ops.c
++++ b/kernel/bpf/bpf_struct_ops.c
+@@ -312,6 +312,20 @@ static int check_zero_holes(const struct btf_type *t, void *data)
+ return 0;
+ }
+
++int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_progs *tprogs,
++ struct bpf_prog *prog,
++ const struct btf_func_model *model,
++ void *image, void *image_end)
++{
++ u32 flags;
+
-+typedef int (*bpf_dummy_ops_init_t)(void);
-+
-+struct bpf_dummy_ops {
-+ bpf_dummy_ops_init_t init;
-+};
-+
-+#endif
-diff --git a/kernel/bpf/bpf_struct_ops_types.h b/kernel/bpf/bpf_struct_ops_types.h
-index 066d83ea1c99..02c86cf9c207 100644
---- a/kernel/bpf/bpf_struct_ops_types.h
-+++ b/kernel/bpf/bpf_struct_ops_types.h
-@@ -2,6 +2,8 @@
- /* internal file - do not include directly */
-
- #ifdef CONFIG_BPF_JIT
-+#include <linux/bpf_dummy_ops.h>
-+BPF_STRUCT_OPS_TYPE(bpf_dummy_ops)
- #ifdef CONFIG_INET
- #include <net/tcp.h>
- BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)
-diff --git a/net/bpf/Makefile b/net/bpf/Makefile
-index 1c0a98d8c28f..1ebe270bde23 100644
---- a/net/bpf/Makefile
-+++ b/net/bpf/Makefile
-@@ -1,2 +1,5 @@
- # SPDX-License-Identifier: GPL-2.0-only
- obj-$(CONFIG_BPF_SYSCALL) := test_run.o
-+ifeq ($(CONFIG_BPF_JIT),y)
-+obj-$(CONFIG_BPF_SYSCALL) += bpf_dummy_struct_ops.o
-+endif
-diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c
-new file mode 100644
-index 000000000000..1249e4bb4ccb
---- /dev/null
-+++ b/net/bpf/bpf_dummy_struct_ops.c
-@@ -0,0 +1,44 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021. Huawei Technologies Co., Ltd
-+ */
-+#include <linux/kernel.h>
-+#include <linux/bpf_verifier.h>
-+#include <linux/bpf.h>
-+#include <linux/btf.h>
-+#include <linux/bpf_dummy_ops.h>
-+
-+extern struct bpf_struct_ops bpf_bpf_dummy_ops;
-+
-+static int bpf_dummy_init(struct btf *btf)
-+{
-+ return 0;
++ tprogs[BPF_TRAMP_FENTRY].progs[0] = prog;
++ tprogs[BPF_TRAMP_FENTRY].nr_progs = 1;
++ flags = model->ret_size > 0 ? BPF_TRAMP_F_RET_FENTRY_RET : 0;
++ return arch_prepare_bpf_trampoline(NULL, image, image_end,
++ model, flags, tprogs, NULL);
+}
+
-+static const struct bpf_verifier_ops bpf_dummy_verifier_ops = {
-+};
-+
-+static int bpf_dummy_init_member(const struct btf_type *t,
-+ const struct btf_member *member,
-+ void *kdata, const void *udata)
-+{
-+ return -EOPNOTSUPP;
-+}
-+
-+static int bpf_dummy_reg(void *kdata)
-+{
-+ return -EOPNOTSUPP;
-+}
-+
-+static void bpf_dummy_unreg(void *kdata)
-+{
-+}
-+
-+struct bpf_struct_ops bpf_bpf_dummy_ops = {
-+ .verifier_ops = &bpf_dummy_verifier_ops,
-+ .init = bpf_dummy_init,
-+ .init_member = bpf_dummy_init_member,
-+ .reg = bpf_dummy_reg,
-+ .unreg = bpf_dummy_unreg,
-+ .name = "bpf_dummy_ops",
-+};
+ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
+ void *value, u64 flags)
+ {
+@@ -323,7 +337,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
+ struct bpf_tramp_progs *tprogs = NULL;
+ void *udata, *kdata;
+ int prog_fd, err = 0;
+- void *image;
++ void *image, *image_end;
+ u32 i;
+
+ if (flags)
+@@ -363,12 +377,12 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
+ udata = &uvalue->data;
+ kdata = &kvalue->data;
+ image = st_map->image;
++ image_end = st_map->image + PAGE_SIZE;
+
+ for_each_member(i, t, member) {
+ const struct btf_type *mtype, *ptype;
+ struct bpf_prog *prog;
+ u32 moff;
+- u32 flags;
+
+ moff = btf_member_bit_offset(t, member) / 8;
+ ptype = btf_type_resolve_ptr(btf_vmlinux, member->type, NULL);
+@@ -430,14 +444,9 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
+ goto reset_unlock;
+ }
+
+- tprogs[BPF_TRAMP_FENTRY].progs[0] = prog;
+- tprogs[BPF_TRAMP_FENTRY].nr_progs = 1;
+- flags = st_ops->func_models[i].ret_size > 0 ?
+- BPF_TRAMP_F_RET_FENTRY_RET : 0;
+- err = arch_prepare_bpf_trampoline(NULL, image,
+- st_map->image + PAGE_SIZE,
+- &st_ops->func_models[i],
+- flags, tprogs, NULL);
++ err = bpf_struct_ops_prepare_trampoline(tprogs, prog,
++ &st_ops->func_models[i],
++ image, image_end);
+ if (err < 0)
+ goto reset_unlock;
+
--
2.29.2