185b528e0SShwetha/*
285b528e0SShwetha * Copyright (c) 2016 Cisco and/or its affiliates.
385b528e0SShwetha * Licensed under the Apache License, Version 2.0 (the "License");
485b528e0SShwetha * you may not use this file except in compliance with the License.
585b528e0SShwetha * You may obtain a copy of the License at:
685b528e0SShwetha *
785b528e0SShwetha *     http://www.apache.org/licenses/LICENSE-2.0
885b528e0SShwetha *
985b528e0SShwetha * Unless required by applicable law or agreed to in writing, software
1085b528e0SShwetha * distributed under the License is distributed on an "AS IS" BASIS,
1185b528e0SShwetha * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1285b528e0SShwetha * See the License for the specific language governing permissions and
1385b528e0SShwetha * limitations under the License.
1485b528e0SShwetha */
1585b528e0SShwetha#include <vnet/vnet.h>
1685b528e0SShwetha#include <stdint.h>
1785b528e0SShwetha#include <time.h>
1885b528e0SShwetha#include <string.h>
1985b528e0SShwetha#include <vppinfra/mem.h>
2085b528e0SShwetha#include "math64.h"
2185b528e0SShwetha#include "pot_util.h"
2285b528e0SShwetha
2385b528e0SShwethapot_main_t pot_main;
2485b528e0SShwetha
2585b528e0SShwethastatic void pot_profile_cleanup(pot_profile *profile);
2685b528e0SShwetha
2785b528e0SShwethastatic void pot_main_profiles_reset (void)
2885b528e0SShwetha{
2985b528e0SShwetha    pot_main_t *sm = &pot_main;
3085b528e0SShwetha    int i = 0;
3185b528e0SShwetha
3285b528e0SShwetha    for (i = 0; i < MAX_POT_PROFILES; i++)
3385b528e0SShwetha    {
3485b528e0SShwetha      pot_profile_cleanup(&(sm->profile_list[i]));
3585b528e0SShwetha    }
3685b528e0SShwetha    sm->active_profile_id = 0;
3785b528e0SShwetha    if (sm->profile_list_name)
3885b528e0SShwetha	vec_free(sm->profile_list_name);
3985b528e0SShwetha    sm->profile_list_name = NULL;
4085b528e0SShwetha}
4185b528e0SShwetha
4285b528e0SShwethaint pot_util_init (void)
4385b528e0SShwetha{
4485b528e0SShwetha    pot_main_profiles_reset();
4585b528e0SShwetha
4685b528e0SShwetha    return(0);
4785b528e0SShwetha}
4885b528e0SShwetha
4985b528e0SShwethastatic void pot_profile_init(pot_profile * new, u8 id)
5085b528e0SShwetha{
5185b528e0SShwetha    if (new)
5285b528e0SShwetha    {
53b7b92993SDave Barach        clib_memset(new, 0, sizeof(pot_profile));
5485b528e0SShwetha        new->id = id;
5585b528e0SShwetha    }
5685b528e0SShwetha}
5785b528e0SShwetha
5885b528e0SShwethapot_profile *pot_profile_find(u8 id)
5985b528e0SShwetha{
6085b528e0SShwetha    pot_main_t *sm = &pot_main;
6185b528e0SShwetha
62c53191deSDave Barach    if (id < MAX_POT_PROFILES)
6385b528e0SShwetha    {
6485b528e0SShwetha        return (&(sm->profile_list[id]));
6585b528e0SShwetha    }
6685b528e0SShwetha    return (NULL);
6785b528e0SShwetha}
6885b528e0SShwethastatic int pot_profile_name_equal (u8 *name0, u8 *name1)
6985b528e0SShwetha{
7085b528e0SShwetha    int len0, len1;
7185b528e0SShwetha
7285b528e0SShwetha    len0 = vec_len (name0);
7385b528e0SShwetha    len1 = vec_len (name1);
7485b528e0SShwetha    if (len0 != len1)
7585b528e0SShwetha        return(0);
7685b528e0SShwetha    return (0==strncmp ((char *) name0, (char *)name1, len0));
7785b528e0SShwetha}
7885b528e0SShwetha
7985b528e0SShwethaint pot_profile_list_is_enabled (u8 *name)
8085b528e0SShwetha{
8185b528e0SShwetha    pot_main_t *sm = &pot_main;
8285b528e0SShwetha    return (pot_profile_name_equal(sm->profile_list_name, name));
8385b528e0SShwetha}
8485b528e0SShwetha
8585b528e0SShwethavoid pot_profile_list_init(u8 * profile_list_name)
8685b528e0SShwetha{
8785b528e0SShwetha    pot_main_t *sm = &pot_main;
8885b528e0SShwetha    int i = 0;
8985b528e0SShwetha
9085b528e0SShwetha    /* If it is the same profile list skip reset */
9185b528e0SShwetha    if (pot_profile_name_equal(sm->profile_list_name, profile_list_name))
9285b528e0SShwetha    {
9385b528e0SShwetha      return;
9485b528e0SShwetha    }
9585b528e0SShwetha
9685b528e0SShwetha    pot_main_profiles_reset();
9785b528e0SShwetha    if (vec_len(profile_list_name))
9885b528e0SShwetha      sm->profile_list_name = (u8 *)vec_dup(profile_list_name);
9985b528e0SShwetha    else
10085b528e0SShwetha      sm->profile_list_name = 0;
10185b528e0SShwetha    sm->active_profile_id = 0;
10285b528e0SShwetha
10385b528e0SShwetha    for (i = 0; i < MAX_POT_PROFILES; i++)
10485b528e0SShwetha    {
10585b528e0SShwetha      pot_profile_init(&(sm->profile_list[i]), i);
10685b528e0SShwetha    }
10785b528e0SShwetha}
10885b528e0SShwetha
10985b528e0SShwethastatic void pot_profile_cleanup(pot_profile * profile)
11085b528e0SShwetha{
11185b528e0SShwetha    u16 id = profile->id;
11285b528e0SShwetha
113b7b92993SDave Barach    clib_memset(profile, 0, sizeof(pot_profile));
11485b528e0SShwetha    profile->id = id;           /* Restore id alone */
11585b528e0SShwetha}
11685b528e0SShwetha
11785b528e0SShwethaint pot_profile_create(pot_profile * profile, u64 prime,
11885b528e0SShwetha    u64 poly2, u64 lpc, u64 secret_share)
11985b528e0SShwetha{
12085b528e0SShwetha    if (profile && !profile->in_use)
12185b528e0SShwetha    {
12285b528e0SShwetha        pot_profile_cleanup(profile);
12385b528e0SShwetha        profile->prime = prime;
12485b528e0SShwetha        profile->primeinv = 1.0 / prime;
12585b528e0SShwetha        profile->lpc = lpc;
12685b528e0SShwetha        profile->poly_pre_eval = poly2;
12785b528e0SShwetha        profile->secret_share = secret_share;
12885b528e0SShwetha	profile->total_pkts_using_this_profile = 0;
12985b528e0SShwetha        profile->valid = 1;
13085b528e0SShwetha	return(0);
13185b528e0SShwetha    }
13285b528e0SShwetha
13385b528e0SShwetha    return(-1);
13485b528e0SShwetha}
13585b528e0SShwetha
13685b528e0SShwethaint pot_set_validator(pot_profile * profile, u64 key)
13785b528e0SShwetha{
13885b528e0SShwetha    if (profile && !profile->in_use)
13985b528e0SShwetha    {
14085b528e0SShwetha        profile->validator = 1;
14185b528e0SShwetha        profile->secret_key = key;
14285b528e0SShwetha	return(0);
14385b528e0SShwetha    }
14485b528e0SShwetha    return(-1);
14585b528e0SShwetha}
14685b528e0SShwetha
14785b528e0SShwethaalways_inline u64 pot_update_cumulative_inline(u64 cumulative, u64 random,
14885b528e0SShwetha    u64 secret_share, u64 prime, u64 lpc, u64 pre_split, double prime_inv)
14985b528e0SShwetha{
15085b528e0SShwetha    u64 share_random = 0;
15185b528e0SShwetha    u64 cumulative_new = 0;
15285b528e0SShwetha
15385b528e0SShwetha    /*
15485b528e0SShwetha     * calculate split share for random
15585b528e0SShwetha     */
15685b528e0SShwetha    share_random = add64_mod(pre_split, random, prime, prime_inv);
15785b528e0SShwetha
15885b528e0SShwetha    /*
15985b528e0SShwetha     * lpc * (share_secret + share_random)
16085b528e0SShwetha     */
16185b528e0SShwetha    share_random = add64_mod(share_random, secret_share, prime, prime_inv);
16285b528e0SShwetha    share_random = mul64_mod(share_random, lpc, prime, prime_inv);
16385b528e0SShwetha
16485b528e0SShwetha    cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv);
16585b528e0SShwetha
16685b528e0SShwetha    return (cumulative_new);
16785b528e0SShwetha}
16885b528e0SShwetha
16985b528e0SShwethau64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random)
17085b528e0SShwetha{
17185b528e0SShwetha    if (profile && profile->valid != 0)
17285b528e0SShwetha    {
17385b528e0SShwetha        return (pot_update_cumulative_inline(cumulative, random, profile->secret_share,
17485b528e0SShwetha                profile->prime, profile->lpc, profile->poly_pre_eval,
17585b528e0SShwetha                profile->primeinv));
17685b528e0SShwetha    }
17785b528e0SShwetha    return (0);
17885b528e0SShwetha}
17985b528e0SShwetha
18085b528e0SShwethaalways_inline u8 pot_validate_inline(u64 secret, u64 prime, double prime_inv,
18185b528e0SShwetha    u64 cumulative, u64 random)
18285b528e0SShwetha{
18385b528e0SShwetha    if (cumulative == (random + secret))
18485b528e0SShwetha    {
18585b528e0SShwetha        return (1);
18685b528e0SShwetha    }
18785b528e0SShwetha    else if (cumulative == add64_mod(random, secret, prime, prime_inv))
18885b528e0SShwetha    {
18985b528e0SShwetha        return (1);
19085b528e0SShwetha    }
19185b528e0SShwetha    return (0);
19285b528e0SShwetha}
19385b528e0SShwetha
19485b528e0SShwetha/*
19585b528e0SShwetha * return True if the cumulative matches secret from a profile
19685b528e0SShwetha */
19785b528e0SShwethau8 pot_validate(pot_profile * profile, u64 cumulative, u64 random)
19885b528e0SShwetha{
19985b528e0SShwetha    if (profile && profile->validator)
20085b528e0SShwetha    {
20185b528e0SShwetha        return (pot_validate_inline(profile->secret_key, profile->prime,
20285b528e0SShwetha                profile->primeinv, cumulative, random));
20385b528e0SShwetha    }
20485b528e0SShwetha    return (0);
20585b528e0SShwetha}
20685b528e0SShwetha
20785b528e0SShwetha/*
20885b528e0SShwetha * Utility function to get random number per pack
20985b528e0SShwetha */
21085b528e0SShwethau64 pot_generate_random(pot_profile * profile)
21185b528e0SShwetha{
21285b528e0SShwetha    u64 random = 0;
21385b528e0SShwetha    int32_t second_half;
21485b528e0SShwetha    static u32 seed = 0;
21585b528e0SShwetha
21685b528e0SShwetha    if (PREDICT_FALSE(!seed))
21785b528e0SShwetha        seed = random_default_seed();
21885b528e0SShwetha
21985b528e0SShwetha    /*
22085b528e0SShwetha     * Upper 4 bytes seconds
22185b528e0SShwetha     */
22285b528e0SShwetha    random = (u64) time(NULL);
22385b528e0SShwetha
22485b528e0SShwetha    random &= 0xffffffff;
22585b528e0SShwetha    random = random << 32;
22685b528e0SShwetha    /*
22785b528e0SShwetha     * Lower 4 bytes random number
22885b528e0SShwetha     */
22985b528e0SShwetha    second_half = random_u32(&seed);
23085b528e0SShwetha
23185b528e0SShwetha    random |= second_half;
23285b528e0SShwetha
23385b528e0SShwetha    if (PREDICT_TRUE(profile != NULL))
23485b528e0SShwetha    {
23585b528e0SShwetha        random &= profile->bit_mask;
23685b528e0SShwetha    }
23785b528e0SShwetha    return (random);
23885b528e0SShwetha}
23985b528e0SShwetha
24085b528e0SShwethaint pot_profile_set_bit_mask(pot_profile * profile, u16 bits)
24185b528e0SShwetha{
24285b528e0SShwetha    int sizeInBits;
24385b528e0SShwetha
24485b528e0SShwetha    if (profile && !profile->in_use)
24585b528e0SShwetha    {
24685b528e0SShwetha        sizeInBits = sizeof(profile->bit_mask) * 8;
24785b528e0SShwetha        profile->bit_mask =
24885b528e0SShwetha            (bits >=
24985b528e0SShwetha            sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1);
25085b528e0SShwetha	return(0);
25185b528e0SShwetha    }
25285b528e0SShwetha    return(-1);
25385b528e0SShwetha}
25485b528e0SShwetha
25585b528e0SShwethaclib_error_t *clear_pot_profile_command_fn(vlib_main_t * vm,
25685b528e0SShwetha    unformat_input_t * input, vlib_cli_command_t * cmd)
25785b528e0SShwetha{
25885b528e0SShwetha
25985b528e0SShwetha    pot_main_profiles_reset();
26085b528e0SShwetha
26185b528e0SShwetha    return 0;
26285b528e0SShwetha}
26385b528e0SShwetha
26485b528e0SShwethavoid clear_pot_profiles()
26585b528e0SShwetha{
26685b528e0SShwetha    clear_pot_profile_command_fn(0, 0, 0);
26785b528e0SShwetha}
26885b528e0SShwetha
26985b528e0SShwethaVLIB_CLI_COMMAND(clear_pot_profile_command) =
27085b528e0SShwetha{
27185b528e0SShwetha.path = "clear pot profile",
27285b528e0SShwetha.short_help = "clear pot profile [<index>|all]",
27385b528e0SShwetha.function = clear_pot_profile_command_fn,
27485b528e0SShwetha};
27585b528e0SShwetha
27685b528e0SShwethastatic clib_error_t *set_pot_profile_command_fn(vlib_main_t * vm,
27785b528e0SShwetha    unformat_input_t * input, vlib_cli_command_t * cmd)
27885b528e0SShwetha{
27985b528e0SShwetha    u64 prime;
28085b528e0SShwetha    u64 secret_share;
28185b528e0SShwetha    u64 secret_key;
28285b528e0SShwetha    u8 validator = 0;
283c53191deSDave Barach    u32 profile_id = ~0;
28485b528e0SShwetha    u32 bits;
28585b528e0SShwetha    u64 lpc = 0, poly2 = 0;
28685b528e0SShwetha    pot_profile *profile = NULL;
28785b528e0SShwetha    u8 *profile_list_name = NULL;
28885b528e0SShwetha
28985b528e0SShwetha    bits = MAX_BITS;
29085b528e0SShwetha
29185b528e0SShwetha    while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
29285b528e0SShwetha    {
29385b528e0SShwetha        if (unformat(input, "name %s",
29485b528e0SShwetha		     &profile_list_name));
29585b528e0SShwetha        else if (unformat(input, "id %d", &profile_id))
29685b528e0SShwetha            ;
29785b528e0SShwetha        else if (unformat(input, "validate-key 0x%Lx", &secret_key))
29885b528e0SShwetha            validator = 1;
29985b528e0SShwetha        else if (unformat(input, "prime-number 0x%Lx", &prime))
30085b528e0SShwetha            ;
30185b528e0SShwetha        else if (unformat(input, "secret_share 0x%Lx", &secret_share))
30285b528e0SShwetha            ;
30385b528e0SShwetha        else if (unformat(input, "polynomial2 0x%Lx", &poly2))
30485b528e0SShwetha            ;
30585b528e0SShwetha        else if (unformat(input, "lpc 0x%Lx", &lpc))
30685b528e0SShwetha            ;
30785b528e0SShwetha        else if (unformat(input, "bits-in-random %d", &bits))
30885b528e0SShwetha        {
30985b528e0SShwetha            if (bits > MAX_BITS)
31085b528e0SShwetha                bits = MAX_BITS;
31185b528e0SShwetha        }
31285b528e0SShwetha        else
31357fc854cSShwetha	  break;
31485b528e0SShwetha    }
31585b528e0SShwetha    if (profile_list_name == 0)
31685b528e0SShwetha    {
31785b528e0SShwetha        return clib_error_return(0, "Name cannot be null");
31885b528e0SShwetha    }
31985b528e0SShwetha    pot_profile_list_init(profile_list_name);
32085b528e0SShwetha    profile = pot_profile_find(profile_id);
32185b528e0SShwetha
32285b528e0SShwetha    if (profile)
32385b528e0SShwetha    {
32485b528e0SShwetha        pot_profile_create(profile, prime, poly2, lpc, secret_share);
32585b528e0SShwetha        if (validator)
32685b528e0SShwetha            pot_set_validator(profile, secret_key);
32785b528e0SShwetha        pot_profile_set_bit_mask(profile, bits);
32885b528e0SShwetha    }
32985b528e0SShwetha    vec_free(profile_list_name);
33085b528e0SShwetha    return 0;
33185b528e0SShwetha}
33285b528e0SShwetha
33385b528e0SShwethaVLIB_CLI_COMMAND(set_pot_profile_command) =
33485b528e0SShwetha{
33585b528e0SShwetha.path = "set pot profile",
33685b528e0SShwetha.short_help = "set pot profile name <string> id [0-1] [validator-key 0xu64] \
33785b528e0SShwetha                  prime-number 0xu64 secret_share 0xu64 lpc 0xu64 \
33885b528e0SShwetha                  polynomial2 0xu64 bits-in-random [0-64] ",
33985b528e0SShwetha.function = set_pot_profile_command_fn,
34085b528e0SShwetha};
34185b528e0SShwetha
34285b528e0SShwethastatic clib_error_t *set_pot_profile_activate_command_fn(vlib_main_t * vm,
34385b528e0SShwetha    unformat_input_t * input, vlib_cli_command_t * cmd)
34485b528e0SShwetha{
34585b528e0SShwetha    pot_main_t *sm = &pot_main;
34685b528e0SShwetha    u8 *profile_list_name = NULL;
34785b528e0SShwetha    u32 id = 0;
34885b528e0SShwetha    clib_error_t *result = NULL;
34985b528e0SShwetha
35085b528e0SShwetha    while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
35185b528e0SShwetha    {
35285b528e0SShwetha        if (unformat(input, "name %s",
35385b528e0SShwetha		     &profile_list_name));
35485b528e0SShwetha        else if (unformat(input, "id %d", &id))
35585b528e0SShwetha            ;
35685b528e0SShwetha        else
35785b528e0SShwetha            return clib_error_return(0, "unknown input `%U'",
35885b528e0SShwetha                format_unformat_error, input);
35985b528e0SShwetha    }
36085b528e0SShwetha    if (profile_list_name == 0)
36185b528e0SShwetha    {
36285b528e0SShwetha        return clib_error_return(0, "Name cannot be null");
36385b528e0SShwetha    }
36485b528e0SShwetha
36585b528e0SShwetha    if (!pot_profile_list_is_enabled(profile_list_name)) {
36685b528e0SShwetha        result = clib_error_return(0, "%s list is not enabled, profile in use %s",
36785b528e0SShwetha				 profile_list_name, sm->profile_list_name);
36885b528e0SShwetha    } else if (0 != pot_profile_set_active((u8)id)) {
36985b528e0SShwetha        result = clib_error_return(0, "Profile %d not defined in %s",
37085b528e0SShwetha				 id, sm->profile_list_name);
37185b528e0SShwetha    }
37285b528e0SShwetha    vec_free(profile_list_name);
37385b528e0SShwetha    return result;
37485b528e0SShwetha}
37585b528e0SShwetha
37685b528e0SShwethaVLIB_CLI_COMMAND(set_pot_profile_activate_command) =
37785b528e0SShwetha{
37885b528e0SShwetha.path = "set pot profile-active",
37985b528e0SShwetha.short_help = "set pot profile-active name <string> id [0-1]",
38085b528e0SShwetha.function = set_pot_profile_activate_command_fn,
38185b528e0SShwetha};
38285b528e0SShwetha
38385b528e0SShwethastatic clib_error_t *show_pot_profile_command_fn(vlib_main_t * vm,
38485b528e0SShwetha    unformat_input_t * input, vlib_cli_command_t * cmd)
38585b528e0SShwetha{
38685b528e0SShwetha    pot_main_t *sm = &pot_main;
38785b528e0SShwetha    pot_profile *p = NULL;
38885b528e0SShwetha    u16 i;
38985b528e0SShwetha    u8 *s = 0;
39085b528e0SShwetha
39185b528e0SShwetha    if (vec_len(sm->profile_list_name) == 0)
39285b528e0SShwetha    {
39385b528e0SShwetha        s = format(s, "POT Profiles not configured\n");
39485b528e0SShwetha        vlib_cli_output(vm, "%v", s);
39585b528e0SShwetha        return 0;
39685b528e0SShwetha    }
39785b528e0SShwetha    s = format(s, "Profile list in use  : %s\n",sm->profile_list_name);
39885b528e0SShwetha    for (i = 0; i < MAX_POT_PROFILES; i++)
39985b528e0SShwetha    {
40085b528e0SShwetha        p = pot_profile_find(i);
40185b528e0SShwetha        if (p->valid == 0)
40285b528e0SShwetha            continue;
40385b528e0SShwetha        s = format(s, "POT Profile at index: %d\n", i);
40485b528e0SShwetha        s = format(s, "                 Id : %d\n", p->id);
40585b528e0SShwetha        s = format(s, "          Validator : %s (%d)\n",
40685b528e0SShwetha            (p->validator) ? "True" : "False", p->validator);
40785b528e0SShwetha        if (p->validator == 1)
40885b528e0SShwetha            s = format(s, "         Secret key : 0x%Lx (%Ld)\n",
40985b528e0SShwetha                p->secret_key, p->secret_key);
41085b528e0SShwetha        s = format(s, "       Secret share : 0x%Lx (%Ld)\n",
41185b528e0SShwetha            p->secret_share, p->secret_share);
41285b528e0SShwetha        s = format(s, "       Prime number : 0x%Lx (%Ld)\n",
41385b528e0SShwetha            p->prime, p->prime);
41485b528e0SShwetha        s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n",
41585b528e0SShwetha            p->poly_pre_eval, p->poly_pre_eval);
41685b528e0SShwetha        s = format(s, "                 LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc);
41785b528e0SShwetha
41885b528e0SShwetha        s = format(s, "           Bit mask : 0x%Lx (%Ld)\n",
41985b528e0SShwetha            p->bit_mask, p->bit_mask);
42085b528e0SShwetha    }
42185b528e0SShwetha
42285b528e0SShwetha    p = pot_profile_find(sm->active_profile_id);
42385b528e0SShwetha
42485b528e0SShwetha    if (p && p->valid && p->in_use) {
42585b528e0SShwetha        s = format(s, "\nProfile index in use: %d\n", sm->active_profile_id);
42685b528e0SShwetha        s = format(s, "Pkts passed : 0x%Lx (%Ld)\n",
42785b528e0SShwetha		   p->total_pkts_using_this_profile,
42885b528e0SShwetha		   p->total_pkts_using_this_profile);
42985b528e0SShwetha        if (pot_is_decap(p))
43085b528e0SShwetha            s = format(s, "  This is Decap node.  \n");
43185b528e0SShwetha    } else {
43285b528e0SShwetha        s = format(s, "\nProfile index in use: None\n");
43385b528e0SShwetha    }
43485b528e0SShwetha    vlib_cli_output(vm, "%v", s);
43585b528e0SShwetha    vec_free(s);
43685b528e0SShwetha
43785b528e0SShwetha    return 0;
43885b528e0SShwetha}
43985b528e0SShwetha
44085b528e0SShwethaVLIB_CLI_COMMAND(show_pot_profile_command) =
44185b528e0SShwetha{
44285b528e0SShwetha.path = "show pot profile",
44385b528e0SShwetha.short_help = "show pot profile",
44485b528e0SShwetha.function = show_pot_profile_command_fn,
44585b528e0SShwetha};
446