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 17 struct test_spec { 18 const char *name; 19 bool expect_failure; 20 const char *expect_msg; 21 int log_level; 22 }; 23 24 static int tester_init(struct test_loader *tester) 25 { 26 if (!tester->log_buf) { 27 tester->log_buf_sz = TEST_LOADER_LOG_BUF_SZ; 28 tester->log_buf = malloc(tester->log_buf_sz); 29 if (!ASSERT_OK_PTR(tester->log_buf, "tester_log_buf")) 30 return -ENOMEM; 31 } 32 33 return 0; 34 } 35 36 void test_loader_fini(struct test_loader *tester) 37 { 38 if (!tester) 39 return; 40 41 free(tester->log_buf); 42 } 43 44 static int parse_test_spec(struct test_loader *tester, 45 struct bpf_object *obj, 46 struct bpf_program *prog, 47 struct test_spec *spec) 48 { 49 struct btf *btf; 50 int func_id, i; 51 52 memset(spec, 0, sizeof(*spec)); 53 54 spec->name = bpf_program__name(prog); 55 56 btf = bpf_object__btf(obj); 57 if (!btf) { 58 ASSERT_FAIL("BPF object has no BTF"); 59 return -EINVAL; 60 } 61 62 func_id = btf__find_by_name_kind(btf, spec->name, BTF_KIND_FUNC); 63 if (func_id < 0) { 64 ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->name); 65 return -EINVAL; 66 } 67 68 for (i = 1; i < btf__type_cnt(btf); i++) { 69 const struct btf_type *t; 70 const char *s; 71 72 t = btf__type_by_id(btf, i); 73 if (!btf_is_decl_tag(t)) 74 continue; 75 76 if (t->type != func_id || btf_decl_tag(t)->component_idx != -1) 77 continue; 78 79 s = btf__str_by_offset(btf, t->name_off); 80 if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) { 81 spec->expect_failure = true; 82 } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) { 83 spec->expect_failure = false; 84 } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) { 85 spec->expect_msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 86 } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) { 87 errno = 0; 88 spec->log_level = strtol(s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1, NULL, 0); 89 if (errno) { 90 ASSERT_FAIL("failed to parse test log level from '%s'", s); 91 return -EINVAL; 92 } 93 } 94 } 95 96 return 0; 97 } 98 99 static void prepare_case(struct test_loader *tester, 100 struct test_spec *spec, 101 struct bpf_object *obj, 102 struct bpf_program *prog) 103 { 104 int min_log_level = 0; 105 106 if (env.verbosity > VERBOSE_NONE) 107 min_log_level = 1; 108 if (env.verbosity > VERBOSE_VERY) 109 min_log_level = 2; 110 111 bpf_program__set_log_buf(prog, tester->log_buf, tester->log_buf_sz); 112 113 /* Make sure we set at least minimal log level, unless test requirest 114 * even higher level already. Make sure to preserve independent log 115 * level 4 (verifier stats), though. 116 */ 117 if ((spec->log_level & 3) < min_log_level) 118 bpf_program__set_log_level(prog, (spec->log_level & 4) | min_log_level); 119 else 120 bpf_program__set_log_level(prog, spec->log_level); 121 122 tester->log_buf[0] = '\0'; 123 } 124 125 static void emit_verifier_log(const char *log_buf, bool force) 126 { 127 if (!force && env.verbosity == VERBOSE_NONE) 128 return; 129 fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log_buf); 130 } 131 132 static void validate_case(struct test_loader *tester, 133 struct test_spec *spec, 134 struct bpf_object *obj, 135 struct bpf_program *prog, 136 int load_err) 137 { 138 if (spec->expect_msg) { 139 char *match; 140 141 match = strstr(tester->log_buf, spec->expect_msg); 142 if (!ASSERT_OK_PTR(match, "expect_msg")) { 143 /* if we are in verbose mode, we've already emitted log */ 144 if (env.verbosity == VERBOSE_NONE) 145 emit_verifier_log(tester->log_buf, true /*force*/); 146 fprintf(stderr, "EXPECTED MSG: '%s'\n", spec->expect_msg); 147 return; 148 } 149 } 150 } 151 152 /* this function is forced noinline and has short generic name to look better 153 * in test_progs output (in case of a failure) 154 */ 155 static noinline 156 void run_subtest(struct test_loader *tester, 157 const char *skel_name, 158 skel_elf_bytes_fn elf_bytes_factory) 159 { 160 LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name); 161 struct bpf_object *obj = NULL, *tobj; 162 struct bpf_program *prog, *tprog; 163 const void *obj_bytes; 164 size_t obj_byte_cnt; 165 int err; 166 167 if (tester_init(tester) < 0) 168 return; /* failed to initialize tester */ 169 170 obj_bytes = elf_bytes_factory(&obj_byte_cnt); 171 obj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts); 172 if (!ASSERT_OK_PTR(obj, "obj_open_mem")) 173 return; 174 175 bpf_object__for_each_program(prog, obj) { 176 const char *prog_name = bpf_program__name(prog); 177 struct test_spec spec; 178 179 if (!test__start_subtest(prog_name)) 180 continue; 181 182 /* if we can't derive test specification, go to the next test */ 183 err = parse_test_spec(tester, obj, prog, &spec); 184 if (!ASSERT_OK(err, "parse_test_spec")) 185 continue; 186 187 tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts); 188 if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */ 189 continue; 190 191 bpf_object__for_each_program(tprog, tobj) 192 bpf_program__set_autoload(tprog, false); 193 194 bpf_object__for_each_program(tprog, tobj) { 195 /* only load specified program */ 196 if (strcmp(bpf_program__name(tprog), prog_name) == 0) { 197 bpf_program__set_autoload(tprog, true); 198 break; 199 } 200 } 201 202 prepare_case(tester, &spec, tobj, tprog); 203 204 err = bpf_object__load(tobj); 205 if (spec.expect_failure) { 206 if (!ASSERT_ERR(err, "unexpected_load_success")) { 207 emit_verifier_log(tester->log_buf, false /*force*/); 208 goto tobj_cleanup; 209 } 210 } else { 211 if (!ASSERT_OK(err, "unexpected_load_failure")) { 212 emit_verifier_log(tester->log_buf, true /*force*/); 213 goto tobj_cleanup; 214 } 215 } 216 217 emit_verifier_log(tester->log_buf, false /*force*/); 218 validate_case(tester, &spec, tobj, tprog, err); 219 220 tobj_cleanup: 221 bpf_object__close(tobj); 222 } 223 224 bpf_object__close(obj); 225 } 226 227 void test_loader__run_subtests(struct test_loader *tester, 228 const char *skel_name, 229 skel_elf_bytes_fn elf_bytes_factory) 230 { 231 /* see comment in run_subtest() for why we do this function nesting */ 232 run_subtest(tester, skel_name, elf_bytes_factory); 233 } 234