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 <stdlib.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <bpf/bpf.h> 8 #include <bpf/libbpf.h> 9 #include "test_progs.h" 10 #include "testing_helpers.h" 11 12 int parse_num_list(const char *s, bool **num_set, int *num_set_len) 13 { 14 int i, set_len = 0, new_len, num, start = 0, end = -1; 15 bool *set = NULL, *tmp, parsing_end = false; 16 char *next; 17 18 while (s[0]) { 19 errno = 0; 20 num = strtol(s, &next, 10); 21 if (errno) 22 return -errno; 23 24 if (parsing_end) 25 end = num; 26 else 27 start = num; 28 29 if (!parsing_end && *next == '-') { 30 s = next + 1; 31 parsing_end = true; 32 continue; 33 } else if (*next == ',') { 34 parsing_end = false; 35 s = next + 1; 36 end = num; 37 } else if (*next == '\0') { 38 parsing_end = false; 39 s = next; 40 end = num; 41 } else { 42 return -EINVAL; 43 } 44 45 if (start > end) 46 return -EINVAL; 47 48 if (end + 1 > set_len) { 49 new_len = end + 1; 50 tmp = realloc(set, new_len); 51 if (!tmp) { 52 free(set); 53 return -ENOMEM; 54 } 55 for (i = set_len; i < start; i++) 56 tmp[i] = false; 57 set = tmp; 58 set_len = new_len; 59 } 60 for (i = start; i <= end; i++) 61 set[i] = true; 62 } 63 64 if (!set || parsing_end) 65 return -EINVAL; 66 67 *num_set = set; 68 *num_set_len = set_len; 69 70 return 0; 71 } 72 73 int parse_test_list(const char *s, 74 struct test_filter_set *set, 75 bool is_glob_pattern) 76 { 77 char *input, *state = NULL, *next; 78 struct test_filter *tmp, *tests = NULL; 79 int i, j, cnt = 0; 80 81 input = strdup(s); 82 if (!input) 83 return -ENOMEM; 84 85 while ((next = strtok_r(state ? NULL : input, ",", &state))) { 86 char *subtest_str = strchr(next, '/'); 87 char *pattern = NULL; 88 int glob_chars = 0; 89 90 tmp = realloc(tests, sizeof(*tests) * (cnt + 1)); 91 if (!tmp) 92 goto err; 93 tests = tmp; 94 95 tests[cnt].subtest_cnt = 0; 96 tests[cnt].subtests = NULL; 97 98 if (is_glob_pattern) { 99 pattern = "%s"; 100 } else { 101 pattern = "*%s*"; 102 glob_chars = 2; 103 } 104 105 if (subtest_str) { 106 char **tmp_subtests = NULL; 107 int subtest_cnt = tests[cnt].subtest_cnt; 108 109 *subtest_str = '\0'; 110 subtest_str += 1; 111 tmp_subtests = realloc(tests[cnt].subtests, 112 sizeof(*tmp_subtests) * 113 (subtest_cnt + 1)); 114 if (!tmp_subtests) 115 goto err; 116 tests[cnt].subtests = tmp_subtests; 117 118 tests[cnt].subtests[subtest_cnt] = 119 malloc(strlen(subtest_str) + glob_chars + 1); 120 if (!tests[cnt].subtests[subtest_cnt]) 121 goto err; 122 sprintf(tests[cnt].subtests[subtest_cnt], 123 pattern, 124 subtest_str); 125 126 tests[cnt].subtest_cnt++; 127 } 128 129 tests[cnt].name = malloc(strlen(next) + glob_chars + 1); 130 if (!tests[cnt].name) 131 goto err; 132 sprintf(tests[cnt].name, pattern, next); 133 134 cnt++; 135 } 136 137 tmp = realloc(set->tests, sizeof(*tests) * (cnt + set->cnt)); 138 if (!tmp) 139 goto err; 140 141 memcpy(tmp + set->cnt, tests, sizeof(*tests) * cnt); 142 set->tests = tmp; 143 set->cnt += cnt; 144 145 free(tests); 146 free(input); 147 return 0; 148 149 err: 150 for (i = 0; i < cnt; i++) { 151 for (j = 0; j < tests[i].subtest_cnt; j++) 152 free(tests[i].subtests[j]); 153 154 free(tests[i].name); 155 } 156 free(tests); 157 free(input); 158 return -ENOMEM; 159 } 160 161 __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info) 162 { 163 __u32 info_len = sizeof(*info); 164 int err; 165 166 memset(info, 0, sizeof(*info)); 167 err = bpf_link_get_info_by_fd(bpf_link__fd(link), info, &info_len); 168 if (err) { 169 printf("failed to get link info: %d\n", -errno); 170 return 0; 171 } 172 return info->prog_id; 173 } 174 175 int extra_prog_load_log_flags = 0; 176 177 int bpf_prog_test_load(const char *file, enum bpf_prog_type type, 178 struct bpf_object **pobj, int *prog_fd) 179 { 180 LIBBPF_OPTS(bpf_object_open_opts, opts, 181 .kernel_log_level = extra_prog_load_log_flags, 182 ); 183 struct bpf_object *obj; 184 struct bpf_program *prog; 185 __u32 flags; 186 int err; 187 188 obj = bpf_object__open_file(file, &opts); 189 if (!obj) 190 return -errno; 191 192 prog = bpf_object__next_program(obj, NULL); 193 if (!prog) { 194 err = -ENOENT; 195 goto err_out; 196 } 197 198 if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) 199 bpf_program__set_type(prog, type); 200 201 flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32; 202 bpf_program__set_flags(prog, flags); 203 204 err = bpf_object__load(obj); 205 if (err) 206 goto err_out; 207 208 *pobj = obj; 209 *prog_fd = bpf_program__fd(prog); 210 211 return 0; 212 err_out: 213 bpf_object__close(obj); 214 return err; 215 } 216 217 int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 218 size_t insns_cnt, const char *license, 219 __u32 kern_version, char *log_buf, 220 size_t log_buf_sz) 221 { 222 LIBBPF_OPTS(bpf_prog_load_opts, opts, 223 .kern_version = kern_version, 224 .prog_flags = BPF_F_TEST_RND_HI32, 225 .log_level = extra_prog_load_log_flags, 226 .log_buf = log_buf, 227 .log_size = log_buf_sz, 228 ); 229 230 return bpf_prog_load(type, NULL, license, insns, insns_cnt, &opts); 231 } 232 233 __u64 read_perf_max_sample_freq(void) 234 { 235 __u64 sample_freq = 5000; /* fallback to 5000 on error */ 236 FILE *f; 237 238 f = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r"); 239 if (f == NULL) { 240 printf("Failed to open /proc/sys/kernel/perf_event_max_sample_rate: err %d\n" 241 "return default value: 5000\n", -errno); 242 return sample_freq; 243 } 244 if (fscanf(f, "%llu", &sample_freq) != 1) { 245 printf("Failed to parse /proc/sys/kernel/perf_event_max_sample_rate: err %d\n" 246 "return default value: 5000\n", -errno); 247 } 248 249 fclose(f); 250 return sample_freq; 251 } 252