/src/openvswitch/lib/random.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at: |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include <config.h> |
18 | | #include "random.h" |
19 | | |
20 | | #include <errno.h> |
21 | | #include <stdlib.h> |
22 | | #include <sys/time.h> |
23 | | |
24 | | #include "entropy.h" |
25 | | #include "hash.h" |
26 | | #include "ovs-thread.h" |
27 | | #include "timeval.h" |
28 | | #include "util.h" |
29 | | |
30 | | /* This is the 32-bit PRNG recommended in G. Marsaglia, "Xorshift RNGs", |
31 | | * _Journal of Statistical Software_ 8:14 (July 2003). According to the paper, |
32 | | * it has a period of 2**32 - 1 and passes almost all tests of randomness. |
33 | | * |
34 | | * We use this PRNG instead of libc's rand() because rand() varies in quality |
35 | | * and because its maximum value also varies between 32767 and INT_MAX, whereas |
36 | | * we often want random numbers in the full range of uint32_t. |
37 | | * |
38 | | * This random number generator is intended for purposes that do not require |
39 | | * cryptographic-quality randomness. */ |
40 | | |
41 | | /* Current random state. */ |
42 | | DEFINE_STATIC_PER_THREAD_DATA(uint32_t, seed, 0); |
43 | | |
44 | | static uint32_t random_next(void); |
45 | | |
46 | | void |
47 | | random_init(void) |
48 | 0 | { |
49 | 0 | uint32_t *seedp = seed_get(); |
50 | 0 | while (!*seedp) { |
51 | 0 | struct timeval tv; |
52 | 0 | uint32_t entropy; |
53 | 0 | pthread_t self; |
54 | |
|
55 | 0 | xgettimeofday(&tv); |
56 | 0 | get_entropy_or_die(&entropy, 4); |
57 | 0 | self = pthread_self(); |
58 | |
|
59 | 0 | *seedp = (tv.tv_sec ^ tv.tv_usec ^ entropy |
60 | 0 | ^ hash_bytes(&self, sizeof self, 0)); |
61 | 0 | } |
62 | 0 | } |
63 | | |
64 | | void |
65 | | random_set_seed(uint32_t seed_) |
66 | 0 | { |
67 | 0 | ovs_assert(seed_); |
68 | 0 | *seed_get() = seed_; |
69 | 0 | } |
70 | | |
71 | | void |
72 | | random_bytes(void *p_, size_t n) |
73 | 0 | { |
74 | 0 | uint8_t *p = p_; |
75 | |
|
76 | 0 | random_init(); |
77 | |
|
78 | 0 | for (; n > 4; p += 4, n -= 4) { |
79 | 0 | uint32_t x = random_next(); |
80 | 0 | memcpy(p, &x, 4); |
81 | 0 | } |
82 | |
|
83 | 0 | if (n) { |
84 | 0 | uint32_t x = random_next(); |
85 | 0 | memcpy(p, &x, n); |
86 | 0 | } |
87 | 0 | } |
88 | | |
89 | | |
90 | | uint32_t |
91 | | random_uint32(void) |
92 | 0 | { |
93 | 0 | random_init(); |
94 | 0 | return random_next(); |
95 | 0 | } |
96 | | |
97 | | uint64_t |
98 | | random_uint64(void) |
99 | 0 | { |
100 | 0 | uint64_t x; |
101 | |
|
102 | 0 | random_init(); |
103 | |
|
104 | 0 | x = random_next(); |
105 | 0 | x |= (uint64_t) random_next() << 32; |
106 | 0 | return x; |
107 | 0 | } |
108 | | |
109 | | static uint32_t |
110 | | random_next(void) |
111 | 0 | { |
112 | 0 | uint32_t *seedp = seed_get_unsafe(); |
113 | |
|
114 | 0 | *seedp ^= *seedp << 13; |
115 | 0 | *seedp ^= *seedp >> 17; |
116 | 0 | *seedp ^= *seedp << 5; |
117 | |
|
118 | 0 | return *seedp; |
119 | 0 | } |