1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 #include <stdlib.h> 4 #include <test_progs.h> 5 #include <bpf/btf.h> 6 7 #define str_has_pfx(str, pfx) \ 8 (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0) 9 10 #define TEST_LOADER_LOG_BUF_SZ 1048576 11 12 #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure" 13 #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success" 14 #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg=" 15 #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level=" 16 #define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags=" 17 18 struct test_spec { 19 const char *name; 20 bool expect_failure; 21 const char **expect_msgs; 22 size_t expect_msg_cnt; 23 int log_level; 24 int prog_flags; 25 }; 26 27 static int tester_init(struct test_loader *tester) 28 { 29 if (!tester->log_buf) { 30 tester->log_buf_sz = TEST_LOADER_LOG_BUF_SZ; 31 tester->log_buf = malloc(tester->log_buf_sz); 32 if (!ASSERT_OK_PTR(tester->log_buf, "tester_log_buf")) 33 return -ENOMEM; 34 } 35 36 return 0; 37 } 38 39 void test_loader_fini(struct test_loader *tester) 40 { 41 if (!tester) 42 return; 43 44 free(tester->log_buf); 45 } 46 47 static int parse_test_spec(struct test_loader *tester, 48 struct bpf_object *obj, 49 struct bpf_program *prog, 50 struct test_spec *spec) 51 { 52 struct btf *btf; 53 int func_id, i; 54 55 memset(spec, 0, sizeof(*spec)); 56 57 spec->name = bpf_program__name(prog); 58 59 btf = bpf_object__btf(obj); 60 if (!btf) { 61 ASSERT_FAIL("BPF object has no BTF"); 62 return -EINVAL; 63 } 64 65 func_id = btf__find_by_name_kind(btf, spec->name, BTF_KIND_FUNC); 66 if (func_id < 0) { 67 ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->name); 68 return -EINVAL; 69 } 70 71 for (i = 1; i < btf__type_cnt(btf); i++) { 72 const struct btf_type *t; 73 const char *s, *val; 74 char *e; 75 76 t = btf__type_by_id(btf, i); 77 if (!btf_is_decl_tag(t)) 78 continue; 79 80 if (t->type != func_id || btf_decl_tag(t)->component_idx != -1) 81 continue; 82 83 s = btf__str_by_offset(btf, t->name_off); 84 if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) { 85 spec->expect_failure = true; 86 } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) { 87 spec->expect_failure = false; 88 } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) { 89 void *tmp; 90 const char **msg; 91 92 tmp = realloc(spec->expect_msgs, 93 (1 + spec->expect_msg_cnt) * sizeof(void *)); 94 if (!tmp) { 95 ASSERT_FAIL("failed to realloc memory for messages\n"); 96 return -ENOMEM; 97 } 98 spec->expect_msgs = tmp; 99 msg = &spec->expect_msgs[spec->expect_msg_cnt++]; 100 *msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 101 } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) { 102 val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1; 103 errno = 0; 104 spec->log_level = strtol(val, &e, 0); 105 if (errno || e[0] != '\0') { 106 ASSERT_FAIL("failed to parse test log level from '%s'", s); 107 return -EINVAL; 108 } 109 } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) { 110 val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1; 111 if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) { 112 spec->prog_flags |= BPF_F_STRICT_ALIGNMENT; 113 } else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) { 114 spec->prog_flags |= BPF_F_ANY_ALIGNMENT; 115 } else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) { 116 spec->prog_flags |= BPF_F_TEST_RND_HI32; 117 } else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) { 118 spec->prog_flags |= BPF_F_TEST_STATE_FREQ; 119 } else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) { 120 spec->prog_flags |= BPF_F_SLEEPABLE; 121 } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) { 122 spec->prog_flags |= BPF_F_XDP_HAS_FRAGS; 123 } else /* assume numeric value */ { 124 errno = 0; 125 spec->prog_flags |= strtol(val, &e, 0); 126 if (errno || e[0] != '\0') { 127 ASSERT_FAIL("failed to parse test prog flags from '%s'", s); 128 return -EINVAL; 129 } 130 } 131 } 132 } 133 134 return 0; 135 } 136 137 static void prepare_case(struct test_loader *tester, 138 struct test_spec *spec, 139 struct bpf_object *obj, 140 struct bpf_program *prog) 141 { 142 int min_log_level = 0, prog_flags; 143 144 if (env.verbosity > VERBOSE_NONE) 145 min_log_level = 1; 146 if (env.verbosity > VERBOSE_VERY) 147 min_log_level = 2; 148 149 bpf_program__set_log_buf(prog, tester->log_buf, tester->log_buf_sz); 150 151 /* Make sure we set at least minimal log level, unless test requirest 152 * even higher level already. Make sure to preserve independent log 153 * level 4 (verifier stats), though. 154 */ 155 if ((spec->log_level & 3) < min_log_level) 156 bpf_program__set_log_level(prog, (spec->log_level & 4) | min_log_level); 157 else 158 bpf_program__set_log_level(prog, spec->log_level); 159 160 prog_flags = bpf_program__flags(prog); 161 bpf_program__set_flags(prog, prog_flags | spec->prog_flags); 162 163 tester->log_buf[0] = '\0'; 164 tester->next_match_pos = 0; 165 } 166 167 static void emit_verifier_log(const char *log_buf, bool force) 168 { 169 if (!force && env.verbosity == VERBOSE_NONE) 170 return; 171 fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log_buf); 172 } 173 174 static void validate_case(struct test_loader *tester, 175 struct test_spec *spec, 176 struct bpf_object *obj, 177 struct bpf_program *prog, 178 int load_err) 179 { 180 int i, j; 181 182 for (i = 0; i < spec->expect_msg_cnt; i++) { 183 char *match; 184 const char *expect_msg; 185 186 expect_msg = spec->expect_msgs[i]; 187 188 match = strstr(tester->log_buf + tester->next_match_pos, expect_msg); 189 if (!ASSERT_OK_PTR(match, "expect_msg")) { 190 /* if we are in verbose mode, we've already emitted log */ 191 if (env.verbosity == VERBOSE_NONE) 192 emit_verifier_log(tester->log_buf, true /*force*/); 193 for (j = 0; j < i; j++) 194 fprintf(stderr, "MATCHED MSG: '%s'\n", spec->expect_msgs[j]); 195 fprintf(stderr, "EXPECTED MSG: '%s'\n", expect_msg); 196 return; 197 } 198 199 tester->next_match_pos = match - tester->log_buf + strlen(expect_msg); 200 } 201 } 202 203 /* this function is forced noinline and has short generic name to look better 204 * in test_progs output (in case of a failure) 205 */ 206 static noinline 207 void run_subtest(struct test_loader *tester, 208 const char *skel_name, 209 skel_elf_bytes_fn elf_bytes_factory) 210 { 211 LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name); 212 struct bpf_object *obj = NULL, *tobj; 213 struct bpf_program *prog, *tprog; 214 const void *obj_bytes; 215 size_t obj_byte_cnt; 216 int err; 217 218 if (tester_init(tester) < 0) 219 return; /* failed to initialize tester */ 220 221 obj_bytes = elf_bytes_factory(&obj_byte_cnt); 222 obj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts); 223 if (!ASSERT_OK_PTR(obj, "obj_open_mem")) 224 return; 225 226 bpf_object__for_each_program(prog, obj) { 227 const char *prog_name = bpf_program__name(prog); 228 struct test_spec spec; 229 230 if (!test__start_subtest(prog_name)) 231 continue; 232 233 /* if we can't derive test specification, go to the next test */ 234 err = parse_test_spec(tester, obj, prog, &spec); 235 if (!ASSERT_OK(err, "parse_test_spec")) 236 continue; 237 238 tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts); 239 if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */ 240 continue; 241 242 bpf_object__for_each_program(tprog, tobj) 243 bpf_program__set_autoload(tprog, false); 244 245 bpf_object__for_each_program(tprog, tobj) { 246 /* only load specified program */ 247 if (strcmp(bpf_program__name(tprog), prog_name) == 0) { 248 bpf_program__set_autoload(tprog, true); 249 break; 250 } 251 } 252 253 prepare_case(tester, &spec, tobj, tprog); 254 255 err = bpf_object__load(tobj); 256 if (spec.expect_failure) { 257 if (!ASSERT_ERR(err, "unexpected_load_success")) { 258 emit_verifier_log(tester->log_buf, false /*force*/); 259 goto tobj_cleanup; 260 } 261 } else { 262 if (!ASSERT_OK(err, "unexpected_load_failure")) { 263 emit_verifier_log(tester->log_buf, true /*force*/); 264 goto tobj_cleanup; 265 } 266 } 267 268 emit_verifier_log(tester->log_buf, false /*force*/); 269 validate_case(tester, &spec, tobj, tprog, err); 270 271 tobj_cleanup: 272 bpf_object__close(tobj); 273 } 274 275 bpf_object__close(obj); 276 } 277 278 void test_loader__run_subtests(struct test_loader *tester, 279 const char *skel_name, 280 skel_elf_bytes_fn elf_bytes_factory) 281 { 282 /* see comment in run_subtest() for why we do this function nesting */ 283 run_subtest(tester, skel_name, elf_bytes_factory); 284 } 285