linux/drivers/net/wireguard/selftest/ratelimiter.c
<<
>>
Prefs
   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
 227