diff options
author | AkshayaNadahalli <anadahal@cisco.com> | 2016-08-09 13:38:04 +0530 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2016-11-03 11:44:21 +0000 |
commit | ed4a2fdd4d62c46a2237157cd3a72bda16fceb6a (patch) | |
tree | 1fa59d681435a39f3b7f840b60229f8c3edf4f19 /vnet/vnet/ip/ip6_hop_by_hop.c | |
parent | 273c26a531bf031b3426588041bad67fe7f0a246 (diff) |
Adding Sequence Number - Per Packet Counter(PPC) support for iOAM6.
- Added support in classifier session to identify a flow to be iOAM6 encap/decap
- Sequence number as part of iOAM6 E2E header is created as a plugin.
Change-Id: Ib7605de45aecff25d684d099b525f8dc96ee7038
Signed-off-by: AkshayaNadahalli <anadahal@cisco.com>
Diffstat (limited to 'vnet/vnet/ip/ip6_hop_by_hop.c')
-rw-r--r-- | vnet/vnet/ip/ip6_hop_by_hop.c | 279 |
1 files changed, 234 insertions, 45 deletions
diff --git a/vnet/vnet/ip/ip6_hop_by_hop.c b/vnet/vnet/ip/ip6_hop_by_hop.c index 72490b915e4..e8bc8906335 100644 --- a/vnet/vnet/ip/ip6_hop_by_hop.c +++ b/vnet/vnet/ip/ip6_hop_by_hop.c @@ -1,5 +1,5 @@ /* - * 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: @@ -25,6 +25,7 @@ #include <vnet/ip/ip6_hop_by_hop.h> #include <vnet/fib/ip6_fib.h> +#include <vnet/classify/vnet_classify.h> /** * @file @@ -40,8 +41,6 @@ * in-band OAM can be enabled for IPv6 traffic. */ -char *ppc_state[] = { "None", "Encap", "Decap" }; - ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main; #define foreach_ip6_hbyh_ioam_input_next \ @@ -58,6 +57,68 @@ typedef enum } ip6_hbyh_ioam_input_next_t; +u32 +ioam_flow_add (u8 encap, u8 * flow_name) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + flow_data_t *flow = 0; + u32 index = 0; + u8 i; + + pool_get (hm->flows, flow); + memset (flow, 0, sizeof (flow_data_t)); + + index = flow - hm->flows; + strncpy ((char *) flow->flow_name, (char *) flow_name, 31); + + if (!encap) + IOAM_SET_DECAP (index); + + for (i = 0; i < 255; i++) + { + if (hm->flow_handler[i]) + flow->ctx[i] = hm->flow_handler[i] (index, 1); + } + return (index); +} + +static uword +unformat_opaque_ioam (unformat_input_t * input, va_list * args) +{ + u64 *opaquep = va_arg (*args, u64 *); + u8 *flow_name = NULL; + uword ret = 0; + + if (unformat (input, "ioam-encap %s", &flow_name)) + { + *opaquep = ioam_flow_add (1, flow_name); + ret = 1; + } + else if (unformat (input, "ioam-decap %s", &flow_name)) + { + *opaquep = ioam_flow_add (0, flow_name); + ret = 1; + } + + vec_free (flow_name); + return ret; +} + +u8 * +get_flow_name_from_flow_ctx (u32 flow_ctx) +{ + flow_data_t *flow = NULL; + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + u32 index; + + index = IOAM_MASK_DECAP_BIT (flow_ctx); + + if (pool_is_free_index (hm->flows, index)) + return NULL; + + flow = pool_elt_at_index (hm->flows, index); + return (flow->flow_name); +} /* The main h-b-h tracer will be invoked, no need to do much here */ int @@ -96,6 +157,72 @@ ip6_hbh_add_unregister_option (u8 option) return (0); } +/* Config handler registration */ +int +ip6_hbh_config_handler_register (u8 option, + int config_handler (void *data, u8 disable)) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->config_handler)); + + /* Already registered */ + if (hm->config_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->config_handler[option] = config_handler; + + return (0); +} + +int +ip6_hbh_config_handler_unregister (u8 option) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->config_handler)); + + /* Not registered */ + if (!hm->config_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->config_handler[option] = NULL; + return (0); +} + +/* Flow handler registration */ +int +ip6_hbh_flow_handler_register (u8 option, + u32 ioam_flow_handler (u32 flow_ctx, u8 add)) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->flow_handler)); + + /* Already registered */ + if (hm->flow_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->flow_handler[option] = ioam_flow_handler; + + return (0); +} + +int +ip6_hbh_flow_handler_unregister (u8 option) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->flow_handler)); + + /* Not registered */ + if (!hm->flow_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->flow_handler[option] = NULL; + return (0); +} + typedef struct { u32 next_index; @@ -374,7 +501,8 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip6_add_hop_by_hop_node, int ip6_hbh_pop_register_option (u8 option, - int options (ip6_header_t * ip, + int options (vlib_buffer_t * b, + ip6_header_t * ip, ip6_hop_by_hop_option_t * opt)) { ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; @@ -429,7 +557,8 @@ static char *ip6_pop_hop_by_hop_error_strings[] = { static inline void ioam_pop_hop_by_hop_processing (vlib_main_t * vm, ip6_header_t * ip0, - ip6_hop_by_hop_header_t * hbh0) + ip6_hop_by_hop_header_t * hbh0, + vlib_buffer_t * b) { ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; ip6_hop_by_hop_option_t *opt0, *limit0; @@ -456,7 +585,7 @@ ioam_pop_hop_by_hop_processing (vlib_main_t * vm, default: if (hm->pop_options[type0]) { - if ((*hm->pop_options[type0]) (ip0, opt0) < 0) + if ((*hm->pop_options[type0]) (b, ip0, opt0) < 0) { vlib_node_increment_counter (vm, ip6_pop_hop_by_hop_node.index, @@ -543,8 +672,8 @@ ip6_pop_hop_by_hop_node_fn (vlib_main_t * vm, hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1); hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1); - ioam_pop_hop_by_hop_processing (vm, ip0, hbh0); - ioam_pop_hop_by_hop_processing (vm, ip1, hbh1); + ioam_pop_hop_by_hop_processing (vm, ip0, hbh0, b0); + ioam_pop_hop_by_hop_processing (vm, ip1, hbh1, b1); vlib_buffer_advance (b0, (hbh0->length + 1) << 3); vlib_buffer_advance (b1, (hbh1->length + 1) << 3); @@ -632,7 +761,7 @@ ip6_pop_hop_by_hop_node_fn (vlib_main_t * vm, hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1); /* TODO:Temporarily doing it here.. do this validation in end_of_path_cb */ - ioam_pop_hop_by_hop_processing (vm, ip0, hbh0); + ioam_pop_hop_by_hop_processing (vm, ip0, hbh0, b0); /* Pop the trace data */ vlib_buffer_advance (b0, (hbh0->length + 1) << 3); new_l0 = clib_net_to_host_u16 (ip0->payload_length) - @@ -690,8 +819,15 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip6_pop_hop_by_hop_node, ip6_pop_hop_by_hop_node_fn) static clib_error_t *ip6_hop_by_hop_ioam_init (vlib_main_t * vm) { + clib_error_t *error; ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + if ((error = vlib_call_init_function (vm, ip_main_init))) + return (error); + + if ((error = vlib_call_init_function (vm, ip6_lookup_init))) + return error; + hm->vlib_main = vm; hm->vnet_main = vnet_get_main (); hm->unix_time_0 = (u32) time (0); /* Store starting time */ @@ -701,6 +837,8 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip6_pop_hop_by_hop_node, memset (hm->pop_options, 0, sizeof (hm->pop_options)); memset (hm->options_size, 0, sizeof (hm->options_size)); + vnet_classify_register_unformat_opaque_index_fn (unformat_opaque_ioam); + return (0); } @@ -708,15 +846,15 @@ VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_init); int ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, - int has_pot_option, int has_ppc_option) + int has_pot_option, int has_seqno_option) { ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; - u8 *rewrite = 0; + u8 *rewrite = NULL; u32 size, rnd_size; ip6_hop_by_hop_header_t *hbh; u8 *current; - u8 trace_data_size = 0; - u8 pot_data_size = 0; + u8 *trace_data_size = NULL; + u8 *pot_data_size = NULL; vec_free (*rwp); @@ -730,16 +868,19 @@ ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, if (has_trace_option && hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] != 0) { - size += sizeof (ip6_hop_by_hop_option_t); size += hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; } if (has_pot_option && hm->add_options[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) { - size += sizeof (ip6_hop_by_hop_option_t); size += hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; } + if (has_seqno_option) + { + size += hm->options_size[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]; + } + /* Round to a multiple of 8 octets */ rnd_size = (size + 7) & ~7; @@ -757,22 +898,32 @@ ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, if (0 != (hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST])) { trace_data_size = - hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; + &hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] (current, - &trace_data_size)) - current += hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; + trace_data_size)) + current += *trace_data_size; } } if (has_pot_option && hm->add_options[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) { - pot_data_size = hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; + pot_data_size = + &hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] (current, - &pot_data_size)) - current += - sizeof (hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]); + pot_data_size)) + current += *pot_data_size; + } + + if (has_seqno_option && + (hm->add_options[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] != 0)) + { + if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] (current, + & + (hm->options_size + [HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]))) + current += hm->options_size[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]; } *rwp = rewrite; @@ -788,7 +939,20 @@ clear_ioam_rewrite_fn (void) hm->rewrite = 0; hm->has_trace_option = 0; hm->has_pot_option = 0; - hm->has_ppc_option = 0; + hm->has_seqno_option = 0; + hm->has_analyse_option = 0; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] (NULL, 1); + + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] (NULL, 1); + + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]) + { + hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] ((void *) + &hm->has_analyse_option, + 1); + } return 0; } @@ -819,19 +983,43 @@ VLIB_CLI_COMMAND (ip6_clear_ioam_rewrite_cmd, static) = { /* *INDENT-ON* */ clib_error_t * -ip6_ioam_enable (int has_trace_option, int has_pot_option, int has_ppc_option) +ip6_ioam_enable (int has_trace_option, int has_pot_option, + int has_seqno_option, int has_analyse_option) { int rv; ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; rv = ip6_ioam_set_rewrite (&hm->rewrite, has_trace_option, - has_pot_option, has_ppc_option); + has_pot_option, has_seqno_option); switch (rv) { case 0: - hm->has_trace_option = has_trace_option; - hm->has_pot_option = has_pot_option; - hm->has_ppc_option = has_ppc_option; + if (has_trace_option) + { + hm->has_trace_option = has_trace_option; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] (NULL, + 0); + } + + if (has_pot_option) + { + hm->has_pot_option = has_pot_option; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] (NULL, + 0); + } + hm->has_analyse_option = has_analyse_option; + if (has_seqno_option) + { + hm->has_seqno_option = has_seqno_option; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]) + { + hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] ((void *) + &has_analyse_option, + 0); + } + } break; default: @@ -850,7 +1038,8 @@ ip6_set_ioam_rewrite_command_fn (vlib_main_t * vm, { int has_trace_option = 0; int has_pot_option = 0; - int has_ppc_option = 0; + int has_seqno_option = 0; + int has_analyse_option = 0; clib_error_t *rv = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -859,18 +1048,17 @@ ip6_set_ioam_rewrite_command_fn (vlib_main_t * vm, has_trace_option = 1; else if (unformat (input, "pot")) has_pot_option = 1; - else if (unformat (input, "ppc encap")) - has_ppc_option = PPC_ENCAP; - else if (unformat (input, "ppc decap")) - has_ppc_option = PPC_DECAP; - else if (unformat (input, "ppc none")) - has_ppc_option = PPC_NONE; + else if (unformat (input, "seqno")) + has_seqno_option = 1; + else if (unformat (input, "analyse")) + has_analyse_option = 1; else break; } - rv = ip6_ioam_enable (has_trace_option, has_pot_option, has_ppc_option); + rv = ip6_ioam_enable (has_trace_option, has_pot_option, + has_seqno_option, has_analyse_option); return rv; } @@ -896,7 +1084,7 @@ ip6_set_ioam_rewrite_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (ip6_set_ioam_rewrite_cmd, static) = { .path = "set ioam rewrite", - .short_help = "set ioam rewrite [trace] [pot] [ppc <encap|decap|none>]", + .short_help = "set ioam [trace] [pot] [seqno] [analyse]", .function = ip6_set_ioam_rewrite_command_fn, }; /* *INDENT-ON* */ @@ -945,14 +1133,15 @@ ip6_show_ioam_summary_cmd_fn (vlib_main_t * vm, format (s, "Try 'show ioam pot and show pot profile' for more information\n"); - s = format (s, " EDGE TO EDGE - PPC OPTION - %d (%s)\n", - hm->has_ppc_option, ppc_state[hm->has_ppc_option]); -#if 0 - /* 'show ioam ppc' command does not exist. Not sure if it was removed */ - /* or yet to be added. Comment out for now. */ - if (hm->has_ppc_option) - s = format (s, "Try 'show ioam ppc' for more information\n"); -#endif + s = format (s, " EDGE TO EDGE - SeqNo OPTION - %d (%s)\n", + hm->has_seqno_option, + hm->has_seqno_option ? "Enabled" : "Disabled"); + if (hm->has_seqno_option) + s = format (s, "Try 'show ioam e2e' for more information\n"); + + s = format (s, " iOAM Analyse OPTION - %d (%s)\n", + hm->has_analyse_option, + hm->has_analyse_option ? "Enabled" : "Disabled"); vlib_cli_output (vm, "%v", s); vec_free (s); |