Linux Audio

Check our new training course

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.8
  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
 14int 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
 75static 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
105subtest:
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
129static 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
165err:
166	free(ext_test_str);
167	free(ext_subtest_str);
168
169	return -ENOMEM;
170}
171
172int 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
218int 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
253int extra_prog_load_log_flags = 0;
254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
256		       struct bpf_object **pobj, int *prog_fd)
257{
258	LIBBPF_OPTS(bpf_object_open_opts, opts,
259		.kernel_log_level = extra_prog_load_log_flags,
260	);
261	struct bpf_object *obj;
262	struct bpf_program *prog;
263	__u32 flags;
264	int err;
265
266	obj = bpf_object__open_file(file, &opts);
267	if (!obj)
268		return -errno;
269
270	prog = bpf_object__next_program(obj, NULL);
271	if (!prog) {
272		err = -ENOENT;
273		goto err_out;
274	}
275
276	if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type)
277		bpf_program__set_type(prog, type);
278
279	flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS;
280	bpf_program__set_flags(prog, flags);
281
282	err = bpf_object__load(obj);
283	if (err)
284		goto err_out;
285
286	*pobj = obj;
287	*prog_fd = bpf_program__fd(prog);
288
289	return 0;
290err_out:
291	bpf_object__close(obj);
292	return err;
293}
294
295int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
296			  size_t insns_cnt, const char *license,
297			  __u32 kern_version, char *log_buf,
298			  size_t log_buf_sz)
299{
300	LIBBPF_OPTS(bpf_prog_load_opts, opts,
301		.kern_version = kern_version,
302		.prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS,
303		.log_level = extra_prog_load_log_flags,
304		.log_buf = log_buf,
305		.log_size = log_buf_sz,
306	);
307
308	return bpf_prog_load(type, NULL, license, insns, insns_cnt, &opts);
309}
310
311__u64 read_perf_max_sample_freq(void)
312{
313	__u64 sample_freq = 5000; /* fallback to 5000 on error */
314	FILE *f;
315
316	f = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r");
317	if (f == NULL) {
318		printf("Failed to open /proc/sys/kernel/perf_event_max_sample_rate: err %d\n"
319		       "return default value: 5000\n", -errno);
320		return sample_freq;
321	}
322	if (fscanf(f, "%llu", &sample_freq) != 1) {
323		printf("Failed to parse /proc/sys/kernel/perf_event_max_sample_rate: err %d\n"
324		       "return default value: 5000\n", -errno);
325	}
326
327	fclose(f);
328	return sample_freq;
329}
330
331static int finit_module(int fd, const char *param_values, int flags)
332{
333	return syscall(__NR_finit_module, fd, param_values, flags);
334}
335
336static int delete_module(const char *name, int flags)
337{
338	return syscall(__NR_delete_module, name, flags);
339}
340
341int unload_bpf_testmod(bool verbose)
342{
 
 
343	if (kern_sync_rcu())
344		fprintf(stdout, "Failed to trigger kernel-side RCU sync!\n");
345	if (delete_module("bpf_testmod", 0)) {
 
 
 
 
 
 
 
 
 
 
 
 
346		if (errno == ENOENT) {
347			if (verbose)
348				fprintf(stdout, "bpf_testmod.ko is already unloaded.\n");
349			return -1;
350		}
351		fprintf(stdout, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno);
352		return -1;
353	}
354	if (verbose)
355		fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n");
356	return 0;
357}
358
359int load_bpf_testmod(bool verbose)
360{
361	int fd;
362
363	if (verbose)
364		fprintf(stdout, "Loading bpf_testmod.ko...\n");
365
366	fd = open("bpf_testmod.ko", O_RDONLY);
367	if (fd < 0) {
368		fprintf(stdout, "Can't find bpf_testmod.ko kernel module: %d\n", -errno);
369		return -ENOENT;
370	}
371	if (finit_module(fd, "", 0)) {
372		fprintf(stdout, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno);
373		close(fd);
374		return -EINVAL;
375	}
376	close(fd);
377
378	if (verbose)
379		fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n");
380	return 0;
381}
382
 
 
 
 
 
 
 
 
 
 
383/*
384 * Trigger synchronize_rcu() in kernel.
385 */
386int kern_sync_rcu(void)
387{
388	return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389}