Inter-revision diff: patch 1

Comparing rfc (message) to v4 (message)

--- vrfc
+++ v4
@@ -1,279 +1,95 @@
-Currently the test of BPF STRUCT_OPS depends on the specific bpf
-implementation of tcp_congestion_ops, and it can not cover all
-basic functionalities (e.g, return value handling), so introduce
-a dummy BPF STRUCT_OPS for test purpose.
-
-Dummy BPF STRUCT_OPS may not being needed for release kernel, so
-adding a kconfig option BPF_DUMMY_STRUCT_OPS to enable it separatedly.
+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     |  28 +++++
- kernel/bpf/Kconfig                |   7 ++
- kernel/bpf/Makefile               |   2 +
- kernel/bpf/bpf_dummy_struct_ops.c | 173 ++++++++++++++++++++++++++++++
- kernel/bpf/bpf_struct_ops_types.h |   4 +
- 5 files changed, 214 insertions(+)
- create mode 100644 include/linux/bpf_dummy_ops.h
- create mode 100644 kernel/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..b2aad3e6e2fe
---- /dev/null
-+++ b/include/linux/bpf_dummy_ops.h
-@@ -0,0 +1,28 @@
-+/* 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;
 +
-+#ifdef CONFIG_BPF_DUMMY_STRUCT_OPS
-+#include <linux/module.h>
-+
-+struct bpf_dummy_ops_state {
-+	int val;
-+};
-+
-+struct bpf_dummy_ops {
-+	int (*init)(struct bpf_dummy_ops_state *state);
-+	struct module *owner;
-+};
-+
-+extern struct bpf_dummy_ops *bpf_get_dummy_ops(void);
-+extern void bpf_put_dummy_ops(struct bpf_dummy_ops *ops);
-+#else
-+struct bpf_dummy_ops {};
-+static inline struct bpf_dummy_ops *bpf_get_dummy_ops(void) { return NULL; }
-+static inline void bpf_put_dummy_ops(struct bpf_dummy_ops *ops) {}
-+#endif
-+
-+#endif
-diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig
-index a82d6de86522..4a11eca42791 100644
---- a/kernel/bpf/Kconfig
-+++ b/kernel/bpf/Kconfig
-@@ -86,4 +86,11 @@ config BPF_LSM
- 
- 	  If you are unsure how to answer this question, answer N.
- 
-+config BPF_DUMMY_STRUCT_OPS
-+	bool "Enable dummy struct ops"
-+	depends on BPF_SYSCALL && BPF_JIT
-+	help
-+	  Enables dummy struct ops to test the basic functionalities of
-+	  BPF STRUCT_OPS.
-+
- endmenu # "BPF subsystem"
-diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
-index 7f33098ca63f..17e2bb59cceb 100644
---- a/kernel/bpf/Makefile
-+++ b/kernel/bpf/Makefile
-@@ -33,6 +33,8 @@ obj-$(CONFIG_DEBUG_INFO_BTF) += sysfs_btf.o
- endif
- ifeq ($(CONFIG_BPF_JIT),y)
- obj-$(CONFIG_BPF_SYSCALL) += bpf_struct_ops.o
-+obj-$(CONFIG_BPF_SYSCALL) += bpf_dummy_struct_ops.o
- obj-${CONFIG_BPF_LSM} += bpf_lsm.o
- endif
-+obj-$(CONFIG_BPF_DUMMY_STRUCT_OPS) += bpf_dummy_struct_ops.o
- obj-$(CONFIG_BPF_PRELOAD) += preload/
-diff --git a/kernel/bpf/bpf_dummy_struct_ops.c b/kernel/bpf/bpf_dummy_struct_ops.c
-new file mode 100644
-index 000000000000..f76c4a3733f0
---- /dev/null
-+++ b/kernel/bpf/bpf_dummy_struct_ops.c
-@@ -0,0 +1,173 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021. Huawei Technologies Co., Ltd
-+ */
-+#include <linux/kernel.h>
-+#include <linux/spinlock.h>
-+#include <linux/bpf_verifier.h>
-+#include <linux/bpf.h>
-+#include <linux/btf.h>
-+#include <linux/bpf_dummy_ops.h>
-+
-+static struct bpf_dummy_ops *bpf_dummy_ops_singletion;
-+static DEFINE_SPINLOCK(bpf_dummy_ops_lock);
-+
-+static const struct btf_type *dummy_ops_state;
-+
-+struct bpf_dummy_ops *bpf_get_dummy_ops(void)
-+{
-+	struct bpf_dummy_ops *ops;
-+
-+	spin_lock(&bpf_dummy_ops_lock);
-+	ops = bpf_dummy_ops_singletion;
-+	if (ops && !bpf_try_module_get(ops, ops->owner))
-+		ops = NULL;
-+	spin_unlock(&bpf_dummy_ops_lock);
-+
-+	return ops ? ops : ERR_PTR(-ENXIO);
-+}
-+EXPORT_SYMBOL_GPL(bpf_get_dummy_ops);
-+
-+void bpf_put_dummy_ops(struct bpf_dummy_ops *ops)
-+{
-+	bpf_module_put(ops, ops->owner);
-+}
-+EXPORT_SYMBOL_GPL(bpf_put_dummy_ops);
-+
-+static int bpf_dummy_init(struct btf *btf)
-+{
-+	s32 type_id;
-+
-+	type_id = btf_find_by_name_kind(btf, "bpf_dummy_ops_state",
-+					BTF_KIND_STRUCT);
-+	if (type_id < 0)
-+		return -EINVAL;
-+
-+	dummy_ops_state = btf_type_by_id(btf, type_id);
-+
-+	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_func_proto *
-+bpf_dummy_ops_get_func_proto(enum bpf_func_id func_id,
-+			     const struct bpf_prog *prog)
-+{
-+	switch (func_id) {
-+	case BPF_FUNC_map_lookup_elem:
-+		return &bpf_map_lookup_elem_proto;
-+	default:
-+		return NULL;
-+	}
-+}
-+
-+static bool bpf_dummy_ops_is_valid_access(int off, int size,
-+					  enum bpf_access_type type,
-+					  const struct bpf_prog *prog,
-+					  struct bpf_insn_access_aux *info)
-+{
-+	/* a common helper ? */
-+	if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS)
-+		return false;
-+	if (type != BPF_READ)
-+		return false;
-+	if (off % size != 0)
-+		return false;
-+
-+	return btf_ctx_access(off, size, type, prog, info);
-+}
-+
-+static int bpf_dummy_ops_btf_struct_access(struct bpf_verifier_log *log,
-+					   const struct btf *btf,
-+					   const struct btf_type *t, int off,
-+					   int size, enum bpf_access_type atype,
-+					   u32 *next_btf_id)
-+{
-+	size_t end;
-+
-+	if (atype == BPF_READ)
-+		return btf_struct_access(log, btf, t, off, size, atype,
-+					 next_btf_id);
-+
-+	if (t != dummy_ops_state) {
-+		bpf_log(log, "only read is supported\n");
-+		return -EACCES;
-+	}
-+
-+	switch (off) {
-+	case offsetof(struct bpf_dummy_ops_state, val):
-+		end = offsetofend(struct bpf_dummy_ops_state, val);
-+		break;
-+	default:
-+		bpf_log(log, "no write support to bpf_dummy_ops_state at off %d\n",
-+			off);
-+		return -EACCES;
-+	}
-+
-+	if (off + size > end) {
-+		bpf_log(log,
-+			"write access at off %d with size %d beyond the member of bpf_dummy_ops_state ended at %zu\n",
-+			off, size, end);
-+		return -EACCES;
-+	}
-+
-+	return NOT_INIT;
-+}
-+
-+static const struct bpf_verifier_ops bpf_dummy_verifier_ops = {
-+	.get_func_proto = bpf_dummy_ops_get_func_proto,
-+	.is_valid_access = bpf_dummy_ops_is_valid_access,
-+	.btf_struct_access = bpf_dummy_ops_btf_struct_access,
-+};
-+
-+static int bpf_dummy_check_member(const struct btf_type *t,
-+				  const struct btf_member *member)
-+{
-+	return 0;
-+}
-+
-+
-+static int bpf_dummy_init_member(const struct btf_type *t,
-+				 const struct btf_member *member,
-+				 void *kdata, const void *udata)
-+{
-+	return 0;
-+}
-+
-+static int bpf_dummy_reg(void *kdata)
-+{
-+	struct bpf_dummy_ops *ops = kdata;
-+	int err = 0;
-+
-+	spin_lock(&bpf_dummy_ops_lock);
-+	if (!bpf_dummy_ops_singletion)
-+		bpf_dummy_ops_singletion = ops;
-+	else
-+		err = -EEXIST;
-+	spin_unlock(&bpf_dummy_ops_lock);
-+
-+	return err;
-+}
-+
-+static void bpf_dummy_unreg(void *kdata)
-+{
-+	struct bpf_dummy_ops *ops = kdata;
-+
-+	spin_lock(&bpf_dummy_ops_lock);
-+	if (bpf_dummy_ops_singletion == ops)
-+		bpf_dummy_ops_singletion = NULL;
-+	else
-+		WARN_ON(1);
-+	spin_unlock(&bpf_dummy_ops_lock);
-+}
-+
-+extern struct bpf_struct_ops bpf_bpf_dummy_ops;
-+
-+struct bpf_struct_ops bpf_bpf_dummy_ops = {
-+	.verifier_ops = &bpf_dummy_verifier_ops,
-+	.init = bpf_dummy_init,
-+	.init_member = bpf_dummy_init_member,
-+	.check_member = bpf_dummy_check_member,
-+	.reg = bpf_dummy_reg,
-+	.unreg = bpf_dummy_unreg,
-+	.name = "bpf_dummy_ops",
-+};
-diff --git a/kernel/bpf/bpf_struct_ops_types.h b/kernel/bpf/bpf_struct_ops_types.h
-index 7ec458ead497..6d24c75f4d70 100644
---- a/kernel/bpf/bpf_struct_ops_types.h
-+++ b/kernel/bpf/bpf_struct_ops_types.h
-@@ -2,6 +2,10 @@
- /* internal file - do not include directly */
+ 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;
  
- #ifdef CONFIG_BPF_JIT
-+#ifdef CONFIG_BPF_DUMMY_STRUCT_OPS
-+#include <linux/bpf_dummy_ops.h>
-+BPF_STRUCT_OPS_TYPE(bpf_dummy_ops)
-+#endif
- #ifdef CONFIG_INET
- #include <net/tcp.h>
- BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)
+ 	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
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help