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
next prev parent 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 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.