ratelimiter.c (5347B)
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;;) { 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 msleep(500); 180 continue; 181 } else if (ret < 0) { 182 test += test_count; 183 goto err; 184 } else { 185 test += test_count; 186 break; 187 } 188 } 189 190 for (trials = TRIALS_BEFORE_GIVING_UP;;) { 191 int test_count = 0; 192 193 if (capacity_test(skb4, hdr4, &test_count) < 0) { 194 if (!trials--) { 195 test += test_count; 196 goto err; 197 } 198 msleep(50); 199 continue; 200 } 201 test += test_count; 202 break; 203 } 204 205 success = true; 206 207err: 208 kfree_skb(skb4); 209#if IS_ENABLED(CONFIG_IPV6) 210 kfree_skb(skb6); 211#endif 212err_nofree: 213 wg_ratelimiter_uninit(); 214 wg_ratelimiter_uninit(); 215 wg_ratelimiter_uninit(); 216 /* Uninit one extra time to check underflow detection. */ 217 wg_ratelimiter_uninit(); 218out: 219 if (success) 220 pr_info("ratelimiter self-tests: pass\n"); 221 else 222 pr_err("ratelimiter self-test %d: FAIL\n", test); 223 224 return success; 225} 226#endif