All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lorenz Bauer <lmb@cloudflare.com>
To: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
	jakub@cloudflare.com
Cc: kernel-team@cloudflare.com, bpf@vger.kernel.org,
	netdev@vger.kernel.org, Lorenz Bauer <lmb@cloudflare.com>
Subject: [PATCH bpf-next 3/8] bpf: allow multiple programs in BPF_PROG_TEST_RUN
Date: Tue, 16 Feb 2021 10:57:08 +0000	[thread overview]
Message-ID: <20210216105713.45052-4-lmb@cloudflare.com> (raw)
In-Reply-To: <20210216105713.45052-1-lmb@cloudflare.com>

The sk_lookup hook allows installing multiple BPF programs
simultaneously and has defined semantics. We therefore need
to be able to test multiple programs with one PROG_TEST_RUN
call. Extend the UAPI to include a prog_fds array which
enables this case. Passing an array with a single fd falls
back to current behaviour. Program types that allow multiple
programs have to provide a new test_run_array callback.

Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
---
 include/linux/bpf-netns.h      |  2 +
 include/linux/bpf.h            |  3 ++
 include/uapi/linux/bpf.h       |  6 ++-
 kernel/bpf/net_namespace.c     |  2 +-
 kernel/bpf/syscall.c           | 73 ++++++++++++++++++++++++++++++----
 tools/include/uapi/linux/bpf.h |  6 ++-
 6 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/include/linux/bpf-netns.h b/include/linux/bpf-netns.h
index 722f799c1a2e..f34800cd7017 100644
--- a/include/linux/bpf-netns.h
+++ b/include/linux/bpf-netns.h
@@ -5,6 +5,8 @@
 #include <linux/mutex.h>
 #include <uapi/linux/bpf.h>
 
+#define BPF_SK_LOOKUP_MAX_PROGS	64
+
 enum netns_bpf_attach_type {
 	NETNS_BPF_INVALID = -1,
 	NETNS_BPF_FLOW_DISSECTOR = 0,
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 875f6bc4bf1d..67c21c8ba7cc 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -26,6 +26,7 @@ struct bpf_verifier_env;
 struct bpf_verifier_log;
 struct perf_event;
 struct bpf_prog;
+struct bpf_prog_array;
 struct bpf_prog_aux;
 struct bpf_map;
 struct sock;
@@ -437,6 +438,8 @@ bpf_ctx_record_field_size(struct bpf_insn_access_aux *aux, u32 size)
 struct bpf_prog_ops {
 	int (*test_run)(struct bpf_prog *prog, const union bpf_attr *kattr,
 			union bpf_attr __user *uattr);
+	int (*test_run_array)(struct bpf_prog_array *progs, const union bpf_attr *kattr,
+			      union bpf_attr __user *uattr);
 };
 
 struct bpf_verifier_ops {
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 4c24daa43bac..b37a0f39b95f 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -589,7 +589,9 @@ union bpf_attr {
 	};
 
 	struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
-		__u32		prog_fd;
+		__u32		prog_fd;	/* input: program to test. mutually exclusive with
+						 *   prog_fds.
+						 */
 		__u32		retval;
 		__u32		data_size_in;	/* input: len of data_in */
 		__u32		data_size_out;	/* input/output: len of data_out
@@ -609,6 +611,8 @@ union bpf_attr {
 		__aligned_u64	ctx_out;
 		__u32		flags;
 		__u32		cpu;
+		__aligned_u64	prog_fds;
+		__u32		prog_fds_cnt;
 	} test;
 
 	struct { /* anonymous struct used by BPF_*_GET_*_ID */
diff --git a/kernel/bpf/net_namespace.c b/kernel/bpf/net_namespace.c
index 542f275bf252..61e4769f0110 100644
--- a/kernel/bpf/net_namespace.c
+++ b/kernel/bpf/net_namespace.c
@@ -411,7 +411,7 @@ static int netns_bpf_max_progs(enum netns_bpf_attach_type type)
 	case NETNS_BPF_FLOW_DISSECTOR:
 		return 1;
 	case NETNS_BPF_SK_LOOKUP:
-		return 64;
+		return BPF_SK_LOOKUP_MAX_PROGS;
 	default:
 		return 0;
 	}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index c859bc46d06c..f8c7b9d86b3f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3100,13 +3100,17 @@ static int bpf_prog_query(const union bpf_attr *attr,
 	}
 }
 
-#define BPF_PROG_TEST_RUN_LAST_FIELD test.cpu
+#define BPF_PROG_TEST_RUN_LAST_FIELD test.prog_fds_cnt
 
 static int bpf_prog_test_run(const union bpf_attr *attr,
 			     union bpf_attr __user *uattr)
 {
+	enum bpf_prog_type prog_type = BPF_PROG_TYPE_UNSPEC;
+	u32 prog_fds[BPF_SK_LOOKUP_MAX_PROGS];
+	struct bpf_prog_array *progs = NULL;
 	struct bpf_prog *prog;
-	int ret = -ENOTSUPP;
+	u32 prog_cnt;
+	int i, ret;
 
 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
 		return -EINVAL;
@@ -3119,14 +3123,67 @@ static int bpf_prog_test_run(const union bpf_attr *attr,
 	    (!attr->test.ctx_size_out && attr->test.ctx_out))
 		return -EINVAL;
 
-	prog = bpf_prog_get(attr->test.prog_fd);
-	if (IS_ERR(prog))
-		return PTR_ERR(prog);
+	if ((attr->test.prog_fds && !attr->test.prog_fds_cnt) ||
+	    (!attr->test.prog_fds && attr->test.prog_fds_cnt))
+		return -EINVAL;
 
-	if (prog->aux->ops->test_run)
-		ret = prog->aux->ops->test_run(prog, attr, uattr);
+	if (attr->test.prog_fds) {
+		u32 __user *uprog_fds = u64_to_user_ptr(attr->test.prog_fds);
 
-	bpf_prog_put(prog);
+		if (attr->test.prog_fds_cnt >= ARRAY_SIZE(prog_fds))
+			return -EINVAL;
+
+		if (attr->test.prog_fd)
+			return -EINVAL;
+
+		prog_cnt = attr->test.prog_fds_cnt;
+		if (copy_from_user(prog_fds, uprog_fds, prog_cnt * sizeof(prog_fds[0])))
+			return -EFAULT;
+	} else {
+		prog_cnt = 1;
+		prog_fds[0] = attr->test.prog_fd;
+	}
+
+	progs = bpf_prog_array_alloc(prog_cnt, GFP_KERNEL);
+	if (!progs)
+		return -ENOMEM;
+
+	for (i = 0; i < prog_cnt; i++) {
+		prog = bpf_prog_get(prog_fds[i]);
+		if (IS_ERR(prog)) {
+			ret = PTR_ERR(prog);
+			goto out;
+		}
+
+		progs->items[i].prog = prog;
+
+		if (prog_type && prog->type != prog_type) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		prog_type = prog->type;
+	}
+
+	prog = progs->items[0].prog;
+	if (prog->aux->ops->test_run_array) {
+		ret = prog->aux->ops->test_run_array(progs, attr, uattr);
+	} else if (prog->aux->ops->test_run) {
+		if (prog_cnt > 1) {
+			ret = -EOPNOTSUPP;
+			goto out;
+		}
+
+		ret = prog->aux->ops->test_run(progs->items[0].prog, attr, uattr);
+	} else {
+		ret = -ENOTSUPP;
+	}
+
+out:
+	for (i = 0; i < prog_cnt; i++)
+		if (progs->items[i].prog)
+			bpf_prog_put(progs->items[i].prog);
+	bpf_prog_array_free(progs);
 	return ret;
 }
 
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 4c24daa43bac..b37a0f39b95f 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -589,7 +589,9 @@ union bpf_attr {
 	};
 
 	struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
-		__u32		prog_fd;
+		__u32		prog_fd;	/* input: program to test. mutually exclusive with
+						 *   prog_fds.
+						 */
 		__u32		retval;
 		__u32		data_size_in;	/* input: len of data_in */
 		__u32		data_size_out;	/* input/output: len of data_out
@@ -609,6 +611,8 @@ union bpf_attr {
 		__aligned_u64	ctx_out;
 		__u32		flags;
 		__u32		cpu;
+		__aligned_u64	prog_fds;
+		__u32		prog_fds_cnt;
 	} test;
 
 	struct { /* anonymous struct used by BPF_*_GET_*_ID */
-- 
2.27.0


  parent reply	other threads:[~2021-02-16 11:00 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-16 10:57 [PATCH bpf-next 0/8] PROG_TEST_RUN support for sk_lookup programs Lorenz Bauer
2021-02-16 10:57 ` [PATCH bpf-next 1/8] bpf: consolidate shared test timing code Lorenz Bauer
2021-02-16 10:57 ` [PATCH bpf-next 2/8] bpf: add for_each_bpf_prog helper Lorenz Bauer
2021-02-16 10:57 ` Lorenz Bauer [this message]
2021-02-16 10:57 ` [PATCH bpf-next 4/8] bpf: add PROG_TEST_RUN support for sk_lookup programs Lorenz Bauer
2021-02-23  1:11   ` Alexei Starovoitov
2021-02-23 10:10     ` Lorenz Bauer
2021-02-24  6:11       ` Alexei Starovoitov
2021-02-16 10:57 ` [PATCH bpf-next 5/8] tools: libbpf: allow testing program types with multi-prog semantics Lorenz Bauer
2021-02-16 10:57 ` [PATCH bpf-next 6/8] selftests: bpf: convert sk_lookup multi prog tests to PROG_TEST_RUN Lorenz Bauer
2021-02-16 10:57 ` [PATCH bpf-next 7/8] selftests: bpf: convert sk_lookup ctx access " Lorenz Bauer
2021-02-16 10:57 ` [PATCH bpf-next 8/8] selftests: bpf: check that PROG_TEST_RUN repeats as requested Lorenz Bauer
2021-02-17 20:08 ` [PATCH bpf-next 0/8] PROG_TEST_RUN support for sk_lookup programs John Fastabend
2021-02-23  7:29 ` Andrii Nakryiko
2021-02-23 10:12   ` Lorenz Bauer
2021-02-24 21:37   ` Daniel Borkmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210216105713.45052-4-lmb@cloudflare.com \
    --to=lmb@cloudflare.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=jakub@cloudflare.com \
    --cc=kernel-team@cloudflare.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.