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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vnet/vnet.h>
19 #include <vppinfra/mem.h>
25 static void pot_profile_cleanup(pot_profile *profile);
27 static void pot_main_profiles_reset (void)
29 pot_main_t *sm = &pot_main;
32 for (i = 0; i < MAX_POT_PROFILES; i++)
34 pot_profile_cleanup(&(sm->profile_list[i]));
36 sm->active_profile_id = 0;
37 if (sm->profile_list_name)
38 vec_free(sm->profile_list_name);
39 sm->profile_list_name = NULL;
42 int pot_util_init (void)
44 pot_main_profiles_reset();
49 static void pot_profile_init(pot_profile * new, u8 id)
53 clib_memset(new, 0, sizeof(pot_profile));
58 pot_profile *pot_profile_find(u8 id)
60 pot_main_t *sm = &pot_main;
62 if (id < MAX_POT_PROFILES)
64 return (&(sm->profile_list[id]));
68 static int pot_profile_name_equal (u8 *name0, u8 *name1)
72 len0 = vec_len (name0);
73 len1 = vec_len (name1);
76 return (0==strncmp ((char *) name0, (char *)name1, len0));
79 int pot_profile_list_is_enabled (u8 *name)
81 pot_main_t *sm = &pot_main;
82 return (pot_profile_name_equal(sm->profile_list_name, name));
85 void pot_profile_list_init(u8 * profile_list_name)
87 pot_main_t *sm = &pot_main;
90 /* If it is the same profile list skip reset */
91 if (pot_profile_name_equal(sm->profile_list_name, profile_list_name))
96 pot_main_profiles_reset();
97 if (vec_len(profile_list_name))
98 sm->profile_list_name = (u8 *)vec_dup(profile_list_name);
100 sm->profile_list_name = 0;
101 sm->active_profile_id = 0;
103 for (i = 0; i < MAX_POT_PROFILES; i++)
105 pot_profile_init(&(sm->profile_list[i]), i);
109 static void pot_profile_cleanup(pot_profile * profile)
111 u16 id = profile->id;
113 clib_memset(profile, 0, sizeof(pot_profile));
114 profile->id = id; /* Restore id alone */
117 int pot_profile_create(pot_profile * profile, u64 prime,
118 u64 poly2, u64 lpc, u64 secret_share)
120 if (profile && !profile->in_use)
122 pot_profile_cleanup(profile);
123 profile->prime = prime;
124 profile->primeinv = 1.0 / prime;
126 profile->poly_pre_eval = poly2;
127 profile->secret_share = secret_share;
128 profile->total_pkts_using_this_profile = 0;
136 int pot_set_validator(pot_profile * profile, u64 key)
138 if (profile && !profile->in_use)
140 profile->validator = 1;
141 profile->secret_key = key;
147 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)
150 u64 share_random = 0;
151 u64 cumulative_new = 0;
154 * calculate split share for random
156 share_random = add64_mod(pre_split, random, prime, prime_inv);
159 * lpc * (share_secret + share_random)
161 share_random = add64_mod(share_random, secret_share, prime, prime_inv);
162 share_random = mul64_mod(share_random, lpc, prime, prime_inv);
164 cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv);
166 return (cumulative_new);
169 u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random)
171 if (profile && profile->valid != 0)
173 return (pot_update_cumulative_inline(cumulative, random, profile->secret_share,
174 profile->prime, profile->lpc, profile->poly_pre_eval,
180 always_inline u8 pot_validate_inline(u64 secret, u64 prime, double prime_inv,
181 u64 cumulative, u64 random)
183 if (cumulative == (random + secret))
187 else if (cumulative == add64_mod(random, secret, prime, prime_inv))
195 * return True if the cumulative matches secret from a profile
197 u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random)
199 if (profile && profile->validator)
201 return (pot_validate_inline(profile->secret_key, profile->prime,
202 profile->primeinv, cumulative, random));
208 * Utility function to get random number per pack
210 u64 pot_generate_random(pot_profile * profile)
216 if (PREDICT_FALSE(!seed))
217 seed = random_default_seed();
220 * Upper 4 bytes seconds
222 random = (u64) time(NULL);
224 random &= 0xffffffff;
225 random = random << 32;
227 * Lower 4 bytes random number
229 second_half = random_u32(&seed);
231 random |= second_half;
233 if (PREDICT_TRUE(profile != NULL))
235 random &= profile->bit_mask;
240 int pot_profile_set_bit_mask(pot_profile * profile, u16 bits)
244 if (profile && !profile->in_use)
246 sizeInBits = sizeof(profile->bit_mask) * 8;
249 sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1);
255 clib_error_t *clear_pot_profile_command_fn(vlib_main_t * vm,
256 unformat_input_t * input, vlib_cli_command_t * cmd)
259 pot_main_profiles_reset();
264 void clear_pot_profiles()
266 clear_pot_profile_command_fn(0, 0, 0);
269 VLIB_CLI_COMMAND(clear_pot_profile_command) =
271 .path = "clear pot profile",
272 .short_help = "clear pot profile [<index>|all]",
273 .function = clear_pot_profile_command_fn,
276 static clib_error_t *set_pot_profile_command_fn(vlib_main_t * vm,
277 unformat_input_t * input, vlib_cli_command_t * cmd)
285 u64 lpc = 0, poly2 = 0;
286 pot_profile *profile = NULL;
287 u8 *profile_list_name = NULL;
291 while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
293 if (unformat(input, "name %s",
294 &profile_list_name));
295 else if (unformat(input, "id %d", &profile_id))
297 else if (unformat(input, "validate-key 0x%Lx", &secret_key))
299 else if (unformat(input, "prime-number 0x%Lx", &prime))
301 else if (unformat(input, "secret_share 0x%Lx", &secret_share))
303 else if (unformat(input, "polynomial2 0x%Lx", &poly2))
305 else if (unformat(input, "lpc 0x%Lx", &lpc))
307 else if (unformat(input, "bits-in-random %d", &bits))
315 if (profile_list_name == 0)
317 return clib_error_return(0, "Name cannot be null");
319 pot_profile_list_init(profile_list_name);
320 profile = pot_profile_find(profile_id);
324 pot_profile_create(profile, prime, poly2, lpc, secret_share);
326 pot_set_validator(profile, secret_key);
327 pot_profile_set_bit_mask(profile, bits);
329 vec_free(profile_list_name);
333 VLIB_CLI_COMMAND(set_pot_profile_command) =
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,
342 static clib_error_t *set_pot_profile_activate_command_fn(vlib_main_t * vm,
343 unformat_input_t * input, vlib_cli_command_t * cmd)
345 pot_main_t *sm = &pot_main;
346 u8 *profile_list_name = NULL;
348 clib_error_t *result = NULL;
350 while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
352 if (unformat(input, "name %s",
353 &profile_list_name));
354 else if (unformat(input, "id %d", &id))
357 return clib_error_return(0, "unknown input `%U'",
358 format_unformat_error, input);
360 if (profile_list_name == 0)
362 return clib_error_return(0, "Name cannot be null");
365 if (!pot_profile_list_is_enabled(profile_list_name)) {
366 result = clib_error_return(0, "%s list is not enabled, profile in use %s",
367 profile_list_name, sm->profile_list_name);
368 } else if (0 != pot_profile_set_active((u8)id)) {
369 result = clib_error_return(0, "Profile %d not defined in %s",
370 id, sm->profile_list_name);
372 vec_free(profile_list_name);
376 VLIB_CLI_COMMAND(set_pot_profile_activate_command) =
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,
383 static clib_error_t *show_pot_profile_command_fn(vlib_main_t * vm,
384 unformat_input_t * input, vlib_cli_command_t * cmd)
386 pot_main_t *sm = &pot_main;
387 pot_profile *p = NULL;
391 if (vec_len(sm->profile_list_name) == 0)
393 s = format(s, "POT Profiles not configured\n");
394 vlib_cli_output(vm, "%v", s);
397 s = format(s, "Profile list in use : %s\n",sm->profile_list_name);
398 for (i = 0; i < MAX_POT_PROFILES; i++)
400 p = pot_profile_find(i);
403 s = format(s, "POT Profile at index: %d\n", i);
404 s = format(s, " Id : %d\n", p->id);
405 s = format(s, " Validator : %s (%d)\n",
406 (p->validator) ? "True" : "False", p->validator);
407 if (p->validator == 1)
408 s = format(s, " Secret key : 0x%Lx (%Ld)\n",
409 p->secret_key, p->secret_key);
410 s = format(s, " Secret share : 0x%Lx (%Ld)\n",
411 p->secret_share, p->secret_share);
412 s = format(s, " Prime number : 0x%Lx (%Ld)\n",
414 s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n",
415 p->poly_pre_eval, p->poly_pre_eval);
416 s = format(s, " LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc);
418 s = format(s, " Bit mask : 0x%Lx (%Ld)\n",
419 p->bit_mask, p->bit_mask);
422 p = pot_profile_find(sm->active_profile_id);
424 if (p && p->valid && p->in_use) {
425 s = format(s, "\nProfile index in use: %d\n", sm->active_profile_id);
426 s = format(s, "Pkts passed : 0x%Lx (%Ld)\n",
427 p->total_pkts_using_this_profile,
428 p->total_pkts_using_this_profile);
430 s = format(s, " This is Decap node. \n");
432 s = format(s, "\nProfile index in use: None\n");
434 vlib_cli_output(vm, "%v", s);
440 VLIB_CLI_COMMAND(show_pot_profile_command) =
442 .path = "show pot profile",
443 .short_help = "show pot profile",
444 .function = show_pot_profile_command_fn,