brintos

brintos / linux-shallow public Read only

0
0
Text · 5.2 KiB · d4bb40a Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.4 */5 6#ifdef DEBUG7 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#endif93	}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#endif169 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#endif210err_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	else220		pr_err("ratelimiter self-test %d: FAIL\n", test);221 222	return success;223}224#endif225