Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftests/bpf: support custom per-test flags and multiple expected messages'

Eduard Zingerman says:

====================

This patch allows to specify program flags and multiple verifier log
messages for the test_loader kind of tests. For example:

tools/testing/selftets/bpf/progs/foobar.c:

SEC("tc")
__success __log_level(7)
__msg("first message")
__msg("next message")
__flag(BPF_F_ANY_ALIGNMENT)
int buz(struct __sk_buff *skb)
{ ... }

It was developed by Andrii Nakryiko ([1]), I reused it in a
"test_verifier tests migration to inline assembly" patch series ([2]),
but the series is currently stuck on my side.
Andrii asked to spin this particular patch separately ([3]).

[1] https://lore.kernel.org/bpf/CAEf4BzZH0ZxorCi7nPDbRqSK9f+410RooNwNJGwfw8=0a5i1nw@mail.gmail.com/
[2] https://lore.kernel.org/bpf/20230123145148.2791939-1-eddyz87@gmail.com/
[3] https://lore.kernel.org/bpf/20230123145148.2791939-1-eddyz87@gmail.com/T/#m52e806c5a679a2aa8f484d011be7ec105939127a
====================

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

+85 -10
+23
tools/testing/selftests/bpf/progs/bpf_misc.h
··· 2 2 #ifndef __BPF_MISC_H__ 3 3 #define __BPF_MISC_H__ 4 4 5 + /* This set of attributes controls behavior of the 6 + * test_loader.c:test_loader__run_subtests(). 7 + * 8 + * __msg Message expected to be found in the verifier log. 9 + * Multiple __msg attributes could be specified. 10 + * 11 + * __success Expect program load success in privileged mode. 12 + * 13 + * __failure Expect program load failure in privileged mode. 14 + * 15 + * __log_level Log level to use for the program, numeric value expected. 16 + * 17 + * __flag Adds one flag use for the program, the following values are valid: 18 + * - BPF_F_STRICT_ALIGNMENT; 19 + * - BPF_F_TEST_RND_HI32; 20 + * - BPF_F_TEST_STATE_FREQ; 21 + * - BPF_F_SLEEPABLE; 22 + * - BPF_F_XDP_HAS_FRAGS; 23 + * - A numeric value. 24 + * Multiple __flag attributes could be specified, the final flags 25 + * value is derived by applying binary "or" to all specified values. 26 + */ 5 27 #define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" msg))) 6 28 #define __failure __attribute__((btf_decl_tag("comment:test_expect_failure"))) 7 29 #define __success __attribute__((btf_decl_tag("comment:test_expect_success"))) 8 30 #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl))) 31 + #define __flag(flag) __attribute__((btf_decl_tag("comment:test_prog_flags="#flag))) 9 32 10 33 /* Convenience macro for use with 'asm volatile' blocks */ 11 34 #define __naked __attribute__((naked))
+61 -10
tools/testing/selftests/bpf/test_loader.c
··· 13 13 #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success" 14 14 #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg=" 15 15 #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level=" 16 + #define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags=" 16 17 17 18 struct test_spec { 18 19 const char *name; 19 20 bool expect_failure; 20 - const char *expect_msg; 21 + const char **expect_msgs; 22 + size_t expect_msg_cnt; 21 23 int log_level; 24 + int prog_flags; 22 25 }; 23 26 24 27 static int tester_init(struct test_loader *tester) ··· 70 67 71 68 for (i = 1; i < btf__type_cnt(btf); i++) { 72 69 const struct btf_type *t; 73 - const char *s; 70 + const char *s, *val; 71 + char *e; 74 72 75 73 t = btf__type_by_id(btf, i); 76 74 if (!btf_is_decl_tag(t)) ··· 86 82 } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) { 87 83 spec->expect_failure = false; 88 84 } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) { 89 - spec->expect_msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 85 + void *tmp; 86 + const char **msg; 87 + 88 + tmp = realloc(spec->expect_msgs, 89 + (1 + spec->expect_msg_cnt) * sizeof(void *)); 90 + if (!tmp) { 91 + ASSERT_FAIL("failed to realloc memory for messages\n"); 92 + return -ENOMEM; 93 + } 94 + spec->expect_msgs = tmp; 95 + msg = &spec->expect_msgs[spec->expect_msg_cnt++]; 96 + *msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 90 97 } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) { 98 + val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1; 91 99 errno = 0; 92 - spec->log_level = strtol(s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1, NULL, 0); 93 - if (errno) { 100 + spec->log_level = strtol(val, &e, 0); 101 + if (errno || e[0] != '\0') { 94 102 ASSERT_FAIL("failed to parse test log level from '%s'", s); 95 103 return -EINVAL; 104 + } 105 + } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) { 106 + val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1; 107 + if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) { 108 + spec->prog_flags |= BPF_F_STRICT_ALIGNMENT; 109 + } else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) { 110 + spec->prog_flags |= BPF_F_ANY_ALIGNMENT; 111 + } else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) { 112 + spec->prog_flags |= BPF_F_TEST_RND_HI32; 113 + } else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) { 114 + spec->prog_flags |= BPF_F_TEST_STATE_FREQ; 115 + } else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) { 116 + spec->prog_flags |= BPF_F_SLEEPABLE; 117 + } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) { 118 + spec->prog_flags |= BPF_F_XDP_HAS_FRAGS; 119 + } else /* assume numeric value */ { 120 + errno = 0; 121 + spec->prog_flags |= strtol(val, &e, 0); 122 + if (errno || e[0] != '\0') { 123 + ASSERT_FAIL("failed to parse test prog flags from '%s'", s); 124 + return -EINVAL; 125 + } 96 126 } 97 127 } 98 128 } ··· 139 101 struct bpf_object *obj, 140 102 struct bpf_program *prog) 141 103 { 142 - int min_log_level = 0; 104 + int min_log_level = 0, prog_flags; 143 105 144 106 if (env.verbosity > VERBOSE_NONE) 145 107 min_log_level = 1; ··· 157 119 else 158 120 bpf_program__set_log_level(prog, spec->log_level); 159 121 122 + prog_flags = bpf_program__flags(prog); 123 + bpf_program__set_flags(prog, prog_flags | spec->prog_flags); 124 + 160 125 tester->log_buf[0] = '\0'; 126 + tester->next_match_pos = 0; 161 127 } 162 128 163 129 static void emit_verifier_log(const char *log_buf, bool force) ··· 177 135 struct bpf_program *prog, 178 136 int load_err) 179 137 { 180 - if (spec->expect_msg) { 181 - char *match; 138 + int i, j; 182 139 183 - match = strstr(tester->log_buf, spec->expect_msg); 140 + for (i = 0; i < spec->expect_msg_cnt; i++) { 141 + char *match; 142 + const char *expect_msg; 143 + 144 + expect_msg = spec->expect_msgs[i]; 145 + 146 + match = strstr(tester->log_buf + tester->next_match_pos, expect_msg); 184 147 if (!ASSERT_OK_PTR(match, "expect_msg")) { 185 148 /* if we are in verbose mode, we've already emitted log */ 186 149 if (env.verbosity == VERBOSE_NONE) 187 150 emit_verifier_log(tester->log_buf, true /*force*/); 188 - fprintf(stderr, "EXPECTED MSG: '%s'\n", spec->expect_msg); 151 + for (j = 0; j < i; j++) 152 + fprintf(stderr, "MATCHED MSG: '%s'\n", spec->expect_msgs[j]); 153 + fprintf(stderr, "EXPECTED MSG: '%s'\n", expect_msg); 189 154 return; 190 155 } 156 + 157 + tester->next_match_pos = match - tester->log_buf + strlen(expect_msg); 191 158 } 192 159 } 193 160
+1
tools/testing/selftests/bpf/test_progs.h
··· 427 427 struct test_loader { 428 428 char *log_buf; 429 429 size_t log_buf_sz; 430 + size_t next_match_pos; 430 431 431 432 struct bpf_object *obj; 432 433 };