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