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 #include <linux/membarrier.h> 13 14 int parse_num_list(const char *s, bool **num_set, int *num_set_len) 15 { 16 int i, set_len = 0, new_len, num, start = 0, end = -1; 17 bool *set = NULL, *tmp, parsing_end = false; 18 char *next; 19 20 while (s[0]) { 21 errno = 0; 22 num = strtol(s, &next, 10); 23 if (errno) 24 return -errno; 25 26 if (parsing_end) 27 end = num; 28 else 29 start = num; 30 31 if (!parsing_end && *next == '-') { 32 s = next + 1; 33 parsing_end = true; 34 continue; 35 } else if (*next == ',') { 36 parsing_end = false; 37 s = next + 1; 38 end = num; 39 } else if (*next == '\0') { 40 parsing_end = false; 41 s = next; 42 end = num; 43 } else { 44 return -EINVAL; 45 } 46 47 if (start > end) 48 return -EINVAL; 49 50 if (end + 1 > set_len) { 51 new_len = end + 1; 52 tmp = realloc(set, new_len); 53 if (!tmp) { 54 free(set); 55 return -ENOMEM; 56 } 57 for (i = set_len; i < start; i++) 58 tmp[i] = false; 59 set = tmp; 60 set_len = new_len; 61 } 62 for (i = start; i <= end; i++) 63 set[i] = true; 64 } 65 66 if (!set || parsing_end) 67 return -EINVAL; 68 69 *num_set = set; 70 *num_set_len = set_len; 71 72 return 0; 73 } 74 75 static int do_insert_test(struct test_filter_set *set, 76 char *test_str, 77 char *subtest_str) 78 { 79 struct test_filter *tmp, *test; 80 char **ctmp; 81 int i; 82 83 for (i = 0; i < set->cnt; i++) { 84 test = &set->tests[i]; 85 86 if (strcmp(test_str, test->name) == 0) { 87 free(test_str); 88 goto subtest; 89 } 90 } 91 92 tmp = realloc(set->tests, sizeof(*test) * (set->cnt + 1)); 93 if (!tmp) 94 return -ENOMEM; 95 96 set->tests = tmp; 97 test = &set->tests[set->cnt]; 98 99 test->name = test_str; 100 test->subtests = NULL; 101 test->subtest_cnt = 0; 102 103 set->cnt++; 104 105 subtest: 106 if (!subtest_str) 107 return 0; 108 109 for (i = 0; i < test->subtest_cnt; i++) { 110 if (strcmp(subtest_str, test->subtests[i]) == 0) { 111 free(subtest_str); 112 return 0; 113 } 114 } 115 116 ctmp = realloc(test->subtests, 117 sizeof(*test->subtests) * (test->subtest_cnt + 1)); 118 if (!ctmp) 119 return -ENOMEM; 120 121 test->subtests = ctmp; 122 test->subtests[test->subtest_cnt] = subtest_str; 123 124 test->subtest_cnt++; 125 126 return 0; 127 } 128 129 static int insert_test(struct test_filter_set *set, 130 char *test_spec, 131 bool is_glob_pattern) 132 { 133 char *pattern, *subtest_str, *ext_test_str, *ext_subtest_str = NULL; 134 int glob_chars = 0; 135 136 if (is_glob_pattern) { 137 pattern = "%s"; 138 } else { 139 pattern = "*%s*"; 140 glob_chars = 2; 141 } 142 143 subtest_str = strchr(test_spec, '/'); 144 if (subtest_str) { 145 *subtest_str = '\0'; 146 subtest_str += 1; 147 } 148 149 ext_test_str = malloc(strlen(test_spec) + glob_chars + 1); 150 if (!ext_test_str) 151 goto err; 152 153 sprintf(ext_test_str, pattern, test_spec); 154 155 if (subtest_str) { 156 ext_subtest_str = malloc(strlen(subtest_str) + glob_chars + 1); 157 if (!ext_subtest_str) 158 goto err; 159 160 sprintf(ext_subtest_str, pattern, subtest_str); 161 } 162 163 return do_insert_test(set, ext_test_str, ext_subtest_str); 164 165 err: 166 free(ext_test_str); 167 free(ext_subtest_str); 168 169 return -ENOMEM; 170 } 171 172 int parse_test_list_file(const char *path, 173 struct test_filter_set *set, 174 bool is_glob_pattern) 175 { 176 char *buf = NULL, *capture_start, *capture_end, *scan_end; 177 size_t buflen = 0; 178 int err = 0; 179 FILE *f; 180 181 f = fopen(path, "r"); 182 if (!f) { 183 err = -errno; 184 fprintf(stderr, "Failed to open '%s': %d\n", path, err); 185 return err; 186 } 187 188 while (getline(&buf, &buflen, f) != -1) { 189 capture_start = buf; 190 191 while (isspace(*capture_start)) 192 ++capture_start; 193 194 capture_end = capture_start; 195 scan_end = capture_start; 196 197 while (*scan_end && *scan_end != '#') { 198 if (!isspace(*scan_end)) 199 capture_end = scan_end; 200 201 ++scan_end; 202 } 203 204 if (capture_end == capture_start) 205 continue; 206 207 *(++capture_end) = '\0'; 208 209 err = insert_test(set, capture_start, is_glob_pattern); 210 if (err) 211 break; 212 } 213 214 fclose(f); 215 return err; 216 } 217 218 int parse_test_list(const char *s, 219 struct test_filter_set *set, 220 bool is_glob_pattern) 221 { 222 char *input, *state = NULL, *test_spec; 223 int err = 0; 224 225 input = strdup(s); 226 if (!input) 227 return -ENOMEM; 228 229 while ((test_spec = strtok_r(state ? NULL : input, ",", &state))) { 230 err = insert_test(set, test_spec, is_glob_pattern); 231 if (err) 232 break; 233 } 234 235 free(input); 236 return err; 237 } 238 239 __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info) 240 { 241 __u32 info_len = sizeof(*info); 242 int err; 243 244 memset(info, 0, sizeof(*info)); 245 err = bpf_link_get_info_by_fd(bpf_link__fd(link), info, &info_len); 246 if (err) { 247 printf("failed to get link info: %d\n", -errno); 248 return 0; 249 } 250 return info->prog_id; 251 } 252 253 int extra_prog_load_log_flags = 0; 254 255 int testing_prog_flags(void) 256 { 257 static int cached_flags = -1; 258 static int prog_flags[] = { BPF_F_TEST_RND_HI32, BPF_F_TEST_REG_INVARIANTS }; 259 static struct bpf_insn insns[] = { 260 BPF_MOV64_IMM(BPF_REG_0, 0), 261 BPF_EXIT_INSN(), 262 }; 263 int insn_cnt = ARRAY_SIZE(insns), i, fd, flags = 0; 264 LIBBPF_OPTS(bpf_prog_load_opts, opts); 265 266 if (cached_flags >= 0) 267 return cached_flags; 268 269 for (i = 0; i < ARRAY_SIZE(prog_flags); i++) { 270 opts.prog_flags = prog_flags[i]; 271 fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "flag-test", "GPL", 272 insns, insn_cnt, &opts); 273 if (fd >= 0) { 274 flags |= prog_flags[i]; 275 close(fd); 276 } 277 } 278 279 cached_flags = flags; 280 return cached_flags; 281 } 282 283 int bpf_prog_test_load(const char *file, enum bpf_prog_type type, 284 struct bpf_object **pobj, int *prog_fd) 285 { 286 LIBBPF_OPTS(bpf_object_open_opts, opts, 287 .kernel_log_level = extra_prog_load_log_flags, 288 ); 289 struct bpf_object *obj; 290 struct bpf_program *prog; 291 __u32 flags; 292 int err; 293 294 obj = bpf_object__open_file(file, &opts); 295 if (!obj) 296 return -errno; 297 298 prog = bpf_object__next_program(obj, NULL); 299 if (!prog) { 300 err = -ENOENT; 301 goto err_out; 302 } 303 304 if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) 305 bpf_program__set_type(prog, type); 306 307 flags = bpf_program__flags(prog) | testing_prog_flags(); 308 bpf_program__set_flags(prog, flags); 309 310 err = bpf_object__load(obj); 311 if (err) 312 goto err_out; 313 314 *pobj = obj; 315 *prog_fd = bpf_program__fd(prog); 316 317 return 0; 318 err_out: 319 bpf_object__close(obj); 320 return err; 321 } 322 323 int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 324 size_t insns_cnt, const char *license, 325 __u32 kern_version, char *log_buf, 326 size_t log_buf_sz) 327 { 328 LIBBPF_OPTS(bpf_prog_load_opts, opts, 329 .kern_version = kern_version, 330 .prog_flags = testing_prog_flags(), 331 .log_level = extra_prog_load_log_flags, 332 .log_buf = log_buf, 333 .log_size = log_buf_sz, 334 ); 335 336 return bpf_prog_load(type, NULL, license, insns, insns_cnt, &opts); 337 } 338 339 __u64 read_perf_max_sample_freq(void) 340 { 341 __u64 sample_freq = 5000; /* fallback to 5000 on error */ 342 FILE *f; 343 344 f = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r"); 345 if (f == NULL) { 346 printf("Failed to open /proc/sys/kernel/perf_event_max_sample_rate: err %d\n" 347 "return default value: 5000\n", -errno); 348 return sample_freq; 349 } 350 if (fscanf(f, "%llu", &sample_freq) != 1) { 351 printf("Failed to parse /proc/sys/kernel/perf_event_max_sample_rate: err %d\n" 352 "return default value: 5000\n", -errno); 353 } 354 355 fclose(f); 356 return sample_freq; 357 } 358 359 int finit_module(int fd, const char *param_values, int flags) 360 { 361 return syscall(__NR_finit_module, fd, param_values, flags); 362 } 363 364 int delete_module(const char *name, int flags) 365 { 366 return syscall(__NR_delete_module, name, flags); 367 } 368 369 int unload_bpf_testmod(bool verbose) 370 { 371 int ret, cnt = 0; 372 373 if (kern_sync_rcu()) 374 fprintf(stdout, "Failed to trigger kernel-side RCU sync!\n"); 375 376 for (;;) { 377 ret = delete_module("bpf_testmod", 0); 378 if (!ret || errno != EAGAIN) 379 break; 380 if (++cnt > 10000) { 381 fprintf(stdout, "Unload of bpf_testmod timed out\n"); 382 break; 383 } 384 usleep(100); 385 } 386 387 if (ret) { 388 if (errno == ENOENT) { 389 if (verbose) 390 fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); 391 return -1; 392 } 393 fprintf(stdout, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); 394 return -1; 395 } 396 if (verbose) 397 fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); 398 return 0; 399 } 400 401 int load_bpf_testmod(bool verbose) 402 { 403 int fd; 404 405 if (verbose) 406 fprintf(stdout, "Loading bpf_testmod.ko...\n"); 407 408 fd = open("bpf_testmod.ko", O_RDONLY); 409 if (fd < 0) { 410 fprintf(stdout, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); 411 return -ENOENT; 412 } 413 if (finit_module(fd, "", 0)) { 414 fprintf(stdout, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); 415 close(fd); 416 return -EINVAL; 417 } 418 close(fd); 419 420 if (verbose) 421 fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n"); 422 return 0; 423 } 424 425 /* 426 * Trigger synchronize_rcu() in kernel. 427 */ 428 int kern_sync_rcu(void) 429 { 430 return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0); 431 } 432 433 int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt) 434 { 435 __u32 buf_element_size = sizeof(struct bpf_insn); 436 struct bpf_prog_info info = {}; 437 __u32 info_len = sizeof(info); 438 __u32 xlated_prog_len; 439 440 if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { 441 perror("bpf_prog_get_info_by_fd failed"); 442 return -1; 443 } 444 445 xlated_prog_len = info.xlated_prog_len; 446 if (xlated_prog_len % buf_element_size) { 447 printf("Program length %u is not multiple of %u\n", 448 xlated_prog_len, buf_element_size); 449 return -1; 450 } 451 452 *cnt = xlated_prog_len / buf_element_size; 453 *buf = calloc(*cnt, buf_element_size); 454 if (!buf) { 455 perror("can't allocate xlated program buffer"); 456 return -ENOMEM; 457 } 458 459 bzero(&info, sizeof(info)); 460 info.xlated_prog_len = xlated_prog_len; 461 info.xlated_prog_insns = (__u64)(unsigned long)*buf; 462 if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { 463 perror("second bpf_prog_get_info_by_fd failed"); 464 goto out_free_buf; 465 } 466 467 return 0; 468 469 out_free_buf: 470 free(*buf); 471 *buf = NULL; 472 return -1; 473 } 474 475 bool is_jit_enabled(void) 476 { 477 const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; 478 bool enabled = false; 479 int sysctl_fd; 480 481 sysctl_fd = open(jit_sysctl, O_RDONLY); 482 if (sysctl_fd != -1) { 483 char tmpc; 484 485 if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) 486 enabled = (tmpc != '0'); 487 close(sysctl_fd); 488 } 489 490 return enabled; 491 } 492