aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkshayaNadahalli <anadahal@cisco.com>2016-08-09 13:38:04 +0530
committerDave Barach <openvpp@barachs.net>2016-11-03 11:44:21 +0000
commited4a2fdd4d62c46a2237157cd3a72bda16fceb6a (patch)
tree1fa59d681435a39f3b7f840b60229f8c3edf4f19
parent273c26a531bf031b3426588041bad67fe7f0a246 (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>
-rw-r--r--plugins/ioam-plugin/Makefile.am13
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c232
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h47
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c8
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c109
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h70
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c141
-rw-r--r--plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c3
-rw-r--r--plugins/ioam-plugin/ioam/lib-trace/trace_util.c5
-rw-r--r--vnet/vnet/buffer.h2
-rw-r--r--vnet/vnet/ip/ip6.h4
-rw-r--r--vnet/vnet/ip/ip6_forward.c12
-rw-r--r--vnet/vnet/ip/ip6_hop_by_hop.c279
-rw-r--r--vnet/vnet/ip/ip6_hop_by_hop.h102
-rw-r--r--vpp-api-test/vat/api_format.c24
-rw-r--r--vpp/vpp-api/api.c3
-rw-r--r--vpp/vpp-api/custom_dump.c40
-rw-r--r--vpp/vpp-api/vpe.api8
18 files changed, 1006 insertions, 96 deletions
diff --git a/plugins/ioam-plugin/Makefile.am b/plugins/ioam-plugin/Makefile.am
index 853ac6d37d1..3f1edb10910 100644
--- a/plugins/ioam-plugin/Makefile.am
+++ b/plugins/ioam-plugin/Makefile.am
@@ -115,7 +115,20 @@ ioam_trace_test_plugin_la_SOURCES = \
vppapitestplugins_LTLIBRARIES += ioam_trace_test_plugin.la
vppplugins_LTLIBRARIES += ioam_trace_plugin.la
+########################################
+# iOAM E2E plugin
+########################################
+
+ioam_e2e_plugin_la_SOURCES = \
+ ioam/encap/ip6_ioam_e2e.c \
+ ioam/encap/ip6_ioam_seqno.c \
+ ioam/encap/ip6_ioam_seqno_analyse.c
+
+noinst_HEADERS += \
+ ioam/encap/ip6_ioam_e2e.h \
+ ioam/encap/ip6_ioam_seqno.h
+vppplugins_LTLIBRARIES += ioam_e2e_plugin.la
# Remove *.la files
install-data-hook:
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c
new file mode 100644
index 00000000000..0839cdceca7
--- /dev/null
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c
@@ -0,0 +1,232 @@
+/*
+ * 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/ip.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+#include <vnet/ip/ip6_hop_by_hop.h>
+#include <vnet/plugin/plugin.h>
+
+#include "ip6_ioam_e2e.h"
+
+ioam_e2e_main_t ioam_e2e_main;
+
+static u8 * ioam_e2e_trace_handler (u8 * s,
+ ip6_hop_by_hop_option_t *opt)
+{
+ ioam_e2e_option_t * e2e = (ioam_e2e_option_t *)opt;
+ u32 seqno = 0;
+
+ if (e2e)
+ {
+ seqno = clib_net_to_host_u32 (e2e->e2e_data);
+ }
+
+ s = format (s, "SeqNo = 0x%Lx", seqno);
+ return s;
+}
+
+int
+ioam_e2e_config_handler (void *data, u8 disable)
+{
+ int *analyse = data;
+
+ /* Register hanlders if enabled */
+ if (!disable)
+ {
+ /* If encap node register for encap handler */
+ if (0 == *analyse)
+ {
+ if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
+ ioam_seqno_encap_handler,
+ ioam_e2e_trace_handler) < 0)
+ {
+ return (-1);
+ }
+ }
+ /* If analyze node then register for decap handler */
+ else
+ {
+ if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
+ ioam_seqno_decap_handler) < 0)
+ {
+ return (-1);
+ }
+ }
+ return 0;
+ }
+
+ /* UnRegister handlers */
+ (void) ip6_hbh_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE);
+ (void) ip6_hbh_pop_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE);
+ return 0;
+}
+
+int
+ioam_e2e_rewrite_handler (u8 *rewrite_string,
+ u8 *rewrite_size)
+{
+ ioam_e2e_option_t *e2e_option;
+
+ if (rewrite_string && *rewrite_size == sizeof(ioam_e2e_option_t))
+ {
+ e2e_option = (ioam_e2e_option_t *)rewrite_string;
+ e2e_option->hdr.type = HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE
+ | HBH_OPTION_TYPE_SKIP_UNKNOWN;
+ e2e_option->hdr.length = sizeof (ioam_e2e_option_t) -
+ sizeof (ip6_hop_by_hop_option_t);
+ return(0);
+ }
+ return(-1);
+}
+
+u32
+ioam_e2e_flow_handler (u32 ctx, u8 add)
+{
+ ioam_e2e_data_t *data;
+ u16 i;
+
+ if (add)
+ {
+ pool_get(ioam_e2e_main.e2e_data, data);
+ data->flow_ctx = ctx;
+ ioam_seqno_init_bitmap(&data->seqno_data);
+ return ((u32) (data - ioam_e2e_main.e2e_data));
+ }
+
+ /* Delete case */
+ for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++)
+ {
+ if (pool_is_free_index(ioam_e2e_main.e2e_data, i))
+ continue;
+
+ data = pool_elt_at_index(ioam_e2e_main.e2e_data, i);
+ if (data && (data->flow_ctx == ctx))
+ {
+ pool_put_index(ioam_e2e_main.e2e_data, i);
+ return (0);
+ }
+ }
+ return 0;
+}
+
+static clib_error_t *
+ioam_show_e2e_cmd_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ ioam_e2e_data_t *e2e_data;
+ u8 *s = 0;
+ int i;
+
+ vec_reset_length(s);
+
+ s = format(0, "IOAM E2E information: \n");
+ for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++)
+ {
+ if (pool_is_free_index(ioam_e2e_main.e2e_data, i))
+ continue;
+
+ e2e_data = pool_elt_at_index(ioam_e2e_main.e2e_data, i);
+ s = format(s, "Flow name: %s\n", get_flow_name_from_flow_ctx(e2e_data->flow_ctx));
+
+ s = show_ioam_seqno_cmd_fn(s,
+ &e2e_data->seqno_data,
+ !IOAM_DEAP_ENABLED(e2e_data->flow_ctx));
+ }
+
+ vlib_cli_output(vm, "%v", s);
+ return 0;
+}
+
+
+VLIB_CLI_COMMAND (ioam_show_e2e_cmd, static) = {
+ .path = "show ioam e2e ",
+ .short_help = "show ioam e2e information",
+ .function = ioam_show_e2e_cmd_fn,
+};
+
+/*
+ * 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)
+{
+ clib_error_t * error = 0;
+
+ ioam_e2e_main.vlib_main = vm;
+ ioam_e2e_main.vnet_main = h->vnet_main;
+ return error;
+}
+
+/*
+ * Init handler E2E headet handling.
+ * Init hanlder registers encap, decap, trace and Rewrite handlers.
+ */
+static clib_error_t *
+ioam_e2e_init (vlib_main_t * vm)
+{
+ clib_error_t * error;
+
+ if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init)))
+ {
+ return(error);
+ }
+
+ /*
+ * As of now we have only PPC under E2E header.
+ */
+ if (ip6_hbh_config_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
+ ioam_e2e_config_handler) < 0)
+ {
+ return (clib_error_create("Registration of "
+ "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed"));
+ }
+
+ if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
+ sizeof(ioam_e2e_option_t),
+ ioam_e2e_rewrite_handler) < 0)
+ {
+ return (clib_error_create("Registration of "
+ "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed"));
+ }
+
+ if (ip6_hbh_flow_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
+ ioam_e2e_flow_handler) < 0)
+ {
+ return (clib_error_create("Registration of "
+ "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE Flow handler failed"));
+ }
+
+ return (0);
+}
+
+/*
+ * Init function for the E2E lib.
+ * ip6_hop_by_hop_ioam_e2e_init gets called during init.
+ */
+VLIB_INIT_FUNCTION (ioam_e2e_init);
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h
new file mode 100644
index 00000000000..18f35f80c60
--- /dev/null
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h
@@ -0,0 +1,47 @@
+/*
+ * 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_ip6_ioam_e2e_h__
+#define __included_ip6_ioam_e2e_h__
+
+#include "ip6_ioam_seqno.h"
+
+typedef struct ioam_e2e_data_t_ {
+ u32 flow_ctx;
+ u32 pad;
+ ioam_seqno_data seqno_data;
+} ioam_e2e_data_t;
+
+typedef struct {
+ ioam_e2e_data_t *e2e_data;
+ vlib_main_t *vlib_main;
+ vnet_main_t *vnet_main;
+} ioam_e2e_main_t;
+
+extern ioam_e2e_main_t ioam_e2e_main;
+
+static inline ioam_seqno_data *
+ioam_e2ec_get_seqno_data_from_flow_ctx (u32 flow_ctx)
+{
+ ioam_e2e_data_t *data = NULL;
+ u32 index;
+
+ index = get_flow_data_from_flow_ctx(flow_ctx,
+ HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE);
+ data = &ioam_e2e_main.e2e_data[index];
+ return &(data->seqno_data);
+}
+
+#endif /* __included_ioam_e2e_h__ */
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c
index 9daea9c058f..05f42c91d0f 100644
--- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c
@@ -171,7 +171,7 @@ ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b,
}
int
-ip6_hbh_ioam_proof_of_transit_pop_handler (ip6_header_t *ip,
+ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip,
ip6_hop_by_hop_option_t *opt0)
{
ioam_pot_option_t * pot0;
@@ -248,12 +248,6 @@ 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);
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c
new file mode 100644
index 00000000000..0b4d4192975
--- /dev/null
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c
@@ -0,0 +1,109 @@
+/*
+ * 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/ip.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+#include "ip6_ioam_seqno.h"
+#include "ip6_ioam_e2e.h"
+
+ioam_seqno_data_main_t ioam_seqno_main;
+
+void ioam_seqno_init_bitmap (ioam_seqno_data *data)
+{
+ seqno_bitmap *bitmap = &data->seqno_rx.bitmap;
+ bitmap->window_size = SEQNO_WINDOW_SIZE;
+ bitmap->array_size = SEQNO_WINDOW_ARRAY_SIZE;
+ bitmap->mask = 32 * SEQNO_WINDOW_ARRAY_SIZE - 1;
+ bitmap->array[0] = 0x00000000;/* pretend we haven seen sequence numbers 0*/
+ bitmap->highest = 0;
+
+ data->seq_num = 0;
+ return ;
+}
+
+/*
+ * This Routine gets called from IPv6 hop-by-hop option handling.
+ * Only if we are encap node, then add PPC data.
+ * On a Transit(MID) node we dont do anything with E2E headers.
+ * On decap node decap is handled by seperate function.
+ */
+int
+ioam_seqno_encap_handler (vlib_buffer_t *b, ip6_header_t *ip,
+ ip6_hop_by_hop_option_t *opt)
+{
+ u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index;
+ ioam_e2e_option_t * e2e;
+ int rv = 0;
+ ioam_seqno_data *data;
+
+ data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index);
+ e2e = (ioam_e2e_option_t *) opt;
+ e2e->e2e_data = clib_host_to_net_u32(++data->seq_num);
+
+ return (rv);
+}
+
+/*
+ * This Routine gets called on POP/Decap node.
+ */
+int
+ioam_seqno_decap_handler (vlib_buffer_t *b, ip6_header_t *ip,
+ ip6_hop_by_hop_option_t *opt)
+{
+ u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index;
+ ioam_e2e_option_t * e2e;
+ int rv = 0;
+ ioam_seqno_data *data;
+
+ data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index);
+ e2e = (ioam_e2e_option_t *) opt;
+ ioam_analyze_seqno(&data->seqno_rx, (u64) clib_net_to_host_u32(e2e->e2e_data));
+
+ return (rv);
+}
+
+u8 *
+show_ioam_seqno_cmd_fn (u8 *s, ioam_seqno_data *seqno_data, u8 enc)
+{
+ seqno_rx_info *rx;
+
+ s = format(s, "SeqNo Data:\n");
+ if (enc)
+ {
+ s = format(s, " Current Seq. Number : %llu\n", seqno_data->seq_num);
+ }
+ else
+ {
+ rx = &seqno_data->seqno_rx;
+ s = format(s, " Highest Seq. Number : %llu\n", rx->bitmap.highest);
+ s = format(s, " Packets received : %llu\n", rx->rx_packets);
+ s = format(s, " Lost packets : %llu\n", rx->lost_packets);
+ s = format(s, " Reordered packets : %llu\n", rx->reordered_packets);
+ s = format(s, " Duplicate packets : %llu\n", rx->dup_packets);
+ }
+
+ format(s, "\n");
+ return s;
+}
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h
new file mode 100644
index 00000000000..13a84db0d71
--- /dev/null
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h
@@ -0,0 +1,70 @@
+/*
+ * 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_ip6_ioam_seqno_h__
+#define __included_ip6_ioam_seqno_h__
+
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip6_hop_by_hop.h>
+
+#define SEQ_CHECK_VALUE 0x80000000 /* for seq number wraparound detection */
+
+#define SEQNO_WINDOW_SIZE 2048
+#define SEQNO_WINDOW_ARRAY_SIZE 64
+
+typedef struct seqno_bitmap_ {
+ u32 window_size;
+ u32 array_size;
+ u32 mask;
+ u32 pad;
+ u64 highest;
+ u64 array[SEQNO_WINDOW_ARRAY_SIZE]; /* Will be alloc to array_size */
+} seqno_bitmap;
+
+typedef struct seqno_rx_info_ {
+ u64 rx_packets;
+ u64 lost_packets;
+ u64 reordered_packets;
+ u64 dup_packets;
+ seqno_bitmap bitmap;
+} seqno_rx_info;
+
+/* This structure is 64-byte aligned */
+typedef struct ioam_seqno_data_ {
+ union {
+ u32 seq_num; /* Useful only for encap node */
+ seqno_rx_info seqno_rx;
+ };
+} ioam_seqno_data;
+
+typedef struct ioam_seqno_data_main_t_ {
+ ioam_seqno_data *seqno_data;
+} ioam_seqno_data_main_t;
+
+void ioam_seqno_init_bitmap(ioam_seqno_data *data);
+
+int ioam_seqno_encap_handler(vlib_buffer_t *b, ip6_header_t *ip,
+ ip6_hop_by_hop_option_t *opt);
+
+int
+ioam_seqno_decap_handler(vlib_buffer_t *b, ip6_header_t *ip,
+ ip6_hop_by_hop_option_t *opt);
+
+void ioam_analyze_seqno(seqno_rx_info *ppc_rx, u64 seqno);
+
+u8 *
+show_ioam_seqno_cmd_fn(u8 *s, ioam_seqno_data *seqno_data, u8 enc);
+
+#endif
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c
new file mode 100644
index 00000000000..4638871c224
--- /dev/null
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <vnet/vnet.h>
+#include "ip6_ioam_seqno.h"
+
+static inline void BIT_SET (u64 *p, u32 n)
+{
+ p[ n>>5 ] |= (1 << (n&31));
+}
+
+static inline int BIT_TEST (u64 *p, u32 n)
+{
+ return p[ n>>5 ] & (1 << (n&31));
+}
+
+static void BIT_CLEAR (u64 *p, u64 start, int num_bits, u32 mask)
+{
+ int n, t;
+ int start_index = (start >> 5);
+ int mask_index = (mask >> 5);
+
+ start_index &= mask_index;
+ if (start & 0x1f)
+ {
+ int start_bit = (start & 0x1f);
+
+ n = (1 << start_bit)-1;
+ t = start_bit + num_bits;
+ if (t < 32)
+ {
+ n |= ~((1 << t)-1);
+ p[ start_index ] &= n;
+ return;
+ }
+ p[ start_index ] &= n;
+ start_index = (start_index + 1) & mask_index;
+ num_bits -= (32 - start_bit);
+ }
+ while (num_bits >= 32)
+ {
+ p[ start_index ] = 0;
+ start_index = (start_index + 1) & mask_index;
+ num_bits -= 32;
+ }
+ n = ~((1 << num_bits) - 1);
+ p[ start_index ] &= n;
+}
+
+static inline u8 seqno_check_wraparound(u32 a, u32 b)
+{
+ if ((a != b) && (a > b) && ((a - b) > SEQ_CHECK_VALUE))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Function to analyze the PPC value recevied.
+ * - Updates the bitmap with received sequence number
+ * - counts the received/lost/duplicate/reordered packets
+ */
+void ioam_analyze_seqno (seqno_rx_info *seqno_rx, u64 seqno)
+{
+ int diff;
+ static int peer_dead_count;
+ seqno_bitmap *bitmap = &seqno_rx->bitmap;
+
+ seqno_rx->rx_packets++;
+
+ if (seqno > bitmap->highest)
+ { /* new larger sequence number */
+ peer_dead_count = 0;
+ diff = seqno - bitmap->highest;
+ if (diff < bitmap->window_size)
+ {
+ if (diff > 1)
+ { /* diff==1 is *such* a common case it's a win to optimize it */
+ BIT_CLEAR(bitmap->array, bitmap->highest+1, diff-1, bitmap->mask);
+ seqno_rx->lost_packets += diff -1;
+ }
+ }
+ else
+ {
+ seqno_rx->lost_packets += diff -1;
+ memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) );
+ }
+ BIT_SET(bitmap->array, seqno & bitmap->mask);
+ bitmap->highest = seqno;
+ return;
+ }
+
+ /* we've seen a bigger seq number before */
+ diff = bitmap->highest - seqno;
+ if (diff >= bitmap->window_size)
+ {
+ if (seqno_check_wraparound(bitmap->highest, seqno))
+ {
+ memset( bitmap->array, 0, bitmap->array_size * sizeof(u64));
+ BIT_SET(bitmap->array, seqno & bitmap->mask);
+ bitmap->highest = seqno;
+ return;
+ }
+ else
+ {
+ peer_dead_count++;
+ if (peer_dead_count > 25)
+ {
+ peer_dead_count = 0;
+ memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) );
+ BIT_SET(bitmap->array, seqno & bitmap->mask);
+ bitmap->highest = seqno;
+ }
+ //ppc_rx->reordered_packets++;
+ }
+ return;
+ }
+
+ if (BIT_TEST(bitmap->array, seqno & bitmap->mask))
+ {
+ seqno_rx->dup_packets++;
+ return; /* Already seen */
+ }
+ seqno_rx->reordered_packets++;
+ seqno_rx->lost_packets--;
+ BIT_SET(bitmap->array, seqno & bitmap->mask);
+ return;
+}
diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c
index 5c9814051da..16e10817d00 100644
--- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c
+++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c
@@ -153,7 +153,8 @@ ioam_trace_get_sizeof_handler (u32 * result)
if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254))
return VNET_API_ERROR_INVALID_VALUE;
- size += profile->num_elts * trace_data_size;
+ size +=
+ sizeof (ioam_trace_option_t) + (profile->num_elts * trace_data_size);
*result = size;
return 0;
diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_util.c b/plugins/ioam-plugin/ioam/lib-trace/trace_util.c
index ca9adcd1225..adc02b20f56 100644
--- a/plugins/ioam-plugin/ioam/lib-trace/trace_util.c
+++ b/plugins/ioam-plugin/ioam/lib-trace/trace_util.c
@@ -35,7 +35,7 @@ trace_profile_cleanup (trace_profile * profile)
if (0 !=
(rv =
ip6_ioam_set_rewrite (&hm->rewrite, hm->has_trace_option,
- hm->has_pot_option, hm->has_ppc_option)))
+ hm->has_pot_option, hm->has_seqno_option)))
return (-1);
return 0;
@@ -89,7 +89,8 @@ trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts,
if (0 !=
(rv =
ip6_ioam_set_rewrite (&hm->rewrite, hm->has_trace_option,
- hm->has_pot_option, hm->has_ppc_option)))
+ hm->has_pot_option,
+ hm->has_seqno_option)))
return (-1);
}
diff --git a/vnet/vnet/buffer.h b/vnet/vnet/buffer.h
index 6385f19142c..fafb318104e 100644
--- a/vnet/vnet/buffer.h
+++ b/vnet/vnet/buffer.h
@@ -182,8 +182,8 @@ typedef struct
struct
{
u64 pad;
- u32 opaque_index;
u32 table_index;
+ u32 opaque_index;
u64 hash;
} l2_classify;
diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h
index f6008d71ea1..8b3b9973bf4 100644
--- a/vnet/vnet/ip/ip6.h
+++ b/vnet/vnet/ip/ip6.h
@@ -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:
@@ -521,6 +521,6 @@ int ip6_hbh_unregister_option (u8 option);
void ip6_hbh_set_next_override (uword next);
/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
-#define OI_DECAP 100
+#define OI_DECAP 0x80000000
#endif /* included_ip_ip6_h */
diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c
index 4493cb4cff3..53d13db2be3 100644
--- a/vnet/vnet/ip/ip6_forward.c
+++ b/vnet/vnet/ip/ip6_forward.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:
@@ -2459,12 +2459,12 @@ ip6_hop_by_hop (vlib_main_t * vm,
outdual:
/* Has the classifier flagged this buffer for special treatment? */
- if ((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index == OI_DECAP))
- next0 = hm->next_override;
+ if (PREDICT_FALSE((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index & OI_DECAP)))
+ next0 = hm->next_override;
/* Has the classifier flagged this buffer for special treatment? */
- if ((error1 == 0) && (vnet_buffer(b1)->l2_classify.opaque_index == OI_DECAP))
- next1 = hm->next_override;
+ if (PREDICT_FALSE((error1 == 0) && (vnet_buffer(b1)->l2_classify.opaque_index & OI_DECAP)))
+ next1 = hm->next_override;
if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
{
@@ -2542,7 +2542,7 @@ ip6_hop_by_hop (vlib_main_t * vm,
out0:
/* Has the classifier flagged this buffer for special treatment? */
- if ((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index == OI_DECAP))
+ if (PREDICT_FALSE((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index & OI_DECAP)))
next0 = hm->next_override;
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) {
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);
diff --git a/vnet/vnet/ip/ip6_hop_by_hop.h b/vnet/vnet/ip/ip6_hop_by_hop.h
index dae58619e24..7d157cf55e7 100644
--- a/vnet/vnet/ip/ip6_hop_by_hop.h
+++ b/vnet/vnet/ip/ip6_hop_by_hop.h
@@ -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:
@@ -15,10 +15,30 @@
#ifndef __included_ip6_hop_by_hop_ioam_h__
#define __included_ip6_hop_by_hop_ioam_h__
-#include <vnet/ip/ip6_hop_by_hop.h>
#include <vnet/ip/ip6_hop_by_hop_packet.h>
#include <vnet/ip/ip.h>
+
+#define MAX_IP6_HBH_OPTION 256
+
+/* To determine whether a node is decap MS bit is set */
+#define IOAM_DECAP_BIT 0x80000000
+
+#define IOAM_DEAP_ENABLED(opaque_data) (opaque_data & IOAM_DECAP_BIT)
+
+#define IOAM_SET_DECAP(opaque_data) \
+ (opaque_data |= IOAM_DECAP_BIT)
+
+#define IOAM_MASK_DECAP_BIT(x) (x & ~IOAM_DECAP_BIT)
+
+/*
+ * Stores the run time flow data of hbh options
+ */
+typedef struct {
+ u32 ctx[MAX_IP6_HBH_OPTION];
+ u8 flow_name[64];
+} flow_data_t;
+
typedef struct {
/* The current rewrite we're using */
u8 * rewrite;
@@ -43,10 +63,11 @@ typedef struct {
/* Pot option */
u8 has_pot_option;
-#define PPC_NONE 0
-#define PPC_ENCAP 1
-#define PPC_DECAP 2
- u8 has_ppc_option;
+ /* Per Packet Counter option */
+ u8 has_seqno_option;
+
+ /* Enabling analyis of iOAM data on decap node */
+ u8 has_analyse_option;
#define TSP_SECONDS 0
#define TSP_MILLISECONDS 1
@@ -54,11 +75,16 @@ typedef struct {
#define TSP_NANOSECONDS 3
/* 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);
- int (*get_sizeof_options[256])(u32 *rewrite_size);
-
+ u8 options_size[MAX_IP6_HBH_OPTION];
+ int (*add_options[MAX_IP6_HBH_OPTION])(u8 *rewrite_string, u8 *rewrite_size);
+ int (*pop_options[MAX_IP6_HBH_OPTION])(vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt);
+ int (*get_sizeof_options[MAX_IP6_HBH_OPTION])(u32 *rewrite_size);
+ int (*config_handler[MAX_IP6_HBH_OPTION]) (void *data, u8 disable);
+
+ /* Array of function pointers to handle hbh options being used with classifier */
+ u32 (*flow_handler[MAX_IP6_HBH_OPTION])(u32 flow_ctx, u8 add);
+ flow_data_t *flows;
+
/* convenience */
vlib_main_t * vlib_main;
vnet_main_t * vnet_main;
@@ -67,9 +93,11 @@ typedef struct {
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_enable(int has_trace_option, int has_pot_option,
- int has_e2e_option);
+ int has_seqno_option, int has_analyse_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);
@@ -107,7 +135,8 @@ int ip6_hbh_add_register_option (u8 option,
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 options(vlib_buffer_t *b,
+ ip6_header_t *ip, ip6_hop_by_hop_option_t *opt));
int ip6_hbh_pop_unregister_option (u8 option);
int
@@ -115,6 +144,49 @@ ip6_hbh_get_sizeof_register_option (u8 option,
int get_sizeof_hdr_options(u32 *rewrite_size));
int
-ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option,
- int has_pot_option, int has_ppc_option);
+ip6_ioam_set_rewrite (u8 **rwp, int has_trace_option,
+ int has_pot_option, int has_seq_no);
+
+int
+ip6_hbh_config_handler_register (u8 option,
+ int config_handler(void *data, u8 disable));
+
+int ip6_hbh_config_handler_unregister (u8 option);
+
+int ip6_hbh_flow_handler_register(u8 option,
+ u32 ioam_flow_handler(u32 flow_ctx, u8 add));
+
+int ip6_hbh_flow_handler_unregister(u8 option);
+
+u8 * get_flow_name_from_flow_ctx(u32 flow_ctx);
+
+static inline flow_data_t * get_flow (u32 index)
+{
+ flow_data_t *flow = NULL;
+ ip6_hop_by_hop_ioam_main_t * hm = &ip6_hop_by_hop_ioam_main;
+
+ if (pool_is_free_index (hm->flows, index))
+ return NULL;
+
+ flow = pool_elt_at_index (hm->flows, index);
+ return flow;
+}
+
+static inline u32 get_flow_data_from_flow_ctx (u32 flow_ctx, u8 option)
+{
+ 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);
+ //flow = pool_elt_at_index (hm->flows, index);
+ flow = &hm->flows[index];
+ return (flow->ctx[option]);
+}
+
+static inline u8 is_seqno_enabled (void)
+{
+ return (ip6_hop_by_hop_ioam_main.has_seqno_option);
+}
+
#endif /* __included_ip6_hop_by_hop_ioam_h__ */
diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c
index 6f11083844b..120c39c4dba 100644
--- a/vpp-api-test/vat/api_format.c
+++ b/vpp-api-test/vat/api_format.c
@@ -7814,28 +7814,28 @@ api_ioam_enable (vat_main_t * vam)
f64 timeout;
u32 id = 0;
int has_trace_option = 0;
- int has_pow_option = 0;
- int has_ppc_option = 0;
+ int has_pot_option = 0;
+ int has_seqno_option = 0;
+ int has_analyse_option = 0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "trace"))
has_trace_option = 1;
- else if (unformat (input, "pow"))
- has_pow_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, "pot"))
+ has_pot_option = 1;
+ else if (unformat (input, "seqno"))
+ has_seqno_option = 1;
+ else if (unformat (input, "analyse"))
+ has_analyse_option = 1;
else
break;
}
M (IOAM_ENABLE, ioam_enable);
mp->id = htons (id);
- mp->trace_ppc = has_ppc_option;
- mp->pow_enable = has_pow_option;
+ mp->seqno = has_seqno_option;
+ mp->analyse = has_analyse_option;
+ mp->pot_enable = has_pot_option;
mp->trace_enable = has_trace_option;
S;
diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c
index 81cd8c358ff..c1f826391ce 100644
--- a/vpp/vpp-api/api.c
+++ b/vpp/vpp-api/api.c
@@ -7233,7 +7233,8 @@ vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
/* Ignoring the profile id as currently a single profile
* is supported */
- error = ip6_ioam_enable (mp->trace_enable, mp->pow_enable, mp->trace_ppc);
+ error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable,
+ mp->seqno, mp->analyse);
if (error)
{
clib_error_report (error);
diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c
index 6406cbad3f3..45d7b96a203 100644
--- a/vpp/vpp-api/custom_dump.c
+++ b/vpp/vpp-api/custom_dump.c
@@ -2804,6 +2804,42 @@ static void *vl_api_get_first_msg_id_t_print
FINISH;
}
+static void *vl_api_ioam_enable_t_print
+ (vl_api_ioam_enable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ioam_enable ");
+
+ if (mp->trace_enable)
+ s = format (s, "trace enabled");
+
+ if (mp->pot_enable)
+ s = format (s, "POT enabled");
+
+ if (mp->seqno)
+ s = format (s, "Seqno enabled");
+
+ if (mp->analyse)
+ s = format (s, "Analyse enabled");
+
+ FINISH;
+}
+
+static void *vl_api_ioam_disable_t_print
+ (vl_api_ioam_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ioam_disable ");
+ s = format (s, "trace disabled");
+ s = format (s, "POT disabled");
+ s = format (s, "Seqno disabled");
+ s = format (s, "Analyse disabled");
+
+ FINISH;
+}
+
#define foreach_custom_print_no_arg_function \
_(lisp_eid_table_vni_dump) \
_(lisp_map_resolver_dump) \
@@ -2968,7 +3004,9 @@ _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
_(PUNT, punt) \
_(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \
_(FLOW_CLASSIFY_DUMP, flow_classify_dump) \
-_(GET_FIRST_MSG_ID, get_first_msg_id)
+_(GET_FIRST_MSG_ID, get_first_msg_id) \
+_(IOAM_ENABLE, ioam_enable) \
+_(IOAM_DISABLE, ioam_disable)
void
vl_msg_api_custom_dump_configure (api_main_t * am)
{
diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api
index c5eacce5413..3ec41abc3b1 100644
--- a/vpp/vpp-api/vpe.api
+++ b/vpp/vpp-api/vpe.api
@@ -4124,7 +4124,8 @@ define sw_interface_clear_stats_reply
/** \brief IOAM enable : Enable in-band OAM
@param id - profile id
- @param trace_ppc - Trace PPC (none/encap/decap)
+ @param seqno - To enable Seqno Processing
+ @param analyse - Enabling analysis of iOAM at decap node
@param pow_enable - Proof of Work enabled or not flag
@param trace_enable - iOAM Trace enabled or not flag
*/
@@ -4133,8 +4134,9 @@ define ioam_enable
u32 client_index;
u32 context;
u16 id;
- u8 trace_ppc;
- u8 pow_enable;
+ u8 seqno;
+ u8 analyse;
+ u8 pot_enable;
u8 trace_enable;
u32 node_id;
};