VPP-76:APIs for Proof of transit feature added to iOAM

Moved Proof of Transit utility as a plugin
Moved Proof of Transit option as a plugin

Change-Id: Idc9897205eb8ec80c5dea47b428e6209ac938c32
Signed-off-by: Shwetha <shwethab@cisco.com>
This commit is contained in:
Shwetha
2016-06-15 16:34:16 +01:00
committed by Ole Trøan
parent b6e4d3990e
commit 85b528e093
16 changed files with 1766 additions and 964 deletions

View File

@ -27,9 +27,40 @@ BUILT_SOURCES =
lib_LTLIBRARIES = libsixrd_plugin.la
########################################
# iOAM Proof of Transit
########################################
ioam_pot_plugin_la_SOURCES = plugins/ioam/lib-pot/pot_util.c plugins/ioam/encap/ip6_ioam_pot.c \
plugins/ioam/lib-pot/pot_util.h plugins/ioam/lib-pot/math64.h plugins/ioam/lib-pot/pot_api.c
ioam_pot_plugin_la_LDFLAGS = -module
BUILT_SOURCES = plugins/ioam/lib-pot/pot.api.h
SUFFIXES = .api.h .api
%.api.h: %.api
mkdir -p `dirname $@` ; \
$(CC) $(CPPFLAGS) -E -P -C -x c $^ \
| vppapigen --input - --output $@ --show-name $@
nobase_include_HEADERS = \
plugins/ioam/lib-pot/pot_all_api_h.h \
plugins/ioam/lib-pot/pot_msg_enum.h \
plugins/ioam/lib-pot/pot.api.h \
plugins/ioam/lib-pot/pot_util.h \
plugins/ioam/lib-pot/math64.h
ioam_pot_test_plugin_la_SOURCES = plugins/ioam/lib-pot/pot_test.c plugins/ioam/lib-pot/pot_plugin.api.h
ioam_pot_test_plugin_la_LDFLAGS = -module
lib_LTLIBRARIES += ioam_pot_plugin.la ioam_pot_test_plugin.la
if WITH_PLUGIN_TOOLKIT
install-data-hook:
mkdir /usr/lib/vpp_plugins || true
mkdir /usr/lib/vpp_api_test_plugins || true
cp $(prefix)/lib/sixrd_plugin.so.*.*.* /usr/lib/vpp_plugins
cp $(prefix)/lib/ioam_pot_plugin.so.*.*.* /usr/lib/vpp_plugins
cp $(prefix)/lib/ioam_pot_test_plugin.so.*.*.* \
/usr/lib/vpp_api_test_plugins
endif

View File

@ -0,0 +1,282 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/pg/pg.h>
#include <vppinfra/error.h>
#include <vnet/ip/ip6.h>
#include <vnet/ip/ip6_hop_by_hop.h>
#include <vnet/ip/ip6_hop_by_hop_packet.h>
#include <vppinfra/hash.h>
#include <vppinfra/error.h>
#include <vppinfra/elog.h>
#include <lib-pot/pot_util.h>
typedef CLIB_PACKED(struct {
ip6_hop_by_hop_option_t hdr;
u8 pot_type;
#define PROFILE_ID_MASK 0xF
u8 reserved_profile_id; /* 4 bits reserved, 4 bits to carry profile id */
u64 random;
u64 cumulative;
}) ioam_pot_option_t;
#define foreach_ip6_hop_by_hop_ioam_pot_stats \
_(PROCESSED, "Pkts with ip6 hop-by-hop pot options") \
_(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \
_(PASSED, "Pkts with POT in Policy") \
_(FAILED, "Pkts with POT out of Policy")
static char * ip6_hop_by_hop_ioam_pot_stats_strings[] = {
#define _(sym,string) string,
foreach_ip6_hop_by_hop_ioam_pot_stats
#undef _
};
typedef enum {
#define _(sym,str) IP6_IOAM_POT_##sym,
foreach_ip6_hop_by_hop_ioam_pot_stats
#undef _
IP6_IOAM_POT_N_STATS,
} ip6_ioam_pot_stats_t;
typedef struct {
/* stats */
u64 counters[ARRAY_LEN(ip6_hop_by_hop_ioam_pot_stats_strings)];
/* convenience */
vlib_main_t * vlib_main;
vnet_main_t * vnet_main;
} ip6_hop_by_hop_ioam_pot_main_t;
ip6_hop_by_hop_ioam_pot_main_t ip6_hop_by_hop_ioam_pot_main;
always_inline void
ip6_ioam_stats_increment_counter (u32 counter_index, u64 increment)
{
ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
hm->counters[counter_index] += increment;
}
static u8 * format_ioam_pot (u8 * s, va_list * args)
{
ioam_pot_option_t * pot0 = va_arg (*args, ioam_pot_option_t *);
u64 random, cumulative;
random = cumulative = 0;
if (pot0)
{
random = clib_net_to_host_u64 (pot0->random);
cumulative = clib_net_to_host_u64 (pot0->cumulative);
}
s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x",
random, cumulative, pot0->reserved_profile_id);
return s;
}
u8 *
ip6_hbh_ioam_proof_of_transit_trace_handler (u8 *s, ip6_hop_by_hop_option_t *opt)
{
ioam_pot_option_t *pot;
s = format (s, " POT opt present\n");
pot = (ioam_pot_option_t *) opt;
s = format (s, " %U\n", format_ioam_pot, pot);
return (s);
}
int
ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b,
ip6_header_t *ip,
ip6_hop_by_hop_option_t *opt0)
{
ioam_pot_option_t * pot0;
u64 random = 0, cumulative = 0;
int rv = 0;
u8 pot_profile_index;
pot_profile *pot_profile = 0, *new_profile = 0;
u8 pot_encap = 0;
pot0 = (ioam_pot_option_t *) opt0;
pot_encap = (pot0->random == 0);
pot_profile_index = pot_profile_get_active_id();
pot_profile = pot_profile_get_active();
if (pot_encap && PREDICT_FALSE(!pot_profile))
{
ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
return(-1);
}
if (pot_encap)
{
pot0->reserved_profile_id =
pot_profile_index & PROFILE_ID_MASK;
pot_profile_incr_usage_stats(pot_profile);
}
else
{ /* Non encap node */
if (PREDICT_FALSE(pot0->reserved_profile_id !=
pot_profile_index || pot_profile == 0))
{
/* New profile announced by encap node. */
new_profile =
pot_profile_find(pot0->reserved_profile_id);
if (PREDICT_FALSE(new_profile == 0 ||
new_profile->valid == 0))
{
ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
return(-1);
}
else
{
pot_profile_index = pot0->reserved_profile_id;
pot_profile = new_profile;
pot_profile_set_active(pot_profile_index);
pot_profile_reset_usage_stats(pot_profile);
}
}
pot_profile_incr_usage_stats(pot_profile);
}
if (pot0->random == 0)
{
pot0->random = clib_host_to_net_u64(pot_generate_random(pot_profile));
pot0->cumulative = 0;
}
random = clib_net_to_host_u64(pot0->random);
cumulative = clib_net_to_host_u64(pot0->cumulative);
pot0->cumulative = clib_host_to_net_u64(
pot_update_cumulative(pot_profile,
cumulative,
random));
ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROCESSED, 1);
return (rv);
}
int
ip6_hbh_ioam_proof_of_transit_pop_handler (ip6_header_t *ip,
ip6_hop_by_hop_option_t *opt0)
{
ioam_pot_option_t * pot0;
u64 random = 0;
u64 cumulative = 0;
int rv = 0;
pot_profile *pot_profile = 0;
u8 result = 0;
pot0 = (ioam_pot_option_t *) opt0;
random = clib_net_to_host_u64(pot0->random);
cumulative = clib_net_to_host_u64(pot0->cumulative);
pot_profile = pot_profile_get_active();
result = pot_validate (pot_profile,
cumulative, random);
if (result == 1)
{
ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1);
}
else
{
ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1);
}
return (rv);
}
int ip6_hop_by_hop_ioam_pot_rewrite_handler (u8 *rewrite_string, u8 rewrite_size)
{
ioam_pot_option_t * pot_option;
if (rewrite_string && rewrite_size == sizeof(ioam_pot_option_t))
{
pot_option = (ioam_pot_option_t *)rewrite_string;
pot_option->hdr.type = HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
| HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
pot_option->hdr.length = sizeof (ioam_pot_option_t) -
sizeof (ip6_hop_by_hop_option_t);
return(0);
}
return(-1);
}
static clib_error_t *
ip6_show_ioam_pot_cmd_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
u8 *s = 0;
int i = 0;
for ( i = 0; i < IP6_IOAM_POT_N_STATS; i++)
{
s = format(s, " %s - %lu\n", ip6_hop_by_hop_ioam_pot_stats_strings[i],
hm->counters[i]);
}
vlib_cli_output(vm, "%v", s);
vec_free(s);
return 0;
}
VLIB_CLI_COMMAND (ip6_show_ioam_pot_cmd, static) = {
.path = "show ioam pot",
.short_help = "iOAM pot statistics",
.function = ip6_show_ioam_pot_cmd_fn,
};
static clib_error_t *
ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm)
{
ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main;
clib_error_t * error;
if ((error = vlib_call_init_function (vm, ip_main_init)))
return(error);
if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
return error;
if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init)))
return(error);
hm->vlib_main = vm;
hm->vnet_main = vnet_get_main();
memset(hm->counters, 0, sizeof(hm->counters));
if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_hbh_ioam_proof_of_transit_handler,
ip6_hbh_ioam_proof_of_transit_trace_handler) < 0)
return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT failed"));
if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
sizeof(ioam_pot_option_t),
ip6_hop_by_hop_ioam_pot_rewrite_handler) < 0)
return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT for rewrite failed"));
if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
ip6_hbh_ioam_proof_of_transit_pop_handler) < 0)
return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT POP failed"));
return (0);
}
VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_pot_init);

View File

@ -8,7 +8,7 @@
* Hence this header to combine add/multiply followed by modulo of u64 integrers
* always resulting in u64.
*
* Copyright (c) 2015 Cisco and/or its affiliates.
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:

View File

@ -0,0 +1,97 @@
/* Hey Emacs use -*- mode: C -*- */
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \brief Proof of Transit(POT): Set POT profile
@param id - id of the profile
@param validator - True/False to indicate if this is verifier
@param secret_key - Verification key
@param secret_share - Share of the 1st polynomial
@param prime - Prime number used for modulo operation
@param max_bits - Max bits to be used for Random number generation
@param lpc - Lagrange basis polynomial
@param polynomial_public - pre-evaluated public polynomial
@param list_name_len - length of the name of this profile list
@param list_name - name of this profile list
*/
define pot_profile_add {
u32 client_index;
u32 context;
u8 id;
u8 validator;
u64 secret_key;
u64 secret_share;
u64 prime;
u8 max_bits;
u64 lpc;
u64 polynomial_public;
u8 list_name_len;
u8 list_name[0];
};
/** \brief Proof of Transit profile add / del response
@param context - sender context, to match reply w/ request
@param retval - return value for request
*/
define pot_profile_add_reply {
u32 context;
i32 retval;
};
/** \brief Proof of Transit(POT): Activate POT profile in the list
@param id - id of the profile
@param list_name_len - length of the name of this profile list
@param list_name - name of this profile list
*/
define pot_profile_activate {
u32 client_index;
u32 context;
u8 id;
u8 list_name_len;
u8 list_name[0];
};
/** \brief Proof of Transit profile activate response
@param context - sender context, to match reply w/ request
@param retval - return value for request
*/
define pot_profile_activate_reply {
u32 context;
i32 retval;
};
/** \brief Delete POT Profile
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param list_name_len - length of the name of the profile list
@param list_name - name of profile list to delete
*/
define pot_profile_del {
u32 client_index;
u32 context;
u8 list_name_len;
u8 list_name[0];
};
/** \brief Proof of Transit profile add / del response
@param context - sender context, to match reply w/ request
@param retval - return value for request
*/
define pot_profile_del_reply {
u32 context;
i32 retval;
};

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Include the generated file, see BUILT_SOURCES in Makefile.am */
#include <lib-pot/pot.api.h>

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*------------------------------------------------------------------
* pot_api.c - Proof of Transit related APIs to create
* and maintain profiles
*------------------------------------------------------------------
*/
#include <vnet/vnet.h>
#include <vnet/plugin/plugin.h>
#include <lib-pot/pot_util.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vlibsocket/api.h>
/* define message IDs */
#include <lib-pot/pot_msg_enum.h>
/* define message structures */
#define vl_typedefs
#include <lib-pot/pot_all_api_h.h>
#undef vl_typedefs
/* define generated endian-swappers */
#define vl_endianfun
#include <lib-pot/pot_all_api_h.h>
#undef vl_endianfun
/* instantiate all the print functions we know about */
#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
#define vl_printfun
#include <lib-pot/pot_all_api_h.h>
#undef vl_printfun
/* Get the API version number */
#define vl_api_version(n,v) static u32 api_version=(v);
#include <lib-pot/pot_all_api_h.h>
#undef vl_api_version
/*
* A handy macro to set up a message reply.
* Assumes that the following variables are available:
* mp - pointer to request message
* rmp - pointer to reply message type
* rv - return value
*/
#define REPLY_MACRO(t) \
do { \
unix_shared_memory_queue_t * q = \
vl_api_client_index_to_input_queue (mp->client_index); \
if (!q) \
return; \
\
rmp = vl_msg_api_alloc (sizeof (*rmp)); \
rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base); \
rmp->context = mp->context; \
rmp->retval = ntohl(rv); \
\
vl_msg_api_send_shmem (q, (u8 *)&rmp); \
} while(0);
#define REPLY_MACRO2(t, body) \
do { \
unix_shared_memory_queue_t * q; \
rv = vl_msg_api_pd_handler (mp, rv); \
q = vl_api_client_index_to_input_queue (mp->client_index); \
if (!q) \
return; \
\
rmp = vl_msg_api_alloc (sizeof (*rmp)); \
rmp->_vl_msg_id = ntohs((t)); \
rmp->context = mp->context; \
rmp->retval = ntohl(rv); \
do {body;} while (0); \
vl_msg_api_send_shmem (q, (u8 *)&rmp); \
} while(0);
/* List of message types that this plugin understands */
#define foreach_pot_plugin_api_msg \
_(POT_PROFILE_ADD, pot_profile_add) \
_(POT_PROFILE_ACTIVATE, pot_profile_activate) \
_(POT_PROFILE_DEL, pot_profile_del) \
static void vl_api_pot_profile_add_t_handler
(vl_api_pot_profile_add_t *mp)
{
pot_main_t * sm = &pot_main;
int rv = 0;
vl_api_pot_profile_add_reply_t * rmp;
u8 id;
pot_profile *profile = NULL;
u8 *name = 0;
if (mp->list_name_len)
name = format(0, "%s", mp->list_name);
pot_profile_list_init(name);
id = mp->id;
profile = pot_profile_find(id);
if (profile) {
rv = pot_profile_create(profile,
clib_net_to_host_u64(mp->prime),
clib_net_to_host_u64(mp->polynomial_public),
clib_net_to_host_u64(mp->lpc),
clib_net_to_host_u64(mp->secret_share));
if (rv != 0)
goto ERROROUT;
if (1 == mp->validator)
(void)pot_set_validator(profile, clib_net_to_host_u64(mp->secret_key));
(void)pot_profile_set_bit_mask(profile, mp->max_bits);
} else {
rv = -3;
}
ERROROUT:
vec_free(name);
REPLY_MACRO(VL_API_POT_PROFILE_ADD_REPLY);
}
static void vl_api_pot_profile_activate_t_handler
(vl_api_pot_profile_activate_t *mp)
{
pot_main_t * sm = &pot_main;
int rv = 0;
vl_api_pot_profile_add_reply_t * rmp;
u8 id;
u8 *name = NULL;
if (mp->list_name_len)
name = format(0, "%s", mp->list_name);
if (!pot_profile_list_is_enabled(name)) {
rv = -1;
} else {
id = mp->id;
rv = pot_profile_set_active(id);
}
vec_free(name);
REPLY_MACRO(VL_API_POT_PROFILE_ACTIVATE_REPLY);
}
static void vl_api_pot_profile_del_t_handler
(vl_api_pot_profile_del_t *mp)
{
pot_main_t * sm = &pot_main;
int rv = 0;
vl_api_pot_profile_del_reply_t * rmp;
clear_pot_profiles();
REPLY_MACRO(VL_API_POT_PROFILE_DEL_REPLY);
}
/*
* This routine exists to convince the vlib plugin framework that
* we haven't accidentally copied a random .dll into the plugin directory.
*
* Also collects global variable pointers passed from the vpp engine
*/
clib_error_t *
vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
int from_early_init)
{
pot_main_t * sm = &pot_main;
clib_error_t * error = 0;
sm->vlib_main = vm;
sm->vnet_main = h->vnet_main;
return error;
}
/* Set up the API message handling tables */
static clib_error_t *
pot_plugin_api_hookup (vlib_main_t *vm)
{
pot_main_t * sm = &pot_main;
#define _(N,n) \
vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \
#n, \
vl_api_##n##_t_handler, \
vl_noop_handler, \
vl_api_##n##_t_endian, \
vl_api_##n##_t_print, \
sizeof(vl_api_##n##_t), 1);
foreach_pot_plugin_api_msg;
#undef _
return 0;
}
static clib_error_t * pot_init (vlib_main_t * vm)
{
pot_main_t * sm = &pot_main;
clib_error_t * error = 0;
u8 * name;
bzero(sm, sizeof(pot_main));
(void)pot_util_init();
name = format (0, "pot_%08x%c", api_version, 0);
/* Ask for a correctly-sized block of API message decode slots */
sm->msg_id_base = vl_msg_api_get_msg_ids
((char *) name, VL_MSG_FIRST_AVAILABLE);
error = pot_plugin_api_hookup (vm);
vec_free(name);
return error;
}
VLIB_INIT_FUNCTION (pot_init);

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef included_pot_msg_enum_h
#define included_pot_msg_enum_h
#include <vppinfra/byte_order.h>
#define vl_msg_id(n,h) n,
typedef enum {
#include <lib-pot/pot_all_api_h.h>
/* We'll want to know how many messages IDs we need... */
VL_MSG_FIRST_AVAILABLE,
} vl_msg_id_t;
#undef vl_msg_id
#endif /* included_pot_msg_enum_h */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,195 @@
/*
* pot_util.h -- Proof Of Transit Utility Header
*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef include_vnet_pot_util_h
#define include_vnet_pot_util_h
#include <vnet/ip/ip6_hop_by_hop.h>
#define debug_ioam debug_ioam_fn
/* Dont change this size 256. This is there across multiple components */
#define PATH_NAME_SIZE 256
/* Ring size. this should be same as the one in ODL. Do not change this
without change in ODL. */
#define MAX_POT_PROFILES 2
/**
* Usage:
*
* On any node that participates in Proof of Transit:
*
* Step 1: Initialize this library by calling pot_init()
* Step 2: Setup a proof of transit profile that contains all the parameters needed to compute cumulative:
* Call these functions:
* pot_profile_find
* pot_profile_create
* pot_profile_set_bit_mask - To setup how large we want the numbers used in the computation and random number <= 64 bits
* Step 2a: For validator do this:
* pot_set_validator
* Step 2b: On initial node enable the profile to be used:
* pot_profile_set_active / pot_profile_get_active will return the profile
* Step 3a: At the initial node to generate Random number that will be read by all other nodes:
* pot_generate_random
* Step 3b: At all nodes including initial and verifier call this to compute cumulative:
* pot_update_cumulative
* Step 4: At the verifier:
* pot_validate
*
*/
typedef struct pot_profile_
{
u8 id : 1;
u8 valid : 1;
u8 in_use : 1;
u64 random;
u8 validator;
u64 secret_key;
u64 secret_share;
u64 prime;
u64 lpc;
u64 poly_pre_eval;
u64 bit_mask;
u64 limit;
double primeinv;
u64 total_pkts_using_this_profile;
} pot_profile;
typedef struct {
/* Name of the default profile list in use*/
u8 *profile_list_name;
pot_profile profile_list[MAX_POT_PROFILES];
/* number of profiles in the list */
u8 active_profile_id : 1;
/* API message ID base */
u16 msg_id_base;
/* convenience */
vlib_main_t * vlib_main;
vnet_main_t * vnet_main;
} pot_main_t;
extern pot_main_t pot_main;
/*
* Initialize proof of transit
*/
int pot_util_init(void);
void pot_profile_list_init(u8 * name);
/*
* Find a pot profile by ID
*/
pot_profile *pot_profile_find(u8 id);
static inline u16 pot_profile_get_id(pot_profile * profile)
{
if (profile)
{
return (profile->id);
}
return (0);
}
/* setup and clean up profile */
int pot_profile_create(pot_profile * profile, u64 prime,
u64 poly2, u64 lpc, u64 secret_share);
/*
* Setup profile as a validator
*/
int pot_set_validator(pot_profile * profile, u64 key);
/*
* Setup max bits to be used for random number generation
*/
#define MAX_BITS 64
int pot_profile_set_bit_mask(pot_profile * profile, u16 bits);
/*
* Given a random and cumulative compute the new cumulative for a given profile
*/
u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random);
/*
* return True if the cumulative matches secret from a profile
*/
u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random);
/*
* Utility function to get random number per pack
*/
u64 pot_generate_random(pot_profile * profile);
extern void clear_pot_profiles();
extern int pot_profile_list_is_enabled(u8 *name);
static inline u8 pot_is_decap(pot_profile * p)
{
return (p->validator == 1);
}
static inline int pot_profile_set_active (u8 id)
{
pot_main_t *sm = &pot_main;
pot_profile *profile = NULL;
pot_profile *current_active_prof = NULL;
current_active_prof = pot_profile_find(sm->active_profile_id);
profile = pot_profile_find(id);
if (profile && profile->valid) {
sm->active_profile_id = id;
current_active_prof->in_use = 0;
profile->in_use = 1;
return(0);
}
return(-1);
}
static inline u8 pot_profile_get_active_id (void)
{
pot_main_t *sm = &pot_main;
return (sm->active_profile_id);
}
static inline pot_profile * pot_profile_get_active (void)
{
pot_main_t *sm = &pot_main;
pot_profile *profile = NULL;
profile = pot_profile_find(sm->active_profile_id);
if (profile && profile->in_use)
return(profile);
return (NULL);
}
static inline void pot_profile_reset_usage_stats (pot_profile *pow)
{
if (pow) {
pow->total_pkts_using_this_profile = 0;
}
}
static inline void pot_profile_incr_usage_stats (pot_profile *pow)
{
if (pow) {
pow->total_pkts_using_this_profile++;
}
}
#endif

View File

@ -717,16 +717,6 @@ libvnetplugin_la_SOURCES += \
nobase_include_HEADERS += \
vnet/plugin/plugin.h
########################################
# Service Chain verification util
########################################
libvnet_la_SOURCES += \
vnet/lib-scv/scv_util.c
nobase_include_HEADERS += \
vnet/lib-scv/scv_util.h \
vnet/lib-scv/math64.h
lib_LTLIBRARIES = libvnet.la libvnetplugin.la
dpdk_libs =

File diff suppressed because it is too large Load Diff

View File

@ -45,8 +45,8 @@ typedef struct {
u32 node_id;
u32 app_data;
/* PoW option */
u8 has_pow_option;
/* Pot option */
u8 has_pot_option;
#define PPC_NONE 0
#define PPC_ENCAP 1
@ -60,6 +60,11 @@ typedef struct {
/* Time stamp precision. This is enumerated to above four options */
u32 trace_tsp;
/* Array of function pointers to ADD and POP HBH option handling routines */
u8 options_size[256];
int (*add_options[256])(u8 *rewrite_string, u8 rewrite_size);
int (*pop_options[256])(ip6_header_t *ip, ip6_hop_by_hop_option_t *opt);
/* convenience */
vlib_main_t * vlib_main;
vnet_main_t * vnet_main;
@ -70,7 +75,7 @@ extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main;
extern u8 * format_path_map(u8 * s, va_list * args);
extern clib_error_t *
ip6_ioam_trace_profile_set(u32 trace_option_elts, u32 trace_type, u32 node_id,
u32 app_data, int has_pow_option, u32 trace_tsp,
u32 app_data, int has_pot_option, u32 trace_tsp,
int has_e2e_option);
extern int ip6_ioam_set_destination (ip6_address_t *addr, u32 mask_width,
u32 vrf_id, int is_add, int is_pop, int is_none);
@ -103,5 +108,14 @@ static inline u8 is_zero_ip6_address (ip6_address_t *a)
return ((a->as_u64[0] == 0) && (a->as_u64[1] == 0));
}
extern ip6_hop_by_hop_ioam_main_t * hm;
int ip6_hbh_add_register_option (u8 option,
u8 size,
int rewrite_options(u8 *rewrite_string, u8 size));
int ip6_hbh_add_unregister_option (u8 option);
int ip6_hbh_pop_register_option (u8 option,
int options(ip6_header_t *ip, ip6_hop_by_hop_option_t *opt));
int ip6_hbh_pop_unregister_option (u8 option);
#endif /* __included_ip6_hop_by_hop_ioam_h__ */

View File

@ -40,7 +40,7 @@ typedef struct {
/* $$$$ IANA banana constants */
#define HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST 59 /* Third highest bit set (change en-route) */
#define HBH_OPTION_TYPE_IOAM_PROOF_OF_WORK 60 /* Third highest bit set (change en-route) */
#define HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT 60 /* Third highest bit set (change en-route) */
#define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE 29
/*
@ -171,14 +171,6 @@ typedef CLIB_PACKED(struct {
u32 elts[0]; /* Variable type. So keep it generic */
}) ioam_trace_option_t;
typedef CLIB_PACKED(struct {
ip6_hop_by_hop_option_t hdr;
u8 pow_type;
#define PROFILE_ID_MASK 0xF
u8 reserved_profile_id; /* 4 bits reserved, 4 bits to carry profile id */
u64 random;
u64 cumulative;
}) ioam_pow_option_t;
typedef CLIB_PACKED(struct {
ip6_hop_by_hop_option_t hdr;

File diff suppressed because it is too large Load Diff

View File

@ -1,278 +0,0 @@
/*
* scv_util.h -- Service chain validation/Proof Of Transit Utility Header
*
* Copyright (c) 2015 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef include_vnet_scv_util_h
#define include_vnet_scv_util_h
#include <vnet/ip/ip6_hop_by_hop.h>
#define MAXDEGREE 1024
#define MAXTOKENLEN 128
#define debug_ioam debug_ioam_fn
#define MAX_SERVICE_NODES 10
/* Dont change this size 256. This is there across multiple components */
#define PATH_NAME_SIZE 256
/* Ring size. this should be same as the one in ODL. Do not change this
without change in ODL. */
#define MAX_SERVICE_PROFILES 16
/**
* Usage:
*
* On any [service] node that participates in Service / Path verfication:
*
* Step 1: Initialize this library by calling scv_init()
* Step 2: Setup a Service chain validation profile that contains all the parameters needed to compute cumulative:
* Call these functions:
* scv_profile_find
* scv_profile_create
* scv_profile_set_bit_mask - To setup how large we want the numbers used in the computation and random number <= 64 bits
* Step 2a: For validator do this:
* scv_set_validator
* Step 3a: At the initial Service node to generate Random number that will be read by all other nodes:
* scv_generate_random
* Step 3b: At all service nodes including initial and verifier call this to compute cumulative:
* scv_update_cumulative
* Step 4: At the verifier:
* scv_validate
*
*/
typedef struct scv_profile_
{
u16 id;
u64 random;
u8 validator;
u64 secret_key;
u64 secret_share;
u64 prime;
u64 lpc;
u64 poly_pre_eval;
u64 bit_mask;
u64 limit;
u64 validity;
double primeinv;
// struct hlist_node my_hash_list; when this gets added to hashtbale
} scv_profile;
extern scv_profile *pow_profile;
extern u16 pow_profile_index;
extern u64 total_pkts_using_this_profile;
extern u8 chain_path_name[PATH_NAME_SIZE];
extern u16 invalid_profile_start_index;
extern u8 number_of_invalid_profiles;
extern f64 next_time_to_send;
extern u32 time_exponent;
/*
* Initialize Service chain
*/
void scv_init(u8 * path_name, u8 max, u8 indx);
/*
* Get maximum number of profiles configured for this chain.
*/
u8 scv_get_max_profiles(void);
/*
* Find a SC profile by ID
*/
scv_profile *scv_profile_find(u16 id);
static inline u16 scv_profile_get_id(scv_profile * profile)
{
if (profile)
{
return (profile->id);
}
return (0);
}
/* setup and clean up profile */
void scv_profile_create(scv_profile * profile, u64 prime,
u64 poly2, u64 lpc, u64 secret_share, u64 validity);
/*
* Setup profile as a validator
*/
void scv_set_validator(scv_profile * profile, u64 key);
void scv_profile_cleanup(scv_profile * profile);
/*
* Setup max bits to be used for random number generation
*/
#define MAX_BITS 64
void scv_profile_set_bit_mask(scv_profile * profile, u16 bits);
/*
* Given a random and cumulative compute the new cumulative for a given profile
*/
u64 scv_update_cumulative(scv_profile * profile, u64 cumulative, u64 random);
/*
* return True if the cumulative matches secret from a profile
*/
u8 scv_validate(scv_profile * profile, u64 cumulative, u64 random);
/*
* Utility function to get random number per pack
*/
u64 scv_generate_random(scv_profile * profile);
int scv_profile_to_str(scv_profile * profile, char *buf, int n);
extern void clear_ioam_scv_profiles();
static inline u8 scv_get_profile_in_use(void)
{
return pow_profile_index;
}
static inline
void scv_notification_reset(u16 start_index_recvd, u8 num_profiles_recvd)
{
/* Profiles recevied w/o notn. Nothing to do. */
if (number_of_invalid_profiles == 0)
return;
/* Most likely case. Got all requested profiles */
if (PREDICT_TRUE(num_profiles_recvd == number_of_invalid_profiles &&
start_index_recvd == invalid_profile_start_index))
{
number_of_invalid_profiles = 0;
invalid_profile_start_index = 0;
return;
}
/* Received partial list */
if (num_profiles_recvd < number_of_invalid_profiles)
{
ASSERT(start_index_recvd == invalid_profile_start_index);
invalid_profile_start_index = (start_index_recvd + num_profiles_recvd)
% scv_get_max_profiles();
number_of_invalid_profiles -= num_profiles_recvd;
}
return;
}
int __attribute__ ((weak)) scv_profile_renew(u8 * path_name,
u8 start_index, u8 num_profiles);
int __attribute__ ((weak)) scv_profile_refresh(u8 * path_name,
u8 start_index, u8 num_profiles);
static inline u8 scv_is_decap(scv_profile * p)
{
return (p->validator == 1);
}
static inline u16 scv_get_next_profile_id(vlib_main_t * vm, u16 id)
{
int next_id, num_profiles = 0;
scv_profile *p;
u8 max;
max = scv_get_max_profiles();
next_id = id;
/* Check for new profile in the ring buffer until a valid one. Exclude
checking for the one already in use. */
for (num_profiles = 0; num_profiles < max - 1; num_profiles++)
{
next_id = (next_id + 1) % max;
p = scv_profile_find(next_id);
if (p->validity != 0)
{
vlib_cli_output(vm, "Current id: %d, New id: %d\n", id, next_id);
return (next_id);
}
}
return (id);
}
static inline void
scv_profile_invalidate(vlib_main_t * vm, ip6_hop_by_hop_ioam_main_t * hm,
u16 id, u8 is_encap)
{
scv_profile *p = scv_profile_find(id);
int rc;
u8 max;
f64 now = 0;
p->validity = 0;
/* If there are alredy profiles waiting. If so, use existing start_index.
*/
if (!number_of_invalid_profiles)
invalid_profile_start_index = id;
max = scv_get_max_profiles();
/* Check whether the id is already included in existing list */
if (!(id >= invalid_profile_start_index &&
id <= (invalid_profile_start_index +
number_of_invalid_profiles - 1) % max))
{
number_of_invalid_profiles++;
}
if (number_of_invalid_profiles > scv_get_max_profiles())
number_of_invalid_profiles = scv_get_max_profiles();
now = (f64) (((f64) hm->unix_time_0) +
(vlib_time_now(hm->vlib_main) - hm->vlib_time_0));
if (now <= next_time_to_send)
return;
if (is_encap)
{
rc = scv_profile_renew(chain_path_name,
(u8) invalid_profile_start_index, number_of_invalid_profiles);
if (rc != 0)
vlib_cli_output(vm,
"Renew notification- id start:%d, num %d failed. rc: %d\n",
invalid_profile_start_index, number_of_invalid_profiles, rc);
else
vlib_cli_output(vm,
"Renew notification- id start:%d num %d sent. \n",
invalid_profile_start_index, number_of_invalid_profiles);
}
else
{
/* Non encap node. Send refresh notification for now. Later set a
timer and if there is no profile even after the timeout send
refresh notification. */
rc = scv_profile_refresh(chain_path_name,
(u8) invalid_profile_start_index, number_of_invalid_profiles);
if (rc != 0)
vlib_cli_output(vm,
"Refresh notification- id start:%d, num %d failed. rc: %d\n",
invalid_profile_start_index, number_of_invalid_profiles, rc);
else
vlib_cli_output(vm,
"Refresh notification- id start:%d num %d sent. \n",
invalid_profile_start_index, number_of_invalid_profiles);
}
next_time_to_send = now + time_exponent;
time_exponent <<= 1; /* backoff time is power of 2 seconds */
return;
}
#endif