Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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] = { true, 0 },
 15	[PACKETS_BURSTABLE] = { false, 0 },
 16	[PACKETS_BURSTABLE + 1] = { 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(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(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(skb4, &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(skb4, &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(skb6, &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(skb6, &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(&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(skb4, &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(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(skb4, sizeof(*hdr4));
152	hdr4->saddr = htonl(8182);
153	skb_reset_network_header(skb4);
154	++test;
155
156#if IS_ENABLED(CONFIG_IPV6)
157	skb6 = alloc_skb(sizeof(struct ipv6hdr), GFP_KERNEL);
158	if (unlikely(!skb6)) {
159		kfree_skb(skb4);
160		goto err_nofree;
161	}
162	skb6->protocol = htons(ETH_P_IPV6);
163	hdr6 = (struct ipv6hdr *)skb_put(skb6, 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(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_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_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(skb4);
207#if IS_ENABLED(CONFIG_IPV6)
208	kfree_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