Linux Audio

Check our new training course

Embedded Linux training

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