e69c8837815f8d642fcceae0f66aad2b950e06f0
[vpp.git] / vnet / vnet / lib-scv / scv_util.c
1 /* 
2  * Copyright (c) 2015 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 "scv_util.h"
22
23 scv_profile *pow_profile = NULL;
24 u16 pow_profile_index = 0;
25 u64 total_pkts_using_this_profile = 0;
26 u8 chain_path_name[PATH_NAME_SIZE];
27 scv_profile profile_list[MAX_SERVICE_PROFILES];
28 u8 max_profiles = 0;
29 u16 invalid_profile_start_index = 0;
30 u8 number_of_invalid_profiles = 0;
31 f64 next_time_to_send = 0;
32 u32 time_exponent = 1;
33 vlib_main_t *gvm = 0;
34
35 static void scv_profile_init(scv_profile * new, u16 id)
36 {
37     if (new)
38     {
39         memset(new, 0, sizeof(scv_profile));
40         new->id = id;
41     }
42 }
43
44 /* 
45  * Get maximum number of profiles configured for this chain.
46  */
47 u8 scv_get_max_profiles(void)
48 {
49     return max_profiles;
50 }
51
52 scv_profile *scv_profile_find(u16 id)
53 {
54     u8 max = scv_get_max_profiles();
55
56     if (id >= 0 && id < max)
57     {
58         return (&profile_list[id]);
59     }
60     return (NULL);
61 }
62
63 u8 sc_init_done = 0;
64 void scv_init(u8 * path_name, u8 max, u8 indx)
65 {
66     int i = 0;
67
68     if (sc_init_done)
69     {
70         return;
71     }
72     memcpy(chain_path_name, path_name, strlen((const char *)path_name) + 1);
73     max_profiles = max;
74     pow_profile_index = indx;
75
76     for (i = 0; i < max_profiles; i++)
77     {
78         scv_profile_init(&profile_list[i], i);
79     }
80
81     sc_init_done = 1;
82 }
83
84 void scv_profile_cleanup(scv_profile * profile)
85 {
86     u16 id = profile->id;
87
88     memset(profile, 0, sizeof(scv_profile));
89     profile->id = id;           /* Restore id alone */
90 }
91
92 void scv_profile_create(scv_profile * profile, u64 prime,
93     u64 poly2, u64 lpc, u64 secret_share, u64 validity)
94 {
95     if (profile)
96     {
97         scv_profile_cleanup(profile);
98         profile->prime = prime;
99         profile->primeinv = 1.0 / prime;
100         profile->lpc = lpc;
101         profile->poly_pre_eval = poly2;
102         profile->secret_share = secret_share;
103         profile->validity = validity;
104         time_exponent = 1;      /* Got a new profile. Reset backoff */
105         next_time_to_send = 0;  /* and send next request with no delay */
106     }
107 }
108
109 void scv_set_validator(scv_profile * profile, u64 key)
110 {
111     if (profile)
112     {
113         profile->validator = 1;
114         profile->secret_key = key;
115     }
116 }
117
118 static inline u64 sc_update_cumulative(u64 cumulative, u64 random,
119     u64 secret_share, u64 prime, u64 lpc, u64 pre_split, double prime_inv)
120 {
121     u64 share_random = 0;
122     u64 cumulative_new = 0;
123
124     /* 
125      * calculate split share for random
126      */
127     share_random = add64_mod(pre_split, random, prime, prime_inv);
128
129     /* 
130      * lpc * (share_secret + share_random)
131      */
132     share_random = add64_mod(share_random, secret_share, prime, prime_inv);
133     share_random = mul64_mod(share_random, lpc, prime, prime_inv);
134
135     cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv);
136
137     return (cumulative_new);
138 }
139
140 u64 scv_update_cumulative(scv_profile * profile, u64 cumulative, u64 random)
141 {
142     if (profile && profile->validity != 0)
143     {
144         return (sc_update_cumulative(cumulative, random, profile->secret_share,
145                 profile->prime, profile->lpc, profile->poly_pre_eval,
146                 profile->primeinv));
147     }
148     return (0);
149 }
150
151 static u8 sc_validate(u64 secret, u64 prime, double prime_inv,
152     u64 cumulative, u64 random)
153 {
154     if (cumulative == (random + secret))
155     {
156         return (1);
157     }
158     else if (cumulative == add64_mod(random, secret, prime, prime_inv))
159     {
160         return (1);
161     }
162     return (0);
163 }
164
165 /* 
166  * return True if the cumulative matches secret from a profile
167  */
168 u8 scv_validate(scv_profile * profile, u64 cumulative, u64 random)
169 {
170     if (profile && profile->validator)
171     {
172         return (sc_validate(profile->secret_key, profile->prime,
173                 profile->primeinv, cumulative, random));
174     }
175     return (0);
176 }
177
178 /* 
179  * Utility function to get random number per pack
180  */
181 u64 scv_generate_random(scv_profile * profile)
182 {
183     u64 random = 0;
184     int32_t second_half;
185     static u32 seed = 0;
186
187     if (PREDICT_FALSE(!seed))
188         seed = random_default_seed();
189
190     /* 
191      * Upper 4 bytes seconds
192      */
193     random = (u64) time(NULL);
194
195     random &= 0xffffffff;
196     random = random << 32;
197     /* 
198      * Lower 4 bytes random number
199      */
200     second_half = random_u32(&seed);
201
202     random |= second_half;
203
204     if (PREDICT_TRUE(profile != NULL))
205     {
206         random &= profile->bit_mask;
207     }
208     return (random);
209 }
210
211 void scv_profile_set_bit_mask(scv_profile * profile, u16 bits)
212 {
213     int sizeInBits;
214
215     if (profile)
216     {
217         sizeInBits = sizeof(profile->bit_mask) * 8;
218         profile->bit_mask =
219             (bits >=
220             sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1);
221     }
222 }
223
224 /* 
225  * TODO: Use vector buffers and hash tables
226  */
227 #define MAX_SERVICES 16
228
229 clib_error_t *clear_scv_profile_command_fn(vlib_main_t * vm,
230     unformat_input_t * input, vlib_cli_command_t * cmd)
231 {
232     int i = 0;
233
234     if (!sc_init_done)
235         return 0;
236
237     for (i = 0; i < max_profiles; i++)
238     {
239         scv_profile_cleanup(&profile_list[i]);
240     }
241     pow_profile = NULL;
242     pow_profile_index = 0;
243     total_pkts_using_this_profile = 0;
244     memset(chain_path_name, 0, PATH_NAME_SIZE);
245     max_profiles = 0;
246     invalid_profile_start_index = 0;
247     number_of_invalid_profiles = 0;
248     next_time_to_send = 0;
249     time_exponent = 1;
250     sc_init_done = 0;
251
252     return 0;
253 }
254
255 void clear_scv_profiles()
256 {
257     clear_scv_profile_command_fn(0, 0, 0);
258 }
259
260 VLIB_CLI_COMMAND(clear_scv_profile_command) =
261 {
262 .path = "clear scv profile",
263 .short_help = "clear scv profile [<index>|all]",
264 .function = clear_scv_profile_command_fn,
265 };
266
267 static clib_error_t *set_scv_profile_command_fn(vlib_main_t * vm,
268     unformat_input_t * input, vlib_cli_command_t * cmd)
269 {
270     u64 prime;
271     u64 secret_share, validity;
272     u64 secret_key;
273     u8 validator = 0;
274     u16 profile_id;
275     u32 bits;
276     u64 lpc = 0, poly2 = 0;
277     scv_profile *profile = NULL;
278
279     bits = MAX_BITS;
280
281     while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
282     {
283         if (unformat(input, "id %d", &profile_id))
284             ;
285         else if (unformat(input, "validate-key 0x%Lx", &secret_key))
286             validator = 1;
287         else if (unformat(input, "prime-number 0x%Lx", &prime))
288             ;
289         else if (unformat(input, "secret_share 0x%Lx", &secret_share))
290             ;
291         else if (unformat(input, "polynomial2 0x%Lx", &poly2))
292             ;
293         else if (unformat(input, "lpc 0x%Lx", &lpc))
294             ;
295         else if (unformat(input, "validity 0x%Lx", &validity))
296             ;
297         else if (unformat(input, "bits-in-random %d", &bits))
298         {
299             if (bits > MAX_BITS)
300                 bits = MAX_BITS;
301         }
302         else
303             return clib_error_return(0, "unknown input `%U'",
304                 format_unformat_error, input);
305     }
306
307     scv_init((u8 *) "TEST", MAX_SERVICE_PROFILES, 0 /* start index */ );
308     profile = scv_profile_find(profile_id);
309
310     if (profile)
311     {
312         scv_profile_create(profile, prime, poly2, lpc, secret_share, validity);
313         if (validator)
314             scv_set_validator(profile, secret_key);
315         scv_profile_set_bit_mask(profile, bits);
316     }
317
318     return 0;
319 }
320
321 VLIB_CLI_COMMAND(set_scv_profile_command) =
322 {
323 .path = "set scv profile",
324 .short_help = "set scv profile id [0-16] [validator-key 0xu64] \
325                   prime-number 0xu64 secret_share 0xu64 lpc 0xu64 \
326                   polynomial2 0xu64 bits-in-random [0-64] ",
327 .function = set_scv_profile_command_fn,
328 };
329
330 static clib_error_t *show_scv_profile_command_fn(vlib_main_t * vm,
331     unformat_input_t * input, vlib_cli_command_t * cmd)
332 {
333     scv_profile *p = NULL;
334     u16 i;
335     u8 *s = 0;
336
337     if (sc_init_done == 0)
338     {
339         s = format(s, "SCV Profiles not configured\n");
340         vlib_cli_output(vm, "%v", s);
341         return 0;
342     }
343
344     for (i = 0; i < max_profiles; i++)
345     {
346         p = scv_profile_find(i);
347         if (p->validity == 0)
348             continue;
349         s = format(s, "SCV Profile at index: %d\n", i);
350         s = format(s, "                 Id : %d\n", p->id);
351         s = format(s, "          Validator : %s (%d)\n",
352             (p->validator) ? "True" : "False", p->validator);
353         if (p->validator == 1)
354             s = format(s, "         Secret key : 0x%Lx (%Ld)\n",
355                 p->secret_key, p->secret_key);
356         s = format(s, "       Secret share : 0x%Lx (%Ld)\n",
357             p->secret_share, p->secret_share);
358         s = format(s, "       Prime number : 0x%Lx (%Ld)\n",
359             p->prime, p->prime);
360         s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n",
361             p->poly_pre_eval, p->poly_pre_eval);
362         s = format(s, "                 LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc);
363
364         s = format(s, "           Bit mask : 0x%Lx (%Ld)\n",
365             p->bit_mask, p->bit_mask);
366         s = format(s, "           Validity : 0x%Lx (%Ld)\n",
367             p->validity, p->validity);
368     }
369
370     if (max_profiles)
371     {
372         p = scv_profile_find(pow_profile_index);
373
374         s = format(s, "\nInvalid profiles start : %d Number : %d\n",
375             invalid_profile_start_index, number_of_invalid_profiles);
376
377         if (next_time_to_send)
378             s = format(s, "\nNext time to send : %U, time_exponent:%ld\n",
379                 format_time_interval, "d:h:m:s:f:u",
380                 next_time_to_send, time_exponent);
381         else
382             s = format(s, "\nNext time to send : Immediate\n");
383         s = format(s, "\nPath name : %s\n", chain_path_name);
384         s = format(s, "\nProfile index in use: %d\n", pow_profile_index);
385         s = format(s, "Pkts passed : 0x%Lx (validity:0x%Lx)\n",
386             total_pkts_using_this_profile, p->validity);
387         if (scv_is_decap(p))
388             s = format(s, "  This is Decap node.  \n");
389         vlib_cli_output(vm, "%v", s);
390     }
391     vec_free(s);
392
393     return 0;
394 }
395
396 VLIB_CLI_COMMAND(show_scv_profile_command) =
397 {
398 .path = "show scv profile",
399 .short_help = "show scv profile",
400 .function = show_scv_profile_command_fn,
401 };
402
403 static clib_error_t *test_profile_renew_refresh_fn(vlib_main_t * vm,
404     unformat_input_t * input, vlib_cli_command_t * cmd)
405 {
406     u8 renew_or_refresh = 0;
407
408 #define TEST_PROFILE_RENEW 1
409 #define TEST_PROFILE_REFRESH 2
410     u8 *path_name = 0;
411     u32 start_index = 0, num_profiles = 0;
412     int rc = 0;
413
414     while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
415     {
416         if (unformat(input, "path-name %s start-index %d num-profiles %d",
417                 &path_name, &start_index, &num_profiles))
418             ;
419         else if (unformat(input, "renew"))
420             renew_or_refresh = TEST_PROFILE_RENEW;
421         else if (unformat(input, "refresh"))
422             renew_or_refresh = TEST_PROFILE_REFRESH;
423         else
424             break;
425     }
426
427     if (renew_or_refresh == TEST_PROFILE_RENEW)
428     {
429         
430         rc = scv_profile_renew(path_name, (u8) start_index, (u8) num_profiles);
431     }
432     else if (renew_or_refresh == TEST_PROFILE_REFRESH)
433     {
434         
435         rc = scv_profile_refresh(path_name, (u8) start_index,
436             (u8) num_profiles);
437     }
438     else
439     {
440         vec_free(path_name);
441         return clib_error_return(0, "Enter renew or refresh");
442     }
443
444     vlib_cli_output(vm, "%s notification %s. rc = %d\n",
445         (renew_or_refresh == TEST_PROFILE_RENEW) ? "Renew" : "Refresh",
446         (rc != 0) ? "failed" : "sent", (u32) rc);
447
448     vec_free(path_name);
449
450     return 0;
451 }
452
453 VLIB_CLI_COMMAND(test_ioam_profile_renew_refresh_cmd, static) =
454 {
455 .path = "test ioam profile-notification  ",
456 .short_help =
457         "test ioam profile-notification path-name <string> start-index <index> num-profiles <number> <renew|refresh>",
458 .function = test_profile_renew_refresh_fn,
459 };
460
461 static clib_error_t *set_scv_init_fn(vlib_main_t * vm,
462     unformat_input_t * input, vlib_cli_command_t * cmd)
463 {
464     u8 *path_name = 0;
465     u32 start_index = 0, num_profiles = 0;
466
467     while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
468     {
469         if (unformat(input, "path-name %s start-index %d num-profiles %d",
470                 &path_name, &start_index, &num_profiles))
471             scv_init(path_name, num_profiles, start_index);
472         else
473             return clib_error_return(0, "unknown input `%U'",
474                 format_unformat_error, input);
475     }
476     vec_free(path_name);
477     return 0;
478 }
479
480 VLIB_CLI_COMMAND(set_ioam_sc_init_command, static) =
481 {
482 .path = "set scv-init ",
483 .short_help =
484         "set scv-init path-name <string> start-index <index> num-profiles <number>",
485 .function = set_scv_init_fn,
486 };