Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : #include <vnet/vnet.h>
16 : #include <stdint.h>
17 : #include <time.h>
18 : #include <string.h>
19 : #include <vppinfra/mem.h>
20 : #include "math64.h"
21 : #include "pot_util.h"
22 :
23 : pot_main_t pot_main;
24 :
25 : static void pot_profile_cleanup(pot_profile *profile);
26 :
27 559 : static void pot_main_profiles_reset (void)
28 : {
29 559 : pot_main_t *sm = &pot_main;
30 559 : int i = 0;
31 :
32 1677 : for (i = 0; i < MAX_POT_PROFILES; i++)
33 : {
34 1118 : pot_profile_cleanup(&(sm->profile_list[i]));
35 : }
36 559 : sm->active_profile_id = 0;
37 559 : if (sm->profile_list_name)
38 0 : vec_free(sm->profile_list_name);
39 559 : sm->profile_list_name = NULL;
40 559 : }
41 :
42 559 : int pot_util_init (void)
43 : {
44 559 : pot_main_profiles_reset();
45 :
46 559 : return(0);
47 : }
48 :
49 0 : static void pot_profile_init(pot_profile * new, u8 id)
50 : {
51 0 : if (new)
52 : {
53 0 : clib_memset(new, 0, sizeof(pot_profile));
54 0 : new->id = id;
55 : }
56 0 : }
57 :
58 0 : pot_profile *pot_profile_find(u8 id)
59 : {
60 0 : pot_main_t *sm = &pot_main;
61 :
62 0 : if (id < MAX_POT_PROFILES)
63 : {
64 0 : return (&(sm->profile_list[id]));
65 : }
66 0 : return (NULL);
67 : }
68 0 : static int pot_profile_name_equal (u8 *name0, u8 *name1)
69 : {
70 : int len0, len1;
71 :
72 0 : len0 = vec_len (name0);
73 0 : len1 = vec_len (name1);
74 0 : if (len0 != len1)
75 0 : return(0);
76 0 : return (0==strncmp ((char *) name0, (char *)name1, len0));
77 : }
78 :
79 0 : int pot_profile_list_is_enabled (u8 *name)
80 : {
81 0 : pot_main_t *sm = &pot_main;
82 0 : return (pot_profile_name_equal(sm->profile_list_name, name));
83 : }
84 :
85 0 : void pot_profile_list_init(u8 * profile_list_name)
86 : {
87 0 : pot_main_t *sm = &pot_main;
88 0 : int i = 0;
89 :
90 : /* If it is the same profile list skip reset */
91 0 : if (pot_profile_name_equal(sm->profile_list_name, profile_list_name))
92 : {
93 0 : return;
94 : }
95 :
96 0 : pot_main_profiles_reset();
97 0 : if (vec_len(profile_list_name))
98 0 : sm->profile_list_name = (u8 *)vec_dup(profile_list_name);
99 : else
100 0 : sm->profile_list_name = 0;
101 0 : sm->active_profile_id = 0;
102 :
103 0 : for (i = 0; i < MAX_POT_PROFILES; i++)
104 : {
105 0 : pot_profile_init(&(sm->profile_list[i]), i);
106 : }
107 : }
108 :
109 1118 : static void pot_profile_cleanup(pot_profile * profile)
110 : {
111 1118 : u16 id = profile->id;
112 :
113 1118 : clib_memset(profile, 0, sizeof(pot_profile));
114 1118 : profile->id = id; /* Restore id alone */
115 1118 : }
116 :
117 0 : int pot_profile_create(pot_profile * profile, u64 prime,
118 : u64 poly2, u64 lpc, u64 secret_share)
119 : {
120 0 : if (profile && !profile->in_use)
121 : {
122 0 : pot_profile_cleanup(profile);
123 0 : profile->prime = prime;
124 0 : profile->primeinv = 1.0 / prime;
125 0 : profile->lpc = lpc;
126 0 : profile->poly_pre_eval = poly2;
127 0 : profile->secret_share = secret_share;
128 0 : profile->total_pkts_using_this_profile = 0;
129 0 : profile->valid = 1;
130 0 : return(0);
131 : }
132 :
133 0 : return(-1);
134 : }
135 :
136 0 : int pot_set_validator(pot_profile * profile, u64 key)
137 : {
138 0 : if (profile && !profile->in_use)
139 : {
140 0 : profile->validator = 1;
141 0 : profile->secret_key = key;
142 0 : return(0);
143 : }
144 0 : return(-1);
145 : }
146 :
147 0 : always_inline u64 pot_update_cumulative_inline(u64 cumulative, u64 random,
148 : u64 secret_share, u64 prime, u64 lpc, u64 pre_split, double prime_inv)
149 : {
150 0 : u64 share_random = 0;
151 0 : u64 cumulative_new = 0;
152 :
153 : /*
154 : * calculate split share for random
155 : */
156 0 : share_random = add64_mod(pre_split, random, prime, prime_inv);
157 :
158 : /*
159 : * lpc * (share_secret + share_random)
160 : */
161 0 : share_random = add64_mod(share_random, secret_share, prime, prime_inv);
162 0 : share_random = mul64_mod(share_random, lpc, prime, prime_inv);
163 :
164 0 : cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv);
165 :
166 0 : return (cumulative_new);
167 : }
168 :
169 0 : u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random)
170 : {
171 0 : if (profile && profile->valid != 0)
172 : {
173 0 : return (pot_update_cumulative_inline(cumulative, random, profile->secret_share,
174 : profile->prime, profile->lpc, profile->poly_pre_eval,
175 : profile->primeinv));
176 : }
177 0 : return (0);
178 : }
179 :
180 0 : always_inline u8 pot_validate_inline(u64 secret, u64 prime, double prime_inv,
181 : u64 cumulative, u64 random)
182 : {
183 0 : if (cumulative == (random + secret))
184 : {
185 0 : return (1);
186 : }
187 0 : else if (cumulative == add64_mod(random, secret, prime, prime_inv))
188 : {
189 0 : return (1);
190 : }
191 0 : return (0);
192 : }
193 :
194 : /*
195 : * return True if the cumulative matches secret from a profile
196 : */
197 0 : u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random)
198 : {
199 0 : if (profile && profile->validator)
200 : {
201 0 : return (pot_validate_inline(profile->secret_key, profile->prime,
202 : profile->primeinv, cumulative, random));
203 : }
204 0 : return (0);
205 : }
206 :
207 : /*
208 : * Utility function to get random number per pack
209 : */
210 0 : u64 pot_generate_random(pot_profile * profile)
211 : {
212 0 : u64 random = 0;
213 : int32_t second_half;
214 : static u32 seed = 0;
215 :
216 0 : if (PREDICT_FALSE(!seed))
217 0 : seed = random_default_seed();
218 :
219 : /*
220 : * Upper 4 bytes seconds
221 : */
222 0 : random = (u64) time(NULL);
223 :
224 0 : random &= 0xffffffff;
225 0 : random = random << 32;
226 : /*
227 : * Lower 4 bytes random number
228 : */
229 0 : second_half = random_u32(&seed);
230 :
231 0 : random |= second_half;
232 :
233 0 : if (PREDICT_TRUE(profile != NULL))
234 : {
235 0 : random &= profile->bit_mask;
236 : }
237 0 : return (random);
238 : }
239 :
240 0 : int pot_profile_set_bit_mask(pot_profile * profile, u16 bits)
241 : {
242 : int sizeInBits;
243 :
244 0 : if (profile && !profile->in_use)
245 : {
246 0 : sizeInBits = sizeof(profile->bit_mask) * 8;
247 0 : profile->bit_mask =
248 0 : (bits >=
249 0 : sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1);
250 0 : return(0);
251 : }
252 0 : return(-1);
253 : }
254 :
255 0 : clib_error_t *clear_pot_profile_command_fn(vlib_main_t * vm,
256 : unformat_input_t * input, vlib_cli_command_t * cmd)
257 : {
258 :
259 0 : pot_main_profiles_reset();
260 :
261 0 : return 0;
262 : }
263 :
264 0 : void clear_pot_profiles()
265 : {
266 0 : clear_pot_profile_command_fn(0, 0, 0);
267 0 : }
268 :
269 176567 : VLIB_CLI_COMMAND(clear_pot_profile_command) =
270 : {
271 : .path = "clear pot profile",
272 : .short_help = "clear pot profile [<index>|all]",
273 : .function = clear_pot_profile_command_fn,
274 : };
275 :
276 0 : static clib_error_t *set_pot_profile_command_fn(vlib_main_t * vm,
277 : unformat_input_t * input, vlib_cli_command_t * cmd)
278 : {
279 : u64 prime;
280 : u64 secret_share;
281 : u64 secret_key;
282 0 : u8 validator = 0;
283 0 : u32 profile_id = ~0;
284 : u32 bits;
285 0 : u64 lpc = 0, poly2 = 0;
286 0 : pot_profile *profile = NULL;
287 0 : u8 *profile_list_name = NULL;
288 :
289 0 : bits = MAX_BITS;
290 :
291 0 : while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
292 : {
293 0 : if (unformat(input, "name %s",
294 : &profile_list_name));
295 0 : else if (unformat(input, "id %d", &profile_id))
296 : ;
297 0 : else if (unformat(input, "validate-key 0x%Lx", &secret_key))
298 0 : validator = 1;
299 0 : else if (unformat(input, "prime-number 0x%Lx", &prime))
300 : ;
301 0 : else if (unformat(input, "secret_share 0x%Lx", &secret_share))
302 : ;
303 0 : else if (unformat(input, "polynomial2 0x%Lx", &poly2))
304 : ;
305 0 : else if (unformat(input, "lpc 0x%Lx", &lpc))
306 : ;
307 0 : else if (unformat(input, "bits-in-random %d", &bits))
308 : {
309 0 : if (bits > MAX_BITS)
310 0 : bits = MAX_BITS;
311 : }
312 : else
313 0 : break;
314 : }
315 0 : if (profile_list_name == 0)
316 : {
317 0 : return clib_error_return(0, "Name cannot be null");
318 : }
319 0 : pot_profile_list_init(profile_list_name);
320 0 : profile = pot_profile_find(profile_id);
321 :
322 0 : if (profile)
323 : {
324 0 : pot_profile_create(profile, prime, poly2, lpc, secret_share);
325 0 : if (validator)
326 0 : pot_set_validator(profile, secret_key);
327 0 : pot_profile_set_bit_mask(profile, bits);
328 : }
329 0 : vec_free(profile_list_name);
330 0 : return 0;
331 : }
332 :
333 176567 : VLIB_CLI_COMMAND(set_pot_profile_command) =
334 : {
335 : .path = "set pot profile",
336 : .short_help = "set pot profile name <string> id [0-1] [validator-key 0xu64] \
337 : prime-number 0xu64 secret_share 0xu64 lpc 0xu64 \
338 : polynomial2 0xu64 bits-in-random [0-64] ",
339 : .function = set_pot_profile_command_fn,
340 : };
341 :
342 0 : static clib_error_t *set_pot_profile_activate_command_fn(vlib_main_t * vm,
343 : unformat_input_t * input, vlib_cli_command_t * cmd)
344 : {
345 0 : pot_main_t *sm = &pot_main;
346 0 : u8 *profile_list_name = NULL;
347 0 : u32 id = 0;
348 0 : clib_error_t *result = NULL;
349 :
350 0 : while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
351 : {
352 0 : if (unformat(input, "name %s",
353 : &profile_list_name));
354 0 : else if (unformat(input, "id %d", &id))
355 : ;
356 : else
357 0 : return clib_error_return(0, "unknown input `%U'",
358 : format_unformat_error, input);
359 : }
360 0 : if (profile_list_name == 0)
361 : {
362 0 : return clib_error_return(0, "Name cannot be null");
363 : }
364 :
365 0 : if (!pot_profile_list_is_enabled(profile_list_name)) {
366 0 : result = clib_error_return(0, "%s list is not enabled, profile in use %s",
367 : profile_list_name, sm->profile_list_name);
368 0 : } else if (0 != pot_profile_set_active((u8)id)) {
369 0 : result = clib_error_return(0, "Profile %d not defined in %s",
370 : id, sm->profile_list_name);
371 : }
372 0 : vec_free(profile_list_name);
373 0 : return result;
374 : }
375 :
376 176567 : VLIB_CLI_COMMAND(set_pot_profile_activate_command) =
377 : {
378 : .path = "set pot profile-active",
379 : .short_help = "set pot profile-active name <string> id [0-1]",
380 : .function = set_pot_profile_activate_command_fn,
381 : };
382 :
383 0 : static clib_error_t *show_pot_profile_command_fn(vlib_main_t * vm,
384 : unformat_input_t * input, vlib_cli_command_t * cmd)
385 : {
386 0 : pot_main_t *sm = &pot_main;
387 0 : pot_profile *p = NULL;
388 : u16 i;
389 0 : u8 *s = 0;
390 :
391 0 : if (vec_len(sm->profile_list_name) == 0)
392 : {
393 0 : s = format(s, "POT Profiles not configured\n");
394 0 : vlib_cli_output(vm, "%v", s);
395 0 : return 0;
396 : }
397 0 : s = format(s, "Profile list in use : %s\n",sm->profile_list_name);
398 0 : for (i = 0; i < MAX_POT_PROFILES; i++)
399 : {
400 0 : p = pot_profile_find(i);
401 0 : if (p->valid == 0)
402 0 : continue;
403 0 : s = format(s, "POT Profile at index: %d\n", i);
404 0 : s = format(s, " Id : %d\n", p->id);
405 0 : s = format(s, " Validator : %s (%d)\n",
406 0 : (p->validator) ? "True" : "False", p->validator);
407 0 : if (p->validator == 1)
408 0 : s = format(s, " Secret key : 0x%Lx (%Ld)\n",
409 : p->secret_key, p->secret_key);
410 0 : s = format(s, " Secret share : 0x%Lx (%Ld)\n",
411 : p->secret_share, p->secret_share);
412 0 : s = format(s, " Prime number : 0x%Lx (%Ld)\n",
413 : p->prime, p->prime);
414 0 : s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n",
415 : p->poly_pre_eval, p->poly_pre_eval);
416 0 : s = format(s, " LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc);
417 :
418 0 : s = format(s, " Bit mask : 0x%Lx (%Ld)\n",
419 : p->bit_mask, p->bit_mask);
420 : }
421 :
422 0 : p = pot_profile_find(sm->active_profile_id);
423 :
424 0 : if (p && p->valid && p->in_use) {
425 0 : s = format(s, "\nProfile index in use: %d\n", sm->active_profile_id);
426 0 : s = format(s, "Pkts passed : 0x%Lx (%Ld)\n",
427 : p->total_pkts_using_this_profile,
428 : p->total_pkts_using_this_profile);
429 0 : if (pot_is_decap(p))
430 0 : s = format(s, " This is Decap node. \n");
431 : } else {
432 0 : s = format(s, "\nProfile index in use: None\n");
433 : }
434 0 : vlib_cli_output(vm, "%v", s);
435 0 : vec_free(s);
436 :
437 0 : return 0;
438 : }
439 :
440 176567 : VLIB_CLI_COMMAND(show_pot_profile_command) =
441 : {
442 : .path = "show pot profile",
443 : .short_help = "show pot profile",
444 : .function = show_pot_profile_command_fn,
445 : };
|