From: Eduard Zingerman <eddyz87@gmail.com>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: bpf@vger.kernel.org, ast@kernel.org, andrii@kernel.org,
daniel@iogearbox.net, kernel-team@fb.com, yhs@fb.com
Subject: Re: [PATCH bpf-next 1/4] selftests/bpf: support for BPF_F_TEST_STATE_FREQ in test_loader
Date: Thu, 22 Dec 2022 02:11:29 +0200 [thread overview]
Message-ID: <8492d922b7b2d1829e286ed48e8b0b44974500e0.camel@gmail.com> (raw)
In-Reply-To: <CAEf4BzZH0ZxorCi7nPDbRqSK9f+410RooNwNJGwfw8=0a5i1nw@mail.gmail.com>
On Tue, 2022-12-20 at 13:03 -0800, Andrii Nakryiko wrote:
> On Fri, Dec 16, 2022 at 6:17 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
> >
> > Adds a macro __test_state_freq, the macro expands as a btf_decl_tag of a
> > special form that instructs test_loader that the flag BPF_F_TEST_STATE_FREQ
> > has to be passed to BPF verifier when program is loaded.
> >
>
> I needed similar capabilities locally, but I went a slightly different
> direction. Instead of defining custom macros and logic, I define just
> __flags(X) macro and then parse flags either by their symbolic name
> (or just integer value, which might be useful sometimes for
> development purposes). I've also added support for matching multiple
> messages sequentially which locally is in the same commit. Feel free
> to ignore that part, but I think it's useful as well. So WDYT about
> the below?
Makes total sense. I can replace my patch with your patch in the
patchset, or just wait until your changes land.
>
>
> commit 936bb5d21d717d54c85e74047e082ca3216a7a40
> Author: Andrii Nakryiko <andrii@kernel.org>
> Date: Mon Dec 19 15:57:26 2022 -0800
>
> selftests/bpf: support custom per-test flags and multiple expected messages
>
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
>
> diff --git a/tools/testing/selftests/bpf/test_loader.c
> b/tools/testing/selftests/bpf/test_loader.c
> index 679efb3aa785..b0dab5dee38c 100644
> --- a/tools/testing/selftests/bpf/test_loader.c
> +++ b/tools/testing/selftests/bpf/test_loader.c
> @@ -13,12 +13,15 @@
> #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success"
> #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg="
> #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level="
> +#define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags="
>
> struct test_spec {
> const char *name;
> bool expect_failure;
> - const char *expect_msg;
> + const char **expect_msgs;
> + size_t expect_msg_cnt;
> int log_level;
> + int prog_flags;
> };
>
> static int tester_init(struct test_loader *tester)
> @@ -67,7 +70,8 @@ static int parse_test_spec(struct test_loader *tester,
>
> for (i = 1; i < btf__type_cnt(btf); i++) {
> const struct btf_type *t;
> - const char *s;
> + const char *s, *val;
> + char *e;
>
> t = btf__type_by_id(btf, i);
> if (!btf_is_decl_tag(t))
> @@ -82,14 +86,47 @@ static int parse_test_spec(struct test_loader *tester,
> } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) {
> spec->expect_failure = false;
> } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
> - spec->expect_msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
> + void *tmp;
> + const char **msg;
> +
> + tmp = realloc(spec->expect_msgs, (1 +
> spec->expect_msg_cnt) * sizeof(void *));
> + if (!tmp) {
> + ASSERT_FAIL("failed to realloc memory for messages\n");
> + return -ENOMEM;
> + }
> + spec->expect_msgs = tmp;
> + msg = &spec->expect_msgs[spec->expect_msg_cnt++];
> + *msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
> } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) {
> + val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1;
> errno = 0;
> - spec->log_level = strtol(s +
> sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1, NULL, 0);
> - if (errno) {
> + spec->log_level = strtol(val, &e, 0);
> + if (errno || e[0] != '\0') {
> ASSERT_FAIL("failed to parse test log level from '%s'", s);
> return -EINVAL;
> }
> + } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) {
> + val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1;
> + if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) {
> + spec->prog_flags |= BPF_F_STRICT_ALIGNMENT;
> + } else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) {
> + spec->prog_flags |= BPF_F_ANY_ALIGNMENT;
> + } else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) {
> + spec->prog_flags |= BPF_F_TEST_RND_HI32;
> + } else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) {
> + spec->prog_flags |= BPF_F_TEST_STATE_FREQ;
> + } else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) {
> + spec->prog_flags |= BPF_F_SLEEPABLE;
> + } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) {
> + spec->prog_flags |= BPF_F_XDP_HAS_FRAGS;
> + } else /* assume numeric value */ {
> + errno = 0;
> + spec->prog_flags |= strtol(val, &e, 0);
> + if (errno || e[0] != '\0') {
> + ASSERT_FAIL("failed to parse test prog flags from
> '%s'", s);
> + return -EINVAL;
> + }
> + }
> }
> }
>
> @@ -101,7 +138,7 @@ static void prepare_case(struct test_loader *tester,
> struct bpf_object *obj,
> struct bpf_program *prog)
> {
> - int min_log_level = 0;
> + int min_log_level = 0, prog_flags;
>
> if (env.verbosity > VERBOSE_NONE)
> min_log_level = 1;
> @@ -119,7 +156,11 @@ static void prepare_case(struct test_loader *tester,
> else
> bpf_program__set_log_level(prog, spec->log_level);
>
> + prog_flags = bpf_program__flags(prog);
> + bpf_program__set_flags(prog, prog_flags | spec->prog_flags);
> +
> tester->log_buf[0] = '\0';
> + tester->next_match_pos = 0;
> }
>
> static void emit_verifier_log(const char *log_buf, bool force)
> @@ -135,17 +176,26 @@ static void validate_case(struct test_loader *tester,
> struct bpf_program *prog,
> int load_err)
> {
> - if (spec->expect_msg) {
> + int i, j;
> +
> + for (i = 0; i < spec->expect_msg_cnt; i++) {
> char *match;
> + const char *expect_msg;
> +
> + expect_msg = spec->expect_msgs[i];
>
> - match = strstr(tester->log_buf, spec->expect_msg);
> + match = strstr(tester->log_buf + tester->next_match_pos, expect_msg);
> if (!ASSERT_OK_PTR(match, "expect_msg")) {
> /* if we are in verbose mode, we've already emitted log */
> if (env.verbosity == VERBOSE_NONE)
> emit_verifier_log(tester->log_buf, true /*force*/);
> - fprintf(stderr, "EXPECTED MSG: '%s'\n", spec->expect_msg);
> + for (j = 0; j < i; j++)
> + fprintf(stderr, "MATCHED MSG: '%s'\n", spec->expect_msgs[j]);
> + fprintf(stderr, "EXPECTED MSG: '%s'\n", expect_msg);
> return;
> }
> +
> + tester->next_match_pos = match - tester->log_buf + strlen(expect_msg);
> }
> }
>
> diff --git a/tools/testing/selftests/bpf/test_progs.h
> b/tools/testing/selftests/bpf/test_progs.h
> index 3f058dfadbaf..9af80704f20a 100644
> --- a/tools/testing/selftests/bpf/test_progs.h
> +++ b/tools/testing/selftests/bpf/test_progs.h
> @@ -410,6 +410,7 @@ int write_sysctl(const char *sysctl, const char *value);
> struct test_loader {
> char *log_buf;
> size_t log_buf_sz;
> + size_t next_match_pos;
>
> struct bpf_object *obj;
> };
>
>
>
>
> > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > ---
> > tools/testing/selftests/bpf/progs/bpf_misc.h | 1 +
> > tools/testing/selftests/bpf/test_loader.c | 10 ++++++++++
> > 2 files changed, 11 insertions(+)
> >
> > diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
> > index 4a01ea9113bf..a42363a3fef1 100644
> > --- a/tools/testing/selftests/bpf/progs/bpf_misc.h
> > +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
> > @@ -6,6 +6,7 @@
> > #define __failure __attribute__((btf_decl_tag("comment:test_expect_failure")))
> > #define __success __attribute__((btf_decl_tag("comment:test_expect_success")))
> > #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl)))
> > +#define __test_state_freq __attribute__((btf_decl_tag("comment:test_state_freq")))
> >
> > #if defined(__TARGET_ARCH_x86)
> > #define SYSCALL_WRAPPER 1
> > diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
> > index 679efb3aa785..ac8517a77161 100644
> > --- a/tools/testing/selftests/bpf/test_loader.c
> > +++ b/tools/testing/selftests/bpf/test_loader.c
> > @@ -11,6 +11,7 @@
> >
> > #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure"
> > #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success"
> > +#define TEST_TAG_TEST_STATE_FREQ "comment:test_state_freq"
> > #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg="
> > #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level="
> >
> > @@ -19,6 +20,7 @@ struct test_spec {
> > bool expect_failure;
> > const char *expect_msg;
> > int log_level;
> > + bool test_state_freq;
> > };
> >
> > static int tester_init(struct test_loader *tester)
> > @@ -81,6 +83,8 @@ static int parse_test_spec(struct test_loader *tester,
> > spec->expect_failure = true;
> > } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) {
> > spec->expect_failure = false;
> > + } else if (strcmp(s, TEST_TAG_TEST_STATE_FREQ) == 0) {
> > + spec->test_state_freq = true;
> > } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
> > spec->expect_msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
> > } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) {
> > @@ -102,6 +106,7 @@ static void prepare_case(struct test_loader *tester,
> > struct bpf_program *prog)
> > {
> > int min_log_level = 0;
> > + __u32 flags = 0;
> >
> > if (env.verbosity > VERBOSE_NONE)
> > min_log_level = 1;
> > @@ -120,6 +125,11 @@ static void prepare_case(struct test_loader *tester,
> > bpf_program__set_log_level(prog, spec->log_level);
> >
> > tester->log_buf[0] = '\0';
> > +
> > + if (spec->test_state_freq)
> > + flags |= BPF_F_TEST_STATE_FREQ;
> > +
> > + bpf_program__set_flags(prog, flags);
>
> see my example above, it's safer to fetch current prog flags to not
> override stuff like BPF_F_SLEEPABLE
>
> > }
> >
> > static void emit_verifier_log(const char *log_buf, bool force)
> > --
> > 2.38.2
> >
next prev parent reply other threads:[~2022-12-22 0:11 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-17 2:17 [PATCH bpf-next 0/4] reduce BPF_ID_MAP_SIZE to fit only valid programs Eduard Zingerman
2022-12-17 2:17 ` [PATCH bpf-next 1/4] selftests/bpf: support for BPF_F_TEST_STATE_FREQ in test_loader Eduard Zingerman
2022-12-17 18:44 ` Yonghong Song
2022-12-20 21:03 ` Andrii Nakryiko
2022-12-22 0:11 ` Eduard Zingerman [this message]
2022-12-22 19:07 ` Andrii Nakryiko
2022-12-17 2:17 ` [PATCH bpf-next 2/4] selftests/bpf: convenience macro for use with 'asm volatile' blocks Eduard Zingerman
2022-12-17 18:58 ` Yonghong Song
2022-12-20 21:05 ` Andrii Nakryiko
2022-12-22 0:12 ` Eduard Zingerman
2022-12-17 2:17 ` [PATCH bpf-next 3/4] bpf: reduce BPF_ID_MAP_SIZE to fit only valid programs Eduard Zingerman
2022-12-17 18:59 ` Yonghong Song
2022-12-20 21:06 ` Andrii Nakryiko
2022-12-17 2:17 ` [PATCH bpf-next 4/4] selftests/bpf: check if verifier.c:check_ids() handles 64+5 ids Eduard Zingerman
2022-12-17 19:17 ` Yonghong Song
2022-12-20 21:18 ` Andrii Nakryiko
2022-12-22 0:33 ` Eduard Zingerman
2022-12-20 21:21 ` [PATCH bpf-next 0/4] reduce BPF_ID_MAP_SIZE to fit only valid programs Andrii Nakryiko
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=8492d922b7b2d1829e286ed48e8b0b44974500e0.camel@gmail.com \
--to=eddyz87@gmail.com \
--cc=andrii.nakryiko@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=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