1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4 */
5
6#ifdef DEBUG
7
8#include <linux/jiffies.h>
9
10static const struct {
11 bool result;
12 unsigned int msec_to_sleep_before;
13} expected_results[] __initconst = {
14 [0 ... PACKETS_BURSTABLE - 1] = { .result: true, .msec_to_sleep_before: 0 },
15 [PACKETS_BURSTABLE] = { false, 0 },
16 [PACKETS_BURSTABLE + 1] = { .result: true, MSEC_PER_SEC / PACKETS_PER_SECOND },
17 [PACKETS_BURSTABLE + 2] = { false, 0 },
18 [PACKETS_BURSTABLE + 3] = { true, (MSEC_PER_SEC / PACKETS_PER_SECOND) * 2 },
19 [PACKETS_BURSTABLE + 4] = { true, 0 },
20 [PACKETS_BURSTABLE + 5] = { false, 0 }
21};
22
23static __init unsigned int maximum_jiffies_at_index(int index)
24{
25 unsigned int total_msecs = 2 * MSEC_PER_SEC / PACKETS_PER_SECOND / 3;
26 int i;
27
28 for (i = 0; i <= index; ++i)
29 total_msecs += expected_results[i].msec_to_sleep_before;
30 return msecs_to_jiffies(m: total_msecs);
31}
32
33static __init int timings_test(struct sk_buff *skb4, struct iphdr *hdr4,
34 struct sk_buff *skb6, struct ipv6hdr *hdr6,
35 int *test)
36{
37 unsigned long loop_start_time;
38 int i;
39
40 wg_ratelimiter_gc_entries(NULL);
41 rcu_barrier();
42 loop_start_time = jiffies;
43
44 for (i = 0; i < ARRAY_SIZE(expected_results); ++i) {
45 if (expected_results[i].msec_to_sleep_before)
46 msleep(msecs: expected_results[i].msec_to_sleep_before);
47
48 if (time_is_before_jiffies(loop_start_time +
49 maximum_jiffies_at_index(i)))
50 return -ETIMEDOUT;
51 if (wg_ratelimiter_allow(skb: skb4, net: &init_net) !=
52 expected_results[i].result)
53 return -EXFULL;
54 ++(*test);
55
56 hdr4->saddr = htonl(ntohl(hdr4->saddr) + i + 1);
57 if (time_is_before_jiffies(loop_start_time +
58 maximum_jiffies_at_index(i)))
59 return -ETIMEDOUT;
60 if (!wg_ratelimiter_allow(skb: skb4, net: &init_net))
61 return -EXFULL;
62 ++(*test);
63
64 hdr4->saddr = htonl(ntohl(hdr4->saddr) - i - 1);
65
66#if IS_ENABLED(CONFIG_IPV6)
67 hdr6->saddr.in6_u.u6_addr32[2] = htonl(i);
68 hdr6->saddr.in6_u.u6_addr32[3] = htonl(i);
69 if (time_is_before_jiffies(loop_start_time +
70 maximum_jiffies_at_index(i)))
71 return -ETIMEDOUT;
72 if (wg_ratelimiter_allow(skb: skb6, net: &init_net) !=
73 expected_results[i].result)
74 return -EXFULL;
75 ++(*test);
76
77 hdr6->saddr.in6_u.u6_addr32[0] =
78 htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) + i + 1);
79 if (time_is_before_jiffies(loop_start_time +
80 maximum_jiffies_at_index(i)))
81 return -ETIMEDOUT;
82 if (!wg_ratelimiter_allow(skb: skb6, net: &init_net))
83 return -EXFULL;
84 ++(*test);
85
86 hdr6->saddr.in6_u.u6_addr32[0] =
87 htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) - i - 1);
88
89 if (time_is_before_jiffies(loop_start_time +
90 maximum_jiffies_at_index(i)))
91 return -ETIMEDOUT;
92#endif
93 }
94 return 0;
95}
96
97static __init int capacity_test(struct sk_buff *skb4, struct iphdr *hdr4,
98 int *test)
99{
100 int i;
101
102 wg_ratelimiter_gc_entries(NULL);
103 rcu_barrier();
104
105 if (atomic_read(v: &total_entries))
106 return -EXFULL;
107 ++(*test);
108
109 for (i = 0; i <= max_entries; ++i) {
110 hdr4->saddr = htonl(i);
111 if (wg_ratelimiter_allow(skb: skb4, net: &init_net) != (i != max_entries))
112 return -EXFULL;
113 ++(*test);
114 }
115 return 0;
116}
117
118bool __init wg_ratelimiter_selftest(void)
119{
120 enum { TRIALS_BEFORE_GIVING_UP = 5000 };
121 bool success = false;
122 int test = 0, trials;
123 struct sk_buff *skb4, *skb6 = NULL;
124 struct iphdr *hdr4;
125 struct ipv6hdr *hdr6 = NULL;
126
127 if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN))
128 return true;
129
130 BUILD_BUG_ON(MSEC_PER_SEC % PACKETS_PER_SECOND != 0);
131
132 if (wg_ratelimiter_init())
133 goto out;
134 ++test;
135 if (wg_ratelimiter_init()) {
136 wg_ratelimiter_uninit();
137 goto out;
138 }
139 ++test;
140 if (wg_ratelimiter_init()) {
141 wg_ratelimiter_uninit();
142 wg_ratelimiter_uninit();
143 goto out;
144 }
145 ++test;
146
147 skb4 = alloc_skb(size: sizeof(struct iphdr), GFP_KERNEL);
148 if (unlikely(!skb4))
149 goto err_nofree;
150 skb4->protocol = htons(ETH_P_IP);
151 hdr4 = (struct iphdr *)skb_put(skb: skb4, len: sizeof(*hdr4));
152 hdr4->saddr = htonl(8182);
153 skb_reset_network_header(skb: skb4);
154 ++test;
155
156#if IS_ENABLED(CONFIG_IPV6)
157 skb6 = alloc_skb(size: sizeof(struct ipv6hdr), GFP_KERNEL);
158 if (unlikely(!skb6)) {
159 kfree_skb(skb: skb4);
160 goto err_nofree;
161 }
162 skb6->protocol = htons(ETH_P_IPV6);
163 hdr6 = (struct ipv6hdr *)skb_put(skb: skb6, len: sizeof(*hdr6));
164 hdr6->saddr.in6_u.u6_addr32[0] = htonl(1212);
165 hdr6->saddr.in6_u.u6_addr32[1] = htonl(289188);
166 skb_reset_network_header(skb: skb6);
167 ++test;
168#endif
169
170 for (trials = TRIALS_BEFORE_GIVING_UP; IS_ENABLED(DEBUG_RATELIMITER_TIMINGS);) {
171 int test_count = 0, ret;
172
173 ret = timings_test(skb4, hdr4, skb6, hdr6, test: &test_count);
174 if (ret == -ETIMEDOUT) {
175 if (!trials--) {
176 test += test_count;
177 goto err;
178 }
179 continue;
180 } else if (ret < 0) {
181 test += test_count;
182 goto err;
183 } else {
184 test += test_count;
185 break;
186 }
187 }
188
189 for (trials = TRIALS_BEFORE_GIVING_UP;;) {
190 int test_count = 0;
191
192 if (capacity_test(skb4, hdr4, test: &test_count) < 0) {
193 if (!trials--) {
194 test += test_count;
195 goto err;
196 }
197 continue;
198 }
199 test += test_count;
200 break;
201 }
202
203 success = true;
204
205err:
206 kfree_skb(skb: skb4);
207#if IS_ENABLED(CONFIG_IPV6)
208 kfree_skb(skb: skb6);
209#endif
210err_nofree:
211 wg_ratelimiter_uninit();
212 wg_ratelimiter_uninit();
213 wg_ratelimiter_uninit();
214 /* Uninit one extra time to check underflow detection. */
215 wg_ratelimiter_uninit();
216out:
217 if (success)
218 pr_info("ratelimiter self-tests: pass\n");
219 else
220 pr_err("ratelimiter self-test %d: FAIL\n", test);
221
222 return success;
223}
224#endif
225

source code of linux/drivers/net/wireguard/selftest/ratelimiter.c