1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 /* Copyright (C) 2019 Netronome Systems, Inc. */ 3 /* Copyright (C) 2020 Facebook, Inc. */ 4 #include <ctype.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <errno.h> 8 #include <bpf/bpf.h> 9 #include <bpf/libbpf.h> 10 #include "test_progs.h" 11 #include "testing_helpers.h" 12 13 int parse_num_list(const char *s, bool **num_set, int *num_set_len) 14 { 15 int i, set_len = 0, new_len, num, start = 0, end = -1; 16 bool *set = NULL, *tmp, parsing_end = false; 17 char *next; 18 19 while (s[0]) { 20 errno = 0; 21 num = strtol(s, &next, 10); 22 if (errno) 23 return -errno; 24 25 if (parsing_end) 26 end = num; 27 else 28 start = num; 29 30 if (!parsing_end && *next == '-') { 31 s = next + 1; 32 parsing_end = true; 33 continue; 34 } else if (*next == ',') { 35 parsing_end = false; 36 s = next + 1; 37 end = num; 38 } else if (*next == '\0') { 39 parsing_end = false; 40 s = next; 41 end = num; 42 } else { 43 return -EINVAL; 44 } 45 46 if (start > end) 47 return -EINVAL; 48 49 if (end + 1 > set_len) { 50 new_len = end + 1; 51 tmp = realloc(set, new_len); 52 if (!tmp) { 53 free(set); 54 return -ENOMEM; 55 } 56 for (i = set_len; i < start; i++) 57 tmp[i] = false; 58 set = tmp; 59 set_len = new_len; 60 } 61 for (i = start; i <= end; i++) 62 set[i] = true; 63 } 64 65 if (!set || parsing_end) 66 return -EINVAL; 67 68 *num_set = set; 69 *num_set_len = set_len; 70 71 return 0; 72 } 73 74 static int do_insert_test(struct test_filter_set *set, 75 char *test_str, 76 char *subtest_str) 77 { 78 struct test_filter *tmp, *test; 79 char **ctmp; 80 int i; 81 82 for (i = 0; i < set->cnt; i++) { 83 test = &set->tests[i]; 84 85 if (strcmp(test_str, test->name) == 0) { 86 free(test_str); 87 goto subtest; 88 } 89 } 90 91 tmp = realloc(set->tests, sizeof(*test) * (set->cnt + 1)); 92 if (!tmp) 93 return -ENOMEM; 94 95 set->tests = tmp; 96 test = &set->tests[set->cnt]; 97 98 test->name = test_str; 99 test->subtests = NULL; 100 test->subtest_cnt = 0; 101 102 set->cnt++; 103 104 subtest: 105 if (!subtest_str) 106 return 0; 107 108 for (i = 0; i < test->subtest_cnt; i++) { 109 if (strcmp(subtest_str, test->subtests[i]) == 0) { 110 free(subtest_str); 111 return 0; 112 } 113 } 114 115 ctmp = realloc(test->subtests, 116 sizeof(*test->subtests) * (test->subtest_cnt + 1)); 117 if (!ctmp) 118 return -ENOMEM; 119 120 test->subtests = ctmp; 121 test->subtests[test->subtest_cnt] = subtest_str; 122 123 test->subtest_cnt++; 124 125 return 0; 126 } 127 128 static int insert_test(struct test_filter_set *set, 129 char *test_spec, 130 bool is_glob_pattern) 131 { 132 char *pattern, *subtest_str, *ext_test_str, *ext_subtest_str = NULL; 133 int glob_chars = 0; 134 135 if (is_glob_pattern) { 136 pattern = "%s"; 137 } else { 138 pattern = "*%s*"; 139 glob_chars = 2; 140 } 141 142 subtest_str = strchr(test_spec, '/'); 143 if (subtest_str) { 144 *subtest_str = '\0'; 145 subtest_str += 1; 146 } 147 148 ext_test_str = malloc(strlen(test_spec) + glob_chars + 1); 149 if (!ext_test_str) 150 goto err; 151 152 sprintf(ext_test_str, pattern, test_spec); 153 154 if (subtest_str) { 155 ext_subtest_str = malloc(strlen(subtest_str) + glob_chars + 1); 156 if (!ext_subtest_str) 157 goto err; 158 159 sprintf(ext_subtest_str, pattern, subtest_str); 160 } 161 162 return do_insert_test(set, ext_test_str, ext_subtest_str); 163 164 err: 165 free(ext_test_str); 166 free(ext_subtest_str); 167 168 return -ENOMEM; 169 } 170 171 int parse_test_list_file(const char *path, 172 struct test_filter_set *set, 173 bool is_glob_pattern) 174 { 175 char *buf = NULL, *capture_start, *capture_end, *scan_end; 176 size_t buflen = 0; 177 int err = 0; 178 FILE *f; 179 180 f = fopen(path, "r"); 181 if (!f) { 182 err = -errno; 183 fprintf(stderr, "Failed to open '%s': %d\n", path, err); 184 return err; 185 } 186 187 while (getline(&buf, &buflen, f) != -1) { 188 capture_start = buf; 189 190 while (isspace(*capture_start)) 191 ++capture_start; 192 193 capture_end = capture_start; 194 scan_end = capture_start; 195 196 while (*scan_end && *scan_end != '#') { 197 if (!isspace(*scan_end)) 198 capture_end = scan_end; 199 200 ++scan_end; 201 } 202 203 if (capture_end == capture_start) 204 continue; 205 206 *(++capture_end) = '\0'; 207 208 err = insert_test(set, capture_start, is_glob_pattern); 209 if (err) 210 break; 211 } 212 213 fclose(f); 214 return err; 215 } 216 217 int parse_test_list(const char *s, 218 struct test_filter_set *set, 219 bool is_glob_pattern) 220 { 221 char *input, *state = NULL, *test_spec; 222 int err = 0; 223 224 input = strdup(s); 225 if (!input) 226 return -ENOMEM; 227 228 while ((test_spec = strtok_r(state ? NULL : input, ",", &state))) { 229 err = insert_test(set, test_spec, is_glob_pattern); 230 if (err) 231 break; 232 } 233 234 free(input); 235 return err; 236 } 237 238 __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info) 239 { 240 __u32 info_len = sizeof(*info); 241 int err; 242 243 memset(info, 0, sizeof(*info)); 244 err = bpf_link_get_info_by_fd(bpf_link__fd(link), info, &info_len); 245 if (err) { 246 printf("failed to get link info: %d\n", -errno); 247 return 0; 248 } 249 return info->prog_id; 250 } 251 252 int extra_prog_load_log_flags = 0; 253 254 int bpf_prog_test_load(const char *file, enum bpf_prog_type type, 255 struct bpf_object **pobj, int *prog_fd) 256 { 257 LIBBPF_OPTS(bpf_object_open_opts, opts, 258 .kernel_log_level = extra_prog_load_log_flags, 259 ); 260 struct bpf_object *obj; 261 struct bpf_program *prog; 262 __u32 flags; 263 int err; 264 265 obj = bpf_object__open_file(file, &opts); 266 if (!obj) 267 return -errno; 268 269 prog = bpf_object__next_program(obj, NULL); 270 if (!prog) { 271 err = -ENOENT; 272 goto err_out; 273 } 274 275 if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) 276 bpf_program__set_type(prog, type); 277 278 flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32; 279 bpf_program__set_flags(prog, flags); 280 281 err = bpf_object__load(obj); 282 if (err) 283 goto err_out; 284 285 *pobj = obj; 286 *prog_fd = bpf_program__fd(prog); 287 288 return 0; 289 err_out: 290 bpf_object__close(obj); 291 return err; 292 } 293 294 int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 295 size_t insns_cnt, const char *license, 296 __u32 kern_version, char *log_buf, 297 size_t log_buf_sz) 298 { 299 LIBBPF_OPTS(bpf_prog_load_opts, opts, 300 .kern_version = kern_version, 301 .prog_flags = BPF_F_TEST_RND_HI32, 302 .log_level = extra_prog_load_log_flags, 303 .log_buf = log_buf, 304 .log_size = log_buf_sz, 305 ); 306 307 return bpf_prog_load(type, NULL, license, insns, insns_cnt, &opts); 308 } 309 310 __u64 read_perf_max_sample_freq(void) 311 { 312 __u64 sample_freq = 5000; /* fallback to 5000 on error */ 313 FILE *f; 314 315 f = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r"); 316 if (f == NULL) { 317 printf("Failed to open /proc/sys/kernel/perf_event_max_sample_rate: err %d\n" 318 "return default value: 5000\n", -errno); 319 return sample_freq; 320 } 321 if (fscanf(f, "%llu", &sample_freq) != 1) { 322 printf("Failed to parse /proc/sys/kernel/perf_event_max_sample_rate: err %d\n" 323 "return default value: 5000\n", -errno); 324 } 325 326 fclose(f); 327 return sample_freq; 328 } 329