bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eduard Zingerman <eddyz87@gmail.com>
To: bpf@vger.kernel.org, ast@kernel.org
Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev,
	kernel-team@fb.com, yhs@fb.com,
	Eduard Zingerman <eddyz87@gmail.com>
Subject: [PATCH bpf-next 01/24] selftests/bpf: Add notion of auxiliary programs for test_loader
Date: Fri, 21 Apr 2023 20:42:11 +0300	[thread overview]
Message-ID: <20230421174234.2391278-2-eddyz87@gmail.com> (raw)
In-Reply-To: <20230421174234.2391278-1-eddyz87@gmail.com>

In order to express test cases that use bpf_tail_call() intrinsic it
is necessary to have several programs to be loaded at a time.
This commit adds __auxiliary annotation to the set of annotations
supported by test_loader.c. Programs marked as auxiliary are always
loaded but are not treated as a separate test.

For example:

    void dummy_prog1(void);

    struct {
            __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
            __uint(max_entries, 4);
            __uint(key_size, sizeof(int));
            __array(values, void (void));
    } prog_map SEC(".maps") = {
            .values = {
                    [0] = (void *) &dummy_prog1,
            },
    };

    SEC("tc")
    __auxiliary
    __naked void dummy_prog1(void) {
            asm volatile ("r0 = 42; exit;");
    }

    SEC("tc")
    __description("reference tracking: check reference or tail call")
    __success __retval(0)
    __naked void check_reference_or_tail_call(void)
    {
            asm volatile (
            "r2 = %[prog_map] ll;"
            "r3 = 0;"
            "call %[bpf_tail_call];"
            "r0 = 0;"
            "exit;"
            :: __imm(bpf_tail_call),
            :  __clobber_all);
    }

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 tools/testing/selftests/bpf/progs/bpf_misc.h |  6 ++
 tools/testing/selftests/bpf/test_loader.c    | 89 +++++++++++++++-----
 2 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 3b307de8dab9..d3c1217ba79a 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -53,6 +53,10 @@
  *                   - A numeric value.
  *                   Multiple __flag attributes could be specified, the final flags
  *                   value is derived by applying binary "or" to all specified values.
+ *
+ * __auxiliary         Annotated program is not a separate test, but used as auxiliary
+ *                     for some other test cases and should always be loaded.
+ * __auxiliary_unpriv  Same, but load program in unprivileged mode.
  */
 #define __msg(msg)		__attribute__((btf_decl_tag("comment:test_expect_msg=" msg)))
 #define __failure		__attribute__((btf_decl_tag("comment:test_expect_failure")))
@@ -65,6 +69,8 @@
 #define __flag(flag)		__attribute__((btf_decl_tag("comment:test_prog_flags="#flag)))
 #define __retval(val)		__attribute__((btf_decl_tag("comment:test_retval="#val)))
 #define __retval_unpriv(val)	__attribute__((btf_decl_tag("comment:test_retval_unpriv="#val)))
+#define __auxiliary		__attribute__((btf_decl_tag("comment:test_auxiliary")))
+#define __auxiliary_unpriv	__attribute__((btf_decl_tag("comment:test_auxiliary_unpriv")))
 
 /* Convenience macro for use with 'asm volatile' blocks */
 #define __naked __attribute__((naked))
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index 40c9b7d532c4..b4edd8454934 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -25,6 +25,8 @@
 #define TEST_TAG_DESCRIPTION_PFX "comment:test_description="
 #define TEST_TAG_RETVAL_PFX "comment:test_retval="
 #define TEST_TAG_RETVAL_PFX_UNPRIV "comment:test_retval_unpriv="
+#define TEST_TAG_AUXILIARY "comment:test_auxiliary"
+#define TEST_TAG_AUXILIARY_UNPRIV "comment:test_auxiliary_unpriv"
 
 /* Warning: duplicated in bpf_misc.h */
 #define POINTER_VALUE	0xcafe4all
@@ -59,6 +61,8 @@ struct test_spec {
 	int log_level;
 	int prog_flags;
 	int mode_mask;
+	bool auxiliary;
+	bool valid;
 };
 
 static int tester_init(struct test_loader *tester)
@@ -87,6 +91,11 @@ static void free_test_spec(struct test_spec *spec)
 	free(spec->unpriv.name);
 	free(spec->priv.expect_msgs);
 	free(spec->unpriv.expect_msgs);
+
+	spec->priv.name = NULL;
+	spec->unpriv.name = NULL;
+	spec->priv.expect_msgs = NULL;
+	spec->unpriv.expect_msgs = NULL;
 }
 
 static int push_msg(const char *msg, struct test_subspec *subspec)
@@ -204,6 +213,12 @@ static int parse_test_spec(struct test_loader *tester,
 			spec->unpriv.expect_failure = false;
 			spec->mode_mask |= UNPRIV;
 			has_unpriv_result = true;
+		} else if (strcmp(s, TEST_TAG_AUXILIARY) == 0) {
+			spec->auxiliary = true;
+			spec->mode_mask |= PRIV;
+		} else if (strcmp(s, TEST_TAG_AUXILIARY_UNPRIV) == 0) {
+			spec->auxiliary = true;
+			spec->mode_mask |= UNPRIV;
 		} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
 			msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
 			err = push_msg(msg, &spec->priv);
@@ -314,6 +329,8 @@ static int parse_test_spec(struct test_loader *tester,
 		}
 	}
 
+	spec->valid = true;
+
 	return 0;
 
 cleanup:
@@ -516,16 +533,18 @@ void run_subtest(struct test_loader *tester,
 		 struct bpf_object_open_opts *open_opts,
 		 const void *obj_bytes,
 		 size_t obj_byte_cnt,
+		 struct test_spec *specs,
 		 struct test_spec *spec,
 		 bool unpriv)
 {
 	struct test_subspec *subspec = unpriv ? &spec->unpriv : &spec->priv;
+	struct bpf_program *tprog, *tprog_iter;
+	struct test_spec *spec_iter;
 	struct cap_state caps = {};
-	struct bpf_program *tprog;
 	struct bpf_object *tobj;
 	struct bpf_map *map;
-	int retval;
-	int err;
+	int retval, err, i;
+	bool should_load;
 
 	if (!test__start_subtest(subspec->name))
 		return;
@@ -546,15 +565,23 @@ void run_subtest(struct test_loader *tester,
 	if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */
 		goto subtest_cleanup;
 
-	bpf_object__for_each_program(tprog, tobj)
-		bpf_program__set_autoload(tprog, false);
+	i = 0;
+	bpf_object__for_each_program(tprog_iter, tobj) {
+		spec_iter = &specs[i++];
+		should_load = false;
+
+		if (spec_iter->valid) {
+			if (strcmp(bpf_program__name(tprog_iter), spec->prog_name) == 0) {
+				tprog = tprog_iter;
+				should_load = true;
+			}
 
-	bpf_object__for_each_program(tprog, tobj) {
-		/* only load specified program */
-		if (strcmp(bpf_program__name(tprog), spec->prog_name) == 0) {
-			bpf_program__set_autoload(tprog, true);
-			break;
+			if (spec_iter->auxiliary &&
+			    spec_iter->mode_mask & (unpriv ? UNPRIV : PRIV))
+				should_load = true;
 		}
+
+		bpf_program__set_autoload(tprog_iter, should_load);
 	}
 
 	prepare_case(tester, spec, tobj, tprog);
@@ -617,11 +644,12 @@ static void process_subtest(struct test_loader *tester,
 			    skel_elf_bytes_fn elf_bytes_factory)
 {
 	LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name);
+	struct test_spec *specs = NULL;
 	struct bpf_object *obj = NULL;
 	struct bpf_program *prog;
 	const void *obj_bytes;
+	int err, i, nr_progs;
 	size_t obj_byte_cnt;
-	int err;
 
 	if (tester_init(tester) < 0)
 		return; /* failed to initialize tester */
@@ -631,25 +659,42 @@ static void process_subtest(struct test_loader *tester,
 	if (!ASSERT_OK_PTR(obj, "obj_open_mem"))
 		return;
 
-	bpf_object__for_each_program(prog, obj) {
-		struct test_spec spec;
+	nr_progs = 0;
+	bpf_object__for_each_program(prog, obj)
+		++nr_progs;
+
+	specs = calloc(nr_progs, sizeof(struct test_spec));
+	if (!ASSERT_OK_PTR(specs, "Can't alloc specs array"))
+		return;
 
-		/* if we can't derive test specification, go to the next test */
-		err = parse_test_spec(tester, obj, prog, &spec);
-		if (err) {
+	i = 0;
+	bpf_object__for_each_program(prog, obj) {
+		/* ignore tests for which  we can't derive test specification */
+		err = parse_test_spec(tester, obj, prog, &specs[i++]);
+		if (err)
 			PRINT_FAIL("Can't parse test spec for program '%s'\n",
 				   bpf_program__name(prog));
+	}
+
+	i = 0;
+	bpf_object__for_each_program(prog, obj) {
+		struct test_spec *spec = &specs[i++];
+
+		if (!spec->valid || spec->auxiliary)
 			continue;
-		}
 
-		if (spec.mode_mask & PRIV)
-			run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt, &spec, false);
-		if (spec.mode_mask & UNPRIV)
-			run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt, &spec, true);
+		if (spec->mode_mask & PRIV)
+			run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt,
+				    specs, spec, false);
+		if (spec->mode_mask & UNPRIV)
+			run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt,
+				    specs, spec, true);
 
-		free_test_spec(&spec);
 	}
 
+	for (i = 0; i < nr_progs; ++i)
+		free_test_spec(&specs[i]);
+	free(specs);
 	bpf_object__close(obj);
 }
 
-- 
2.40.0


  reply	other threads:[~2023-04-21 17:43 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-21 17:42 [PATCH bpf-next 00/24] Second set of verifier/*.c migrated to inline assembly Eduard Zingerman
2023-04-21 17:42 ` Eduard Zingerman [this message]
2023-04-21 17:42 ` [PATCH bpf-next 02/24] selftests/bpf: verifier/bounds converted " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 03/24] selftests/bpf: verifier/bpf_get_stack " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 04/24] selftests/bpf: verifier/btf_ctx_access " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 05/24] selftests/bpf: verifier/ctx " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 06/24] selftests/bpf: verifier/d_path " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 07/24] selftests/bpf: verifier/direct_packet_access " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 08/24] selftests/bpf: verifier/jeq_infer_not_null " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 09/24] selftests/bpf: verifier/loops1 " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 10/24] selftests/bpf: verifier/lwt " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 11/24] selftests/bpf: verifier/map_in_map " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 12/24] selftests/bpf: verifier/map_ptr_mixing " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 13/24] selftests/bpf: verifier/precise " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 14/24] selftests/bpf: verifier/prevent_map_lookup " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 15/24] selftests/bpf: verifier/ref_tracking " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 16/24] selftests/bpf: verifier/regalloc " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 17/24] selftests/bpf: verifier/runtime_jit " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 18/24] selftests/bpf: verifier/search_pruning " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 19/24] selftests/bpf: verifier/sock " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 20/24] selftests/bpf: verifier/spin_lock " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 21/24] selftests/bpf: verifier/subreg " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 22/24] selftests/bpf: verifier/unpriv " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 23/24] selftests/bpf: verifier/value_illegal_alu " Eduard Zingerman
2023-04-21 17:42 ` [PATCH bpf-next 24/24] selftests/bpf: verifier/value_ptr_arith " Eduard Zingerman
2023-04-21 19:40 ` [PATCH bpf-next 00/24] Second set of verifier/*.c migrated " patchwork-bot+netdevbpf
2023-04-21 19:49   ` Eduard Zingerman
2023-04-21 19:53     ` Alexei Starovoitov
2023-04-21 19:48 ` Alexei Starovoitov
2023-04-21 20:00   ` Eduard Zingerman

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=20230421174234.2391278-2-eddyz87@gmail.com \
    --to=eddyz87@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@linux.dev \
    --cc=yhs@fb.com \
    /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 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).