diff mbox series

[bpf-next,1/4] selftests/bpf: support for BPF_F_TEST_STATE_FREQ in test_loader

Message ID 20221217021711.172247-2-eddyz87@gmail.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series reduce BPF_ID_MAP_SIZE to fit only valid programs | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 12 maintainers not CCed: linux-kselftest@vger.kernel.org naveen.n.rao@linux.vnet.ibm.com kpsingh@kernel.org Kenta.Tada@sony.com haoluo@google.com song@kernel.org martin.lau@linux.dev sdf@google.com john.fastabend@gmail.com shuah@kernel.org jolsa@kernel.org mykolal@fb.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning WARNING: line length of 88 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for llvm-toolchain
bpf/vmtest-bpf-next-VM_Test-8 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-34 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for test_verifier on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-37 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-38 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32 on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-32 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_no_alu32_parallel on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-31 success Logs for test_progs_parallel on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-36 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_maps on s390x with gcc

Commit Message

Eduard Zingerman Dec. 17, 2022, 2:17 a.m. UTC
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.

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(+)

Comments

Yonghong Song Dec. 17, 2022, 6:44 p.m. UTC | #1
On 12/16/22 6:17 PM, Eduard Zingerman 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.
> 
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>

Acked-by: Yonghong Song <yhs@fb.com>
Andrii Nakryiko Dec. 20, 2022, 9:03 p.m. UTC | #2
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?


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
>
Eduard Zingerman Dec. 22, 2022, 12:11 a.m. UTC | #3
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
> >
Andrii Nakryiko Dec. 22, 2022, 7:07 p.m. UTC | #4
On Wed, Dec 21, 2022 at 4:11 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> 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.

Mine will take a bit more time and will be stuck in discussions
anyways, so the more prerequisites land before it the better. Please
go ahead and add it to your patch set.

>
> >
> >
diff mbox series

Patch

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);
 }
 
 static void emit_verifier_log(const char *log_buf, bool force)