1
2
3
4
5#ifdef __RDSEED__
6#include <x86intrin.h>
7#endif
8#include <unistd.h>
9
10#include <rte_branch_prediction.h>
11#include <rte_cycles.h>
12#include <rte_lcore.h>
13#include <rte_random.h>
14
15struct rte_rand_state {
16 uint64_t z1;
17 uint64_t z2;
18 uint64_t z3;
19 uint64_t z4;
20 uint64_t z5;
21} __rte_cache_aligned;
22
23static struct rte_rand_state rand_states[RTE_MAX_LCORE];
24
25static uint32_t
26__rte_rand_lcg32(uint32_t *seed)
27{
28 *seed = 1103515245U * *seed + 12345U;
29
30 return *seed;
31}
32
33static uint64_t
34__rte_rand_lcg64(uint32_t *seed)
35{
36 uint64_t low;
37 uint64_t high;
38
39
40
41
42
43 low = __rte_rand_lcg32(seed);
44 high = __rte_rand_lcg32(seed);
45
46 return low | (high << 32);
47}
48
49static uint64_t
50__rte_rand_lfsr258_gen_seed(uint32_t *seed, uint64_t min_value)
51{
52 uint64_t res;
53
54 res = __rte_rand_lcg64(seed);
55
56 if (res < min_value)
57 res += min_value;
58
59 return res;
60}
61
62static void
63__rte_srand_lfsr258(uint64_t seed, struct rte_rand_state *state)
64{
65 uint32_t lcg_seed;
66
67 lcg_seed = (uint32_t)(seed ^ (seed >> 32));
68
69 state->z1 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 2UL);
70 state->z2 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 512UL);
71 state->z3 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 4096UL);
72 state->z4 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 131072UL);
73 state->z5 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 8388608UL);
74}
75
76void
77rte_srand(uint64_t seed)
78{
79 unsigned int lcore_id;
80
81
82 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
83 __rte_srand_lfsr258(seed + lcore_id, &rand_states[lcore_id]);
84}
85
86static __rte_always_inline uint64_t
87__rte_rand_lfsr258_comp(uint64_t z, uint64_t a, uint64_t b, uint64_t c,
88 uint64_t d)
89{
90 return ((z & c) << d) ^ (((z << a) ^ z) >> b);
91}
92
93
94
95
96
97static __rte_always_inline uint64_t
98__rte_rand_lfsr258(struct rte_rand_state *state)
99{
100 state->z1 = __rte_rand_lfsr258_comp(state->z1, 1UL, 53UL,
101 18446744073709551614UL, 10UL);
102 state->z2 = __rte_rand_lfsr258_comp(state->z2, 24UL, 50UL,
103 18446744073709551104UL, 5UL);
104 state->z3 = __rte_rand_lfsr258_comp(state->z3, 3UL, 23UL,
105 18446744073709547520UL, 29UL);
106 state->z4 = __rte_rand_lfsr258_comp(state->z4, 5UL, 24UL,
107 18446744073709420544UL, 23UL);
108 state->z5 = __rte_rand_lfsr258_comp(state->z5, 3UL, 33UL,
109 18446744073701163008UL, 8UL);
110
111 return state->z1 ^ state->z2 ^ state->z3 ^ state->z4 ^ state->z5;
112}
113
114static __rte_always_inline
115struct rte_rand_state *__rte_rand_get_state(void)
116{
117 unsigned int lcore_id;
118
119 lcore_id = rte_lcore_id();
120
121 if (unlikely(lcore_id == LCORE_ID_ANY))
122 lcore_id = rte_get_main_lcore();
123
124 return &rand_states[lcore_id];
125}
126
127uint64_t
128rte_rand(void)
129{
130 struct rte_rand_state *state;
131
132 state = __rte_rand_get_state();
133
134 return __rte_rand_lfsr258(state);
135}
136
137uint64_t
138rte_rand_max(uint64_t upper_bound)
139{
140 struct rte_rand_state *state;
141 uint8_t ones;
142 uint8_t leading_zeros;
143 uint64_t mask = ~((uint64_t)0);
144 uint64_t res;
145
146 if (unlikely(upper_bound < 2))
147 return 0;
148
149 state = __rte_rand_get_state();
150
151 ones = __builtin_popcountll(upper_bound);
152
153
154
155
156 if (unlikely(ones == 1))
157 return __rte_rand_lfsr258(state) & (upper_bound - 1);
158
159
160
161
162
163
164
165
166 leading_zeros = __builtin_clzll(upper_bound);
167 mask >>= leading_zeros;
168
169 do {
170 res = __rte_rand_lfsr258(state) & mask;
171 } while (unlikely(res >= upper_bound));
172
173 return res;
174}
175
176double
177rte_drand(void)
178{
179 static const uint64_t denom = (uint64_t)1 << 53;
180 uint64_t rand64 = rte_rand();
181
182
183
184
185
186
187
188
189
190
191 rand64 &= denom - 1;
192 return (double)rand64 / denom;
193}
194
195static uint64_t
196__rte_random_initial_seed(void)
197{
198#ifdef RTE_LIBEAL_USE_GETENTROPY
199 int ge_rc;
200 uint64_t ge_seed;
201
202 ge_rc = getentropy(&ge_seed, sizeof(ge_seed));
203
204 if (ge_rc == 0)
205 return ge_seed;
206#endif
207#ifdef __RDSEED__
208 unsigned int rdseed_low;
209 unsigned int rdseed_high;
210
211
212 if (_rdseed32_step(&rdseed_low) == 1 &&
213 _rdseed32_step(&rdseed_high) == 1)
214 return (uint64_t)rdseed_low | ((uint64_t)rdseed_high << 32);
215#endif
216
217 return rte_get_tsc_cycles();
218}
219
220RTE_INIT(rte_rand_init)
221{
222 uint64_t seed;
223
224 seed = __rte_random_initial_seed();
225
226 rte_srand(seed);
227}
228