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