Adding Sequence Number - Per Packet Counter(PPC) support for iOAM6. 82/2282/20
authorAkshayaNadahalli <anadahal@cisco.com>
Tue, 9 Aug 2016 08:08:04 +0000 (13:38 +0530)
committerDave Barach <openvpp@barachs.net>
Thu, 3 Nov 2016 11:44:21 +0000 (11:44 +0000)
- 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>
18 files changed:
plugins/ioam-plugin/Makefile.am
plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c [new file with mode: 0644]
plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h [new file with mode: 0644]
plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c
plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c [new file with mode: 0644]
plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h [new file with mode: 0644]
plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c [new file with mode: 0644]
plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c
plugins/ioam-plugin/ioam/lib-trace/trace_util.c
vnet/vnet/buffer.h
vnet/vnet/ip/ip6.h
vnet/vnet/ip/ip6_forward.c
vnet/vnet/ip/ip6_hop_by_hop.c
vnet/vnet/ip/ip6_hop_by_hop.h
vpp-api-test/vat/api_format.c
vpp/vpp-api/api.c
vpp/vpp-api/custom_dump.c
vpp/vpp-api/vpe.api

index 853ac6d..3f1edb1 100644 (file)
@@ -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 (file)
index 0000000..0839cdc
--- /dev/null
@@ -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 (file)
index 0000000..18f35f8
--- /dev/null
@@ -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__ */
index 9daea9c..05f42c9 100644 (file)
@@ -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 (file)
index 0000000..0b4d419
--- /dev/null
@@ -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 (file)
index 0000000..13a84db
--- /dev/null
@@ -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 (file)
index 0000000..4638871
--- /dev/null
@@ -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;
+}
index 5c98140..16e1081 100644 (file)
@@ -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;
index ca9adcd..adc02b2 100644 (file)
@@ -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);
 
        }
index 6385f19..fafb318 100644 (file)
@@ -182,8 +182,8 @@ typedef struct
     struct
     {
       u64 pad;
-      u32 opaque_index;
       u32 table_index;
+      u32 opaque_index;
       u64 hash;
     } l2_classify;
 
index f6008d7..8b3b997 100644 (file)
@@ -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 */
index 4493cb4..53d13db 100644 (file)
@@ -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)) {
index 72490b9..e8bc890 100644 (file)
@@ -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);
index dae5861..7d157cf 100644 (file)
@@ -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:
 #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__ */
index 6f11083..120c39c 100644 (file)
@@ -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;
index 81cd8c3..c1f8263 100644 (file)
@@ -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);
index 6406cba..45d7b96 100644 (file)
@@ -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)
 {
index c5eacce..3ec41ab 100644 (file)
@@ -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;
 };