xref: /linux/tools/testing/selftests/bpf/prog_tests/rhash_timer.c (revision 2beb1b31a12b57e19cd5c82ea6d54e56520605e8)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <sched.h>
5 
6 #include <test_progs.h>
7 #include "rhash_timer.skel.h"
8 
9 #define MAX_ATTEMPTS 256
10 #define RCU_SYNC_INTERVAL 64
11 
pin_to_first_cpu(cpu_set_t * old_mask)12 static int pin_to_first_cpu(cpu_set_t *old_mask)
13 {
14 	cpu_set_t new_mask;
15 	int cpu;
16 
17 	if (sched_getaffinity(0, sizeof(*old_mask), old_mask))
18 		return -errno;
19 
20 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++)
21 		if (CPU_ISSET(cpu, old_mask))
22 			break;
23 	if (cpu == CPU_SETSIZE)
24 		return -EINVAL;
25 
26 	CPU_ZERO(&new_mask);
27 	CPU_SET(cpu, &new_mask);
28 	if (sched_setaffinity(0, sizeof(new_mask), &new_mask))
29 		return -errno;
30 	return 0;
31 }
32 
update_timer_map(int map_fd,__u64 key)33 static int update_timer_map(int map_fd, __u64 key)
34 {
35 	__u64 value[3] = {};
36 
37 	return bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST);
38 }
39 
run_prog(int prog_fd,struct bpf_test_run_opts * opts)40 static int run_prog(int prog_fd, struct bpf_test_run_opts *opts)
41 {
42 	int err;
43 
44 	err = bpf_prog_test_run_opts(prog_fd, opts);
45 	if (err)
46 		return err;
47 	return opts->retval;
48 }
49 
test_rhash_timer(void)50 void test_rhash_timer(void)
51 {
52 	LIBBPF_OPTS(bpf_test_run_opts, opts);
53 	struct rhash_timer *skel = NULL;
54 	cpu_set_t old_mask;
55 	int map_fd = -1, arm_fd, cancel_fd;
56 	bool affinity_set = false;
57 	__u64 key = 1;
58 	int attempt, err;
59 
60 	err = pin_to_first_cpu(&old_mask);
61 	if (!ASSERT_OK(err, "pin_to_first_cpu"))
62 		return;
63 	affinity_set = true;
64 
65 	skel = rhash_timer__open_and_load();
66 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
67 		goto out;
68 
69 	map_fd = bpf_map__fd(skel->maps.timer_map);
70 	if (!ASSERT_GE(map_fd, 0, "timer_map fd"))
71 		goto out;
72 	arm_fd = bpf_program__fd(skel->progs.arm_deleted_timer);
73 	if (!ASSERT_GE(arm_fd, 0, "arm_deleted_timer fd"))
74 		goto out;
75 	cancel_fd = bpf_program__fd(skel->progs.cancel_recycled_timer);
76 	if (!ASSERT_GE(cancel_fd, 0, "cancel_recycled_timer fd"))
77 		goto out;
78 
79 	err = update_timer_map(map_fd, key);
80 	if (!ASSERT_OK(err, "seed_timer_map"))
81 		goto out;
82 
83 	for (attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
84 		err = run_prog(arm_fd, &opts);
85 		if (err) {
86 			ASSERT_OK(err, "arm_deleted_timer");
87 			goto out;
88 		}
89 		if (skel->bss->armed != attempt + 1) {
90 			ASSERT_EQ(skel->bss->armed, attempt + 1, "armed");
91 			goto out;
92 		}
93 		if (skel->bss->timer_init_err) {
94 			ASSERT_OK(skel->bss->timer_init_err, "timer_init_err");
95 			goto out;
96 		}
97 		if (skel->bss->timer_set_callback_err) {
98 			ASSERT_OK(skel->bss->timer_set_callback_err,
99 				  "timer_set_callback_err");
100 			goto out;
101 		}
102 		if (skel->bss->timer_start_err) {
103 			ASSERT_OK(skel->bss->timer_start_err, "timer_start_err");
104 			goto out;
105 		}
106 
107 		if ((attempt + 1) % RCU_SYNC_INTERVAL == 0) {
108 			err = kern_sync_rcu();
109 			if (err) {
110 				ASSERT_OK(err, "kern_sync_rcu");
111 				goto out;
112 			}
113 		}
114 
115 		err = update_timer_map(map_fd, ++key);
116 		if (err) {
117 			ASSERT_OK(err, "replace_timer_map");
118 			goto out;
119 		}
120 
121 		err = run_prog(cancel_fd, &opts);
122 		if (err) {
123 			ASSERT_OK(err, "cancel_recycled_timer");
124 			goto out;
125 		}
126 		if (skel->bss->timer_cancel_err) {
127 			ASSERT_OK(skel->bss->timer_cancel_err, "timer_cancel_err");
128 			goto out;
129 		}
130 		if (skel->bss->cancelled)
131 			break;
132 	}
133 
134 	ASSERT_GT(skel->bss->cancelled, 0, "preserved timer");
135 out:
136 	if (map_fd >= 0)
137 		bpf_map_delete_elem(map_fd, &key);
138 	rhash_timer__destroy(skel);
139 	if (affinity_set)
140 		sched_setaffinity(0, sizeof(old_mask), &old_mask);
141 }
142