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