aboutsummaryrefslogtreecommitdiffstats
path: root/vnet/vnet/ip/ip6_hop_by_hop.c
diff options
context:
space:
mode:
Diffstat (limited to 'vnet/vnet/ip/ip6_hop_by_hop.c')
-rw-r--r--vnet/vnet/ip/ip6_hop_by_hop.c279
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);