VPP-632 : InBand OAM Analyser 47/4047/19
authorAkshayaNadahalli <anadahal@cisco.com>
Thu, 1 Dec 2016 11:03:51 +0000 (16:33 +0530)
committerNeale Ranns <nranns@cisco.com>
Mon, 13 Feb 2017 08:36:59 +0000 (08:36 +0000)
Refer to jira ticket for more details.

Change-Id: I6facb9ef8553a21464f9a2e612706f152badbb68
Signed-off-by: AkshayaNadahalli <anadahal@cisco.com>
33 files changed:
src/plugins/ioam.am
src/plugins/ioam/analyse/ioam_analyse.h [new file with mode: 0644]
src/plugins/ioam/analyse/ioam_summary_export.c [new file with mode: 0644]
src/plugins/ioam/analyse/ioam_summary_export.h [new file with mode: 0755]
src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.c [new file with mode: 0644]
src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.h [new file with mode: 0644]
src/plugins/ioam/analyse/ip6/node.c [new file with mode: 0644]
src/plugins/ioam/encap/ip6_ioam_e2e.c
src/plugins/ioam/encap/ip6_ioam_e2e.h
src/plugins/ioam/encap/ip6_ioam_pot.c
src/plugins/ioam/encap/ip6_ioam_pot.h [new file with mode: 0644]
src/plugins/ioam/encap/ip6_ioam_seqno.c
src/plugins/ioam/encap/ip6_ioam_seqno.h
src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c [deleted file]
src/plugins/ioam/encap/ip6_ioam_trace.c
src/plugins/ioam/encap/ip6_ioam_trace.h [new file with mode: 0644]
src/plugins/ioam/export-common/ioam_export.h
src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c
src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c
src/plugins/ioam/export/ioam_export.c
src/plugins/ioam/export/node.c
src/plugins/ioam/ipfixcollector/ipfixcollector.c [new file with mode: 0644]
src/plugins/ioam/ipfixcollector/ipfixcollector.h [new file with mode: 0644]
src/plugins/ioam/ipfixcollector/node.c [new file with mode: 0644]
src/plugins/ioam/lib-e2e/e2e_util.h [new file with mode: 0644]
src/plugins/ioam/lib-e2e/ioam_seqno_lib.c [new file with mode: 0644]
src/plugins/ioam/lib-e2e/ioam_seqno_lib.h [new file with mode: 0644]
src/plugins/ioam/lib-trace/trace_util.h
src/vnet/ip/ip6.h
src/vnet/ip/ip6_forward.c
src/vnet/ip/ip6_hop_by_hop.c
src/vnet/ip/ip6_hop_by_hop.h
src/vnet/ip/ip6_hop_by_hop_packet.h

index a2b298b..14d8a9e 100644 (file)
@@ -129,17 +129,39 @@ vxlan_gpe_ioam_export_test_plugin_la_SOURCES =          \
 vppapitestplugins_LTLIBRARIES += vxlan_gpe_ioam_export_test_plugin.la
 
 ########################################
-# iOAM E2E plugin
+# iOAM E2E
 ########################################
 
 IOAM_E2E_SRC =                                 \
        ioam/encap/ip6_ioam_e2e.c               \
-       ioam/encap/ip6_ioam_seqno.c             \
-       ioam/encap/ip6_ioam_seqno_analyse.c
+       ioam/encap/ip6_ioam_seqno.c             \
+       ioam/lib-e2e/ioam_seqno_lib.c
 
-IOAM_E2E_NOINST_HDR =                   \
+IOAM_E2E_NOINST_HDR =                    \
        ioam/encap/ip6_ioam_e2e.h        \
-       ioam/encap/ip6_ioam_seqno.h
+       ioam/encap/ip6_ioam_seqno.h      \
+       ioam/lib-e2e/ioam_seqno_lib.h
+
+########################################
+# ipfix collector
+########################################
+
+IPFIX_COLLECTOR_SRC =                          \
+       ioam/ipfixcollector/ipfixcollector.c    \
+       ioam/ipfixcollector/node.c              \
+       ioam/ipfixcollector/ipfixcollector.h
+
+########################################
+# iOAM Analyse
+########################################
+
+IOAM_ANALYSE_SRC =                             \
+       ioam/analyse/ip6/ip6_ioam_analyse.c     \
+       ioam/analyse/ip6/node.c                 \
+       ioam/analyse/ip6/ip6_ioam_analyse.h     \
+       ioam/analyse/ioam_summary_export.c      \
+       ioam/analyse/ioam_analyse.h             \
+       ioam/analyse/ioam_summary_export.h
 
 ########################################
 # iOAM plugins
@@ -150,7 +172,9 @@ ioam_plugin_la_SOURCES =            \
         $(IOAM_EXPORT_SRC)              \
         $(IOAM_TRACE_SRC)               \
         $(IOAM_VXLAN_GPE_SRC)          \
-        $(IOAM_E2E_SRC)
+        $(IOAM_E2E_SRC)                        \
+       $(IPFIX_COLLECTOR_SRC)          \
+       $(IOAM_ANALYSE_SRC)
 
 API_FILES +=                           \
         $(IOAM_POT_API)                 \
diff --git a/src/plugins/ioam/analyse/ioam_analyse.h b/src/plugins/ioam/analyse/ioam_analyse.h
new file mode 100644 (file)
index 0000000..a416cb1
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2017 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 PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_
+#define PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/types.h>
+#include <ioam/lib-e2e/e2e_util.h>
+#include <ioam/lib-trace/trace_util.h>
+
+#define IOAM_FLOW_TEMPLATE_ID    260
+#define IOAM_TRACE_MAX_NODES      10
+#define IOAM_MAX_PATHS_PER_FLOW   10
+
+typedef struct
+{
+  u16 ingress_if;
+  u16 egress_if;
+  u32 node_id;
+} ioam_path_map_t;
+
+/** @brief Analysed iOAM trace data.
+    @note cache aligned.
+*/
+typedef struct
+{
+  /** No of nodes in path. */
+  u8 num_nodes;
+
+  /** Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp. */
+  u8 trace_type;
+
+  /** Flag to indicate whether node is allocated. */
+  u8 is_free;
+
+  u8 pad[5];
+
+  /** Actual PATH flow has taken. */
+  ioam_path_map_t path[IOAM_TRACE_MAX_NODES];
+
+  /** Num of pkts in the flow going over path. */
+  u32 pkt_counter;
+
+  /** Num of bytes in the flow going over path. */
+  u32 bytes_counter;
+
+  /** Minumum Dealay for the flow. */
+  u32 min_delay;
+
+  /** Maximum Dealay for the flow. */
+  u32 max_delay;
+
+  /** Average Dealay for the flow. */
+  u32 mean_delay;
+
+  u32 reserve;
+} ioam_analyse_trace_record;
+
+typedef struct
+{
+  ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW];
+} ioam_analyse_trace_data;
+
+/** @brief Analysed iOAM pot data.
+    @note cache aligned.
+*/
+typedef struct
+{
+  /** Number of packets validated (passes through the service chain)
+      within the timestamps. */
+  u32 sfc_validated_count;
+
+  /** Number of packets invalidated (failed through the service chain)
+      within the timestamps. */
+  u32 sfc_invalidated_count;
+} ioam_analyse_pot_data;
+
+/** @brief Analysed iOAM data.
+    @note cache aligned.
+*/
+typedef struct ioam_analyser_data_t_
+{
+  u8 is_free;
+  u8 pad[3];
+
+  /** Num of pkts sent for this flow. */
+  u32 pkt_sent;
+
+  /** Num of pkts matching this flow. */
+  u32 pkt_counter;
+
+  /** Num of bytes matching this flow. */
+  u32 bytes_counter;
+
+  /** Analysed iOAM trace data. */
+  ioam_analyse_trace_data trace_data;
+
+  /** Analysed iOAM pot data. */
+  ioam_analyse_pot_data pot_data;
+
+  /** Analysed iOAM seqno data. */
+  seqno_rx_info seqno_data;
+
+  /** Cache of previously analysed data, useful for export. */
+  struct ioam_analyser_data_t_ *chached_data_list;
+
+  /** Lock to since we use this to export the data in other thread. */
+  volatile u32 *writer_lock;
+} ioam_analyser_data_t;
+
+always_inline f64
+ip6_ioam_analyse_calc_delay (ioam_trace_hdr_t * trace, u16 trace_len)
+{
+  u16 size_of_traceopt_per_node, size_of_all_traceopts;
+  u8 num_nodes;
+  u32 *start_elt, *end_elt;
+  u32 start_time, end_time;
+
+  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
+  size_of_all_traceopts = trace_len;   /*ioam_trace_type,data_list_elts_left */
+
+  num_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
+
+  num_nodes -= trace->data_list_elts_left;
+
+  start_elt = trace->elts;
+  end_elt =
+    trace->elts +
+    (size_of_traceopt_per_node * (num_nodes - 1) / sizeof (u32));
+
+  if (trace->ioam_trace_type & BIT_TTL_NODEID)
+    {
+      start_elt++;
+      end_elt++;
+    }
+  if (trace->ioam_trace_type & BIT_ING_INTERFACE)
+    {
+      start_elt++;
+      end_elt++;
+    }
+
+  start_time = clib_net_to_host_u32 (*start_elt);
+  end_time = clib_net_to_host_u32 (*end_elt);
+
+  return (f64) (end_time - start_time);
+}
+
+always_inline int
+ip6_ioam_analyse_hbh_trace (ioam_analyser_data_t * data,
+                           ioam_trace_hdr_t * trace, u16 pak_len,
+                           u16 trace_len)
+{
+  ioam_analyse_trace_data *trace_data;
+  u16 size_of_traceopt_per_node;
+  u16 size_of_all_traceopts;
+  u8 i, j, k, num_nodes, max_nodes;
+  u8 *ptr;
+  u32 nodeid;
+  u16 ingress_if, egress_if;
+  ioam_path_map_t *path = NULL;
+  ioam_analyse_trace_record *trace_record;
+
+  while (__sync_lock_test_and_set (data->writer_lock, 1))
+    ;
+
+  trace_data = &data->trace_data;
+
+  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
+  size_of_all_traceopts = trace_len;
+
+  ptr = (u8 *) trace->elts;
+  max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
+  num_nodes = max_nodes - trace->data_list_elts_left;
+
+  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
+    {
+      trace_record = trace_data->path_data + i;
+
+      if (trace_record->is_free ||
+         (num_nodes != trace_record->num_nodes) ||
+         (trace->ioam_trace_type != trace_record->trace_type))
+       continue;
+
+      path = trace_record->path;
+
+      for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
+       {
+         ptr =
+           (u8 *) ((u8 *) trace->elts +
+                   (size_of_traceopt_per_node * (j - 1)));
+
+         nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
+         ptr += 4;
+
+         if (nodeid != path[k].node_id)
+           break;
+
+         if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
+             (trace->ioam_trace_type == TRACE_TYPE_IF))
+           {
+             ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
+             ptr += 2;
+             egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
+             if ((ingress_if != path[k].ingress_if) ||
+                 (egress_if != path[k].egress_if))
+               {
+                 break;
+               }
+           }
+       }
+
+      if (k == num_nodes)
+       {
+         goto found_match;
+       }
+    }
+
+  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
+    {
+      trace_record = trace_data->path_data + i;
+      if (trace_record->is_free)
+       {
+         trace_record->is_free = 0;
+         trace_record->num_nodes = num_nodes;
+         trace_record->trace_type = trace->ioam_trace_type;
+         path = trace_data->path_data[i].path;
+         trace_record->pkt_counter = 0;
+         trace_record->bytes_counter = 0;
+         trace_record->min_delay = 0xFFFFFFFF;
+         trace_record->max_delay = 0;
+         trace_record->mean_delay = 0;
+         break;
+       }
+    }
+
+  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
+    {
+      ptr =
+       (u8 *) ((u8 *) trace->elts + (size_of_traceopt_per_node * (j - 1)));
+
+      path[k].node_id = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
+      ptr += 4;
+
+      if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
+         (trace->ioam_trace_type == TRACE_TYPE_IF))
+       {
+         path[k].ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
+         ptr += 2;
+         path[k].egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
+       }
+    }
+
+found_match:
+  trace_record->pkt_counter++;
+  trace_record->bytes_counter += pak_len;
+
+  if (trace->ioam_trace_type & BIT_TIMESTAMP)
+    {
+      /* Calculate time delay */
+      u32 delay = (u32) ip6_ioam_analyse_calc_delay (trace, trace_len);
+      if (delay < trace_record->min_delay)
+       trace_record->min_delay = delay;
+      else if (delay > trace_record->max_delay)
+       trace_record->max_delay = delay;
+
+      u64 sum = (trace_record->mean_delay * data->seqno_data.rx_packets);
+      trace_record->mean_delay =
+       (u32) ((sum + delay) / (data->seqno_data.rx_packets + 1));
+    }
+
+  *(data->writer_lock) = 0;
+  return 0;
+}
+
+always_inline int
+ip6_ioam_analyse_hbh_e2e (ioam_analyser_data_t * data,
+                         ioam_e2e_packet_t * e2e, u16 len)
+{
+  while (__sync_lock_test_and_set (data->writer_lock, 1))
+    ;
+
+  ioam_analyze_seqno (&data->seqno_data,
+                     (u64) clib_net_to_host_u32 (e2e->e2e_data));
+
+  *(data->writer_lock) = 0;
+  return 0;
+}
+
+always_inline u8 *
+format_path_map (u8 * s, va_list * args)
+{
+  ioam_path_map_t *pm = va_arg (*args, ioam_path_map_t *);
+  u32 num_of_elts = va_arg (*args, u32);
+  u32 i;
+
+  for (i = 0; i < num_of_elts; i++)
+    {
+      s = format (s, "node_id: 0x%x, ingress_if: 0x%x, egress_if:0x%x\n",
+                 pm->node_id, pm->ingress_if, pm->egress_if);
+      pm++;
+    }
+
+  return (s);
+}
+
+always_inline u8 *
+print_analyse_flow (u8 * s, ioam_analyser_data_t * record)
+{
+  int j;
+  ioam_analyse_trace_record *trace_record;
+
+  s = format (s, "pkt_sent : %u\n", record->pkt_sent);
+  s = format (s, "pkt_counter : %u\n", record->pkt_counter);
+  s = format (s, "bytes_counter : %u\n", record->bytes_counter);
+
+  s = format (s, "Trace data: \n");
+
+  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
+    {
+      trace_record = record->trace_data.path_data + j;
+      if (trace_record->is_free)
+       continue;
+
+      s = format (s, "path_map:\n%U", format_path_map,
+                 trace_record->path, trace_record->num_nodes);
+      s = format (s, "pkt_counter: %u\n", trace_record->pkt_counter);
+      s = format (s, "bytes_counter: %u\n", trace_record->bytes_counter);
+
+      s = format (s, "min_delay: %u\n", trace_record->min_delay);
+      s = format (s, "max_delay: %u\n", trace_record->max_delay);
+      s = format (s, "mean_delay: %u\n", trace_record->mean_delay);
+    }
+
+  s = format (s, "\nPOT data: \n");
+  s = format (s, "sfc_validated_count : %u\n",
+             record->pot_data.sfc_validated_count);
+  s = format (s, "sfc_invalidated_count : %u\n",
+             record->pot_data.sfc_invalidated_count);
+
+  s = format (s, "\nSeqno Data:\n");
+  s = format (s,
+             "RX Packets        : %lu\n"
+             "Lost Packets      : %lu\n"
+             "Duplicate Packets : %lu\n"
+             "Reordered Packets : %lu\n",
+             record->seqno_data.rx_packets,
+             record->seqno_data.lost_packets,
+             record->seqno_data.dup_packets,
+             record->seqno_data.reordered_packets);
+
+  s = format (s, "\n");
+  return s;
+}
+
+always_inline void
+ioam_analyse_init_data (ioam_analyser_data_t * data)
+{
+  u16 j;
+  ioam_analyse_trace_data *trace_data;
+
+  data->is_free = 1;
+
+  /* We maintain data corresponding to last IP-Fix export, this may
+   * get extended in future to maintain history of data */
+  vec_validate_aligned (data->chached_data_list, 0, CLIB_CACHE_LINE_BYTES);
+
+  data->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
+                                             CLIB_CACHE_LINE_BYTES);
+  *(data->writer_lock) = 0;
+
+  trace_data = &(data->trace_data);
+  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
+    trace_data->path_data[j].is_free = 1;
+}
+
+#endif /* PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/analyse/ioam_summary_export.c b/src/plugins/ioam/analyse/ioam_summary_export.c
new file mode 100644 (file)
index 0000000..0056732
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2017 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/ip/ip6_packet.h>
+#include <ioam/analyse/ioam_summary_export.h>
+#include <ioam/analyse/ip6/ip6_ioam_analyse.h>
+
+u8 *
+ioam_template_rewrite (flow_report_main_t * frm, flow_report_t * fr,
+                      ip4_address_t * collector_address,
+                      ip4_address_t * src_address, u16 collector_port)
+{
+  ip4_header_t *ip;
+  udp_header_t *udp;
+  ipfix_message_header_t *h;
+  ipfix_set_header_t *s;
+  ipfix_template_header_t *t;
+  ipfix_field_specifier_t *f;
+  ipfix_field_specifier_t *first_field;
+  u8 *rewrite = 0;
+  ip4_ipfix_template_packet_t *tp;
+  u32 field_count = 0;
+  u32 field_index = 0;
+  flow_report_stream_t *stream;
+
+  stream = &frm->streams[fr->stream_index];
+
+  /* Determine field count */
+#define _(field,mask,item,length)                                   \
+    {                                                               \
+  field_count++;                                                    \
+  fr->fields_to_send = clib_bitmap_set (fr->fields_to_send,         \
+                                        field_index, 1);            \
+    }                                                               \
+    field_index++;
+
+  foreach_ioam_ipfix_field;
+#undef _
+
+  /* Add Src address, dest address, src port, dest port
+   * path map,  number of paths manually */
+  field_count += 6;
+
+  /* allocate rewrite space */
+  vec_validate_aligned (rewrite,
+                       sizeof (ip4_ipfix_template_packet_t)
+                       + field_count * sizeof (ipfix_field_specifier_t) - 1,
+                       CLIB_CACHE_LINE_BYTES);
+
+  tp = (ip4_ipfix_template_packet_t *) rewrite;
+  ip = (ip4_header_t *) & tp->ip4;
+  udp = (udp_header_t *) (ip + 1);
+  h = (ipfix_message_header_t *) (udp + 1);
+  s = (ipfix_set_header_t *) (h + 1);
+  t = (ipfix_template_header_t *) (s + 1);
+  first_field = f = (ipfix_field_specifier_t *) (t + 1);
+
+  ip->ip_version_and_header_length = 0x45;
+  ip->ttl = 254;
+  ip->protocol = IP_PROTOCOL_UDP;
+  ip->src_address.as_u32 = src_address->as_u32;
+  ip->dst_address.as_u32 = collector_address->as_u32;
+  udp->src_port = clib_host_to_net_u16 (collector_port);
+  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
+  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
+
+  h->domain_id = clib_host_to_net_u32 (stream->domain_id);     //fr->domain_id);
+
+  /* Add Src address, dest address, src port, dest port
+   * path map,  number of paths manually */
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
+                                     sourceIPv6Address,
+                                     sizeof (ip6_address_t));
+  f++;
+
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
+                                     destinationIPv6Address,
+                                     sizeof (ip6_address_t));
+  f++;
+
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
+                                     sourceTransportPort, 2);
+  f++;
+
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
+                                     destinationTransportPort, 2);
+  f++;
+
+#define _(field,mask,item,length)                               \
+    {                                                           \
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */,       \
+    item, length);                                              \
+    f++;                                                        \
+    }
+  foreach_ioam_ipfix_field;
+#undef _
+
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
+                                     ioamNumberOfPaths, 2);
+  f++;
+
+  /* Add ioamPathMap manually */
+  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
+                                     ioamPathMap, (1 * sizeof (ioam_path)));
+  f++;
+
+  /* Back to the template packet... */
+  ip = (ip4_header_t *) & tp->ip4;
+  udp = (udp_header_t *) (ip + 1);
+
+  ASSERT (f - first_field);
+  /* Field count in this template */
+  t->id_count = ipfix_id_count (IOAM_FLOW_TEMPLATE_ID, f - first_field);
+
+  /* set length in octets */
+  s->set_id_length =
+    ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
+
+  /* message length in octets */
+  h->version_length = version_length ((u8 *) f - (u8 *) h);
+
+  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
+  ip->checksum = ip4_header_checksum (ip);
+
+  return rewrite;
+}
+
+u16
+ioam_analyse_add_ipfix_record (flow_report_t * fr,
+                              ioam_analyser_data_t * record,
+                              vlib_buffer_t * b0, u16 offset,
+                              ip6_address_t * src, ip6_address_t * dst,
+                              u16 src_port, u16 dst_port)
+{
+  while (__sync_lock_test_and_set (record->writer_lock, 1))
+    ;
+
+  int field_index = 0;
+  u16 tmp;
+  int i, j;
+  u16 num_paths = 0;
+  u16 num_paths_offset;
+
+
+  /* Add IPv6 source address manually */
+  memcpy (b0->data + offset, &src->as_u64[0], sizeof (u64));
+  offset += sizeof (u64);
+  memcpy (b0->data + offset, &src->as_u64[1], sizeof (u64));
+  offset += sizeof (u64);
+
+  /* Add IPv6 destination address manually */
+  memcpy (b0->data + offset, &dst->as_u64[0], sizeof (u64));
+  offset += sizeof (u64);
+  memcpy (b0->data + offset, &dst->as_u64[1], sizeof (u64));
+  offset += sizeof (u64);
+
+  /* Add source port manually */
+  tmp = clib_host_to_net_u16 (src_port);
+  memcpy (b0->data + offset, &tmp, sizeof (u16));
+  offset += sizeof (u16);
+
+  /* Add dest port manually */
+  tmp = clib_host_to_net_u16 (dst_port);
+  memcpy (b0->data + offset, &tmp, sizeof (u16));
+  offset += sizeof (u16);
+
+#define _(field,mask,item,length)                            \
+    if (clib_bitmap_get (fr->fields_to_send, field_index))   \
+    {                                                        \
+      /* Expect only 4 bytes */               \
+      u32 tmp;                                             \
+      tmp = clib_host_to_net_u32((u32)record->field - (u32)record->chached_data_list->field);\
+      memcpy (b0->data + offset, &tmp, length);       \
+      offset += length;                                 \
+    }
+  field_index++;
+  foreach_ioam_ipfix_field;
+#undef _
+
+  /* Store num_paths_offset here and update later */
+  num_paths_offset = offset;
+  offset += sizeof (u16);
+
+  /* Add ioamPathMap manually */
+  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
+    {
+      ioam_analyse_trace_record *trace = record->trace_data.path_data + i;
+      ioam_analyse_trace_record *trace_cached =
+       record->chached_data_list->trace_data.path_data + i;
+      ioam_path *path = (ioam_path *) (b0->data + offset);
+
+      if (!trace->is_free)
+       {
+         num_paths++;
+
+         path->num_nodes = trace->num_nodes;
+
+         path->trace_type = trace->trace_type;
+         if (0 < (trace->pkt_counter - trace_cached->pkt_counter))
+           {
+             u64 new_sum = trace->mean_delay * record->seqno_data.rx_packets;
+             u64 old_sum =
+               trace_cached->mean_delay *
+               record->chached_data_list->seqno_data.rx_packets;
+             path->mean_delay =
+               (u32) ((new_sum - old_sum) / (trace->pkt_counter -
+                                             trace_cached->pkt_counter));
+             path->mean_delay = clib_host_to_net_u32 (path->mean_delay);
+           }
+         else
+           path->mean_delay = 0;
+
+         path->bytes_counter =
+           trace->bytes_counter - trace_cached->bytes_counter;
+         path->bytes_counter = clib_host_to_net_u32 (path->bytes_counter);
+
+         path->pkt_counter = trace->pkt_counter - trace_cached->pkt_counter;
+         path->pkt_counter = clib_host_to_net_u32 (path->pkt_counter);
+
+         for (j = 0; j < IOAM_TRACE_MAX_NODES; j++)
+           {
+             path->path[j].node_id =
+               clib_host_to_net_u32 (trace->path[j].node_id);
+             path->path[j].ingress_if =
+               clib_host_to_net_u16 (trace->path[j].ingress_if);
+             path->path[j].egress_if =
+               clib_host_to_net_u16 (trace->path[j].egress_if);
+           }
+
+         offset += sizeof (ioam_path);
+       }
+    }
+
+  num_paths = clib_host_to_net_u16 (num_paths);
+  memcpy (b0->data + num_paths_offset, &num_paths, sizeof (u16));
+
+  /* Update cache */
+  *(record->chached_data_list) = *record;
+  record->chached_data_list->chached_data_list = NULL;
+
+  *(record->writer_lock) = 0;
+  return offset;
+}
+
+vlib_frame_t *
+ioam_send_flows (flow_report_main_t * frm, flow_report_t * fr,
+                vlib_frame_t * f, u32 * to_next, u32 node_index)
+{
+  vlib_buffer_t *b0 = NULL;
+  u32 next_offset = 0;
+  u32 bi0 = ~0;
+  int i;
+  ip4_ipfix_template_packet_t *tp;
+  ipfix_message_header_t *h;
+  ipfix_set_header_t *s = NULL;
+  ip4_header_t *ip;
+  udp_header_t *udp;
+  u32 records_this_buffer;
+  u16 new_l0, old_l0;
+  ip_csum_t sum0;
+  vlib_main_t *vm = frm->vlib_main;
+  ip6_address_t temp;
+  ioam_analyser_data_t *record = NULL;
+  flow_report_stream_t *stream;
+  ioam_analyser_data_t *aggregated_data;
+  u16 data_len;
+
+  stream = &frm->streams[fr->stream_index];
+
+  memset (&temp, 0, sizeof (ip6_address_t));
+
+  aggregated_data = ioam_analyser_main.aggregated_data;
+  data_len = vec_len (aggregated_data);
+
+  vec_foreach_index (i, aggregated_data)
+  {
+    u8 flush = 0;
+    record = aggregated_data + i;
+
+    /* Flush if last entry */
+    if (i == (data_len - 1))
+      flush = 1;
+
+    if (!record->is_free)
+      {
+
+       if (PREDICT_FALSE (b0 == NULL))
+         {
+           if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
+             break;
+
+           b0 = vlib_get_buffer (vm, bi0);
+           memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
+           b0->current_data = 0;
+           b0->current_length = vec_len (fr->rewrite);
+           b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
+           vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
+           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+
+           tp = vlib_buffer_get_current (b0);
+           ip = &tp->ip4;
+           udp = &tp->udp;
+           h = &tp->ipfix.h;
+           s = &tp->ipfix.s;
+
+           /* FIXUP: message header export_time */
+           h->export_time = clib_host_to_net_u32 (((u32) time (NULL)));
+
+           /* FIXUP: message header sequence_number */
+           h->sequence_number = stream->sequence_number++;
+           h->sequence_number = clib_host_to_net_u32 (h->sequence_number);
+           next_offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
+           records_this_buffer = 0;
+         }
+
+       next_offset = ioam_analyse_add_ipfix_record (fr, record,
+                                                    b0, next_offset,
+                                                    &temp, &temp, 0, 0);
+       records_this_buffer++;
+
+       /* Flush data if packet len is about to reach path mtu */
+       if (next_offset > (frm->path_mtu - 250))
+         flush = 1;
+      }
+
+    if (PREDICT_FALSE (flush && b0))
+      {
+       s->set_id_length = ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID,
+                                               next_offset - (sizeof (*ip) +
+                                                              sizeof (*udp) +
+                                                              sizeof (*h)));
+       b0->current_length = next_offset;
+       b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
+       tp = vlib_buffer_get_current (b0);
+       ip = (ip4_header_t *) & tp->ip4;
+       udp = (udp_header_t *) (ip + 1);
+
+       sum0 = ip->checksum;
+       old_l0 = ip->length;
+       new_l0 = clib_host_to_net_u16 ((u16) next_offset);
+       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
+                              length /* changed member */ );
+
+       ip->checksum = ip_csum_fold (sum0);
+       ip->length = new_l0;
+       udp->length =
+         clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
+
+       if (frm->udp_checksum)
+         {
+           /* RFC 7011 section 10.3.2. */
+           udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
+           if (udp->checksum == 0)
+             udp->checksum = 0xffff;
+         }
+
+       to_next[0] = bi0;
+       f->n_vectors++;
+       to_next++;
+
+       if (f->n_vectors == VLIB_FRAME_SIZE)
+         {
+           vlib_put_frame_to_node (vm, node_index, f);
+           f = vlib_get_frame_to_node (vm, node_index);
+           f->n_vectors = 0;
+           to_next = vlib_frame_vector_args (f);
+         }
+       b0 = 0;
+       bi0 = ~0;
+      }
+  }
+
+  return f;
+}
+
+clib_error_t *
+ioam_flow_create (u8 del)
+{
+  vnet_flow_report_add_del_args_t args;
+  int rv;
+  u32 domain_id = 0;
+  flow_report_main_t *frm = &flow_report_main;
+
+  args.rewrite_callback = ioam_template_rewrite;
+  args.flow_data_callback = ioam_send_flows;
+  del ? (args.is_add = 0) : (args.is_add = 1);
+  args.domain_id = domain_id;
+
+  rv = vnet_flow_report_add_del (frm, &args);
+
+  switch (rv)
+    {
+    case 0:
+      break;
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      return clib_error_return (0, "registration not found...");
+    default:
+      return clib_error_return (0, "vnet_flow_report_add_del returned %d",
+                               rv);
+    }
+
+  return 0;
+}
+
+clib_error_t *
+ioam_flow_report_init (vlib_main_t * vm)
+{
+  clib_error_t *error;
+
+  if ((error = vlib_call_init_function (vm, flow_report_init)))
+    return error;
+
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (ioam_flow_report_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/analyse/ioam_summary_export.h b/src/plugins/ioam/analyse/ioam_summary_export.h
new file mode 100755 (executable)
index 0000000..9be31d2
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 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_flow_report_h__
+#define __included_ip6_ioam_flow_report_h__
+
+#include <ioam/analyse/ioam_analyse.h>
+#include <vnet/flow/flow_report.h>
+
+#define foreach_ioam_ipfix_info_element           \
+_(ioamPacketSent, 5239, u32)                     \
+_(ioamPacketCount, 5237, u32)                     \
+_(ioamByteCount, 5238, u32)                       \
+_(ioamPathMap, 5262, u32)                         \
+_(ioamNumberOfPaths, 5264, u16)                   \
+_(ioamSfcValidatedCount, 5278, u32)               \
+_(ioamSfcInValidatedCount, 5279, u32)             \
+_(ioamSeqnoRxCount, 5280, u32)                    \
+_(ioamSeqnoLostCount, 5281, u32)                  \
+_(ioamSeqnoReorderedCount, 5282, u32)             \
+_(ioamSeqnoDupCount, 5283, u32)
+
+
+typedef enum
+{
+#define _(n,v,t) n = v,
+  foreach_ioam_ipfix_info_element
+#undef _
+} ioam_ipfix_info_element_id_t;
+
+#define foreach_ioam_ipfix_field                                          \
+_(pkt_sent, 0xffffffff, ioamPacketSent, 4)                      \
+_(pkt_counter, 0xffffffff, ioamPacketCount, 4)                      \
+_(bytes_counter, 0xffffffff, ioamByteCount, 4)                      \
+_(pot_data.sfc_validated_count, 0xffffffff, ioamSfcValidatedCount, 4)     \
+_(pot_data.sfc_invalidated_count, 0xffffffff, ioamSfcInValidatedCount, 4) \
+_(seqno_data.rx_packets, 0xffffffff, ioamSeqnoRxCount, 4) \
+_(seqno_data.lost_packets, 0xffffffff, ioamSeqnoLostCount, 4) \
+_(seqno_data.reordered_packets, 0xffffffff, ioamSeqnoReorderedCount, 4) \
+_(seqno_data.dup_packets, 0xffffffff, ioamSeqnoDupCount, 4)
+
+clib_error_t *ioam_flow_report_init (vlib_main_t * vm);
+
+typedef struct
+{
+  u8 num_nodes;
+  u8 trace_type;
+  u16 reserve;
+  u32 mean_delay;
+  u32 pkt_counter;
+  u32 bytes_counter;
+  ioam_path_map_t path[IOAM_TRACE_MAX_NODES];
+} ioam_path;
+
+clib_error_t *ioam_flow_create (u8 del);
+
+u8 *ioam_template_rewrite (flow_report_main_t * frm, flow_report_t * fr,
+                          ip4_address_t * collector_address,
+                          ip4_address_t * src_address, u16 collector_port);
+
+u16 ioam_analyse_add_ipfix_record (flow_report_t * fr,
+                                  ioam_analyser_data_t * record,
+                                  vlib_buffer_t * b0, u16 offset,
+                                  ip6_address_t * src, ip6_address_t * dst,
+                                  u16 src_port, u16 dst_port);
+
+#endif /* __included_ip6_ioam_flow_report_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.c b/src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.c
new file mode 100644 (file)
index 0000000..c22ef0f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017 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 <ioam/analyse/ioam_analyse.h>
+#include <ioam/export-common/ioam_export.h>
+#include <ioam/analyse/ip6/ip6_ioam_analyse.h>
+#include <ioam/analyse/ioam_summary_export.h>
+#include <vnet/ip/ip.h>
+#include <ioam/ipfixcollector/ipfixcollector.h>
+
+static clib_error_t *
+ioam_analyse_enable_disable (vlib_main_t * vm,
+                            int is_add, int is_export, int remote_listen)
+{
+  ipfix_client_add_del_t ipfix_reg;
+  clib_error_t *rv = 0;
+
+  ipfix_reg.client_name = format (0, "ip6-hbh-analyse-remote");
+  ipfix_reg.client_node = analyse_node_remote.index;
+  ipfix_reg.ipfix_setid = IPFIX_IOAM_EXPORT_ID;
+
+  if (is_export)
+    {
+      rv = ioam_flow_create (!is_add);
+      if (rv)
+       goto ret;
+    }
+
+  if (is_add)
+    {
+      ip6_ioam_analyse_register_handlers ();
+      if (remote_listen)
+       {
+         ipfix_reg.del = 0;
+         ipfix_collector_reg_setid (vm, &ipfix_reg);
+       }
+      else
+       {
+         ioam_export_set_next_node (&ioam_export_main,
+                                    (u8 *) "ip6-hbh-analyse-local");
+       }
+    }
+  else
+    {
+      ip6_ioam_analyse_unregister_handlers ();
+      if (remote_listen)
+       {
+         ipfix_reg.del = 1;
+         ipfix_collector_reg_setid (vm, &ipfix_reg);
+       }
+      else
+       ioam_export_reset_next_node (&ioam_export_main);
+    }
+
+ret:
+  vec_free (ipfix_reg.client_name);
+  return rv;
+}
+
+static clib_error_t *
+set_ioam_analyse_command_fn (vlib_main_t * vm, unformat_input_t * input,
+                            vlib_cli_command_t * cmd)
+{
+  int is_export = 0;
+  int is_add = 1;
+  int remote_listen = 0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "export-ipfix-collector"))
+       is_export = 1;
+      else if (unformat (input, "disable"))
+       is_add = 0;
+      else if (unformat (input, "listen-ipfix"))
+       remote_listen = 1;
+      else
+       break;
+    }
+
+  return (ioam_analyse_enable_disable (vm, is_add, is_export, remote_listen));
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_ioam_analyse_command, static) = {
+  .path = "set ioam analyse",
+  .short_help = "set ioam analyse [export-ipfix-collector] [disable] [listen-ipfix]",
+  .function = set_ioam_analyse_command_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+show_ioam_analyse_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
+                         vlib_cli_command_t * cmd)
+{
+  ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
+  ioam_analyser_data_t *record = NULL;
+  u8 i;
+  u8 *s = 0;
+
+  vec_reset_length (s);
+  s = format (0, "iOAM Analyse Information: \n");
+  vec_foreach_index (i, am->aggregated_data)
+  {
+    record = am->aggregated_data + i;
+    if (record->is_free)
+      continue;
+
+    s = format (s, "Flow Number: %u\n", i);
+    s = print_analyse_flow (s, record);
+    s = format (s, "\n");
+  }
+  vlib_cli_output (vm, "%v", s);
+
+  vec_free (s);
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ip6_show_ioam_ipfix_cmd, static) = {
+  .path = "show ioam analyse ",
+  .short_help = "show ioam analyser information",
+  .function = show_ioam_analyse_cmd_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+ioam_analyse_init (vlib_main_t * vm)
+{
+  ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
+  u16 i;
+
+  vec_validate_aligned (am->aggregated_data, 50, CLIB_CACHE_LINE_BYTES);
+  vec_foreach_index (i, am->aggregated_data)
+  {
+    ioam_analyse_init_data (am->aggregated_data + i);
+  }
+
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (ioam_analyse_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.h b/src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.h
new file mode 100644 (file)
index 0000000..f6abdce
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 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 PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IP6_IOAM_ANALYSE_NODE_H_
+#define PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IP6_IOAM_ANALYSE_NODE_H_
+
+#include <ioam/analyse/ioam_analyse.h>
+#include <vnet/ip/ip6_hop_by_hop.h>
+
+/** @brief IP6-iOAM analyser main structure.
+    @note cache aligned.
+*/
+typedef struct
+{
+  /** Array of function pointer to analyse each hop-by-hop option. */
+  int (*analyse_hbh_handler[MAX_IP6_HBH_OPTION]) (u32 flow_id,
+                                                 ip6_hop_by_hop_option_t *
+                                                 opt, u16 len);
+
+  /** This contains the aggregated data from the time VPP started analysing. */
+  ioam_analyser_data_t *aggregated_data;
+
+} ip6_ioam_analyser_main_t;
+
+extern ip6_ioam_analyser_main_t ioam_analyser_main;
+
+extern vlib_node_registration_t analyse_node_local;
+extern vlib_node_registration_t analyse_node_remote;
+
+void ip6_ioam_analyse_register_handlers (void);
+
+void ip6_ioam_analyse_unregister_handlers (void);
+
+clib_error_t *ip6_ioam_analyse_init (vlib_main_t * vm);
+
+inline static ioam_analyser_data_t *
+ioam_analyse_get_data_from_flow_id (u32 flow_id)
+{
+  if (flow_id >= vec_len (ioam_analyser_main.aggregated_data))
+    return NULL;
+
+  if (ioam_analyser_main.aggregated_data[flow_id].is_free)
+    ioam_analyser_main.aggregated_data[flow_id].is_free = 0;
+
+  return (ioam_analyser_main.aggregated_data + flow_id);
+}
+
+#endif /* PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IP6_IOAM_ANALYSE_NODE_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/analyse/ip6/node.c b/src/plugins/ioam/analyse/ip6/node.c
new file mode 100644 (file)
index 0000000..6db6355
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2017 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 <vppinfra/error.h>
+#include <vnet/ip/ip.h>
+#include <ioam/export-common/ioam_export.h>
+#include <ioam/encap/ip6_ioam_trace.h>
+#include <ioam/encap/ip6_ioam_pot.h>
+#include <ioam/lib-pot/pot_util.h>
+#include <ioam/encap/ip6_ioam_e2e.h>
+#include <ioam/analyse/ioam_analyse.h>
+#include <ioam/analyse/ip6/ip6_ioam_analyse.h>
+#include <vnet/plugin/plugin.h>
+
+typedef struct
+{
+  u32 next_index;
+  u32 flow_id;
+} analyse_trace_t;
+
+vlib_node_registration_t analyse_node_local;
+vlib_node_registration_t analyse_node_remote;
+
+#define foreach_analyse_error \
+_(ANALYSED, "Packets analysed for summarization") \
+_(FAILED, "Packets analysis failed") \
+
+typedef enum
+{
+#define _(sym,str) ANALYSE_ERROR_##sym,
+  foreach_analyse_error
+#undef _
+    ANALYSE_N_ERROR,
+} analyse_error_t;
+
+static char *analyse_error_strings[] = {
+#define _(sym,string) string,
+  foreach_analyse_error
+#undef _
+};
+
+typedef enum
+{
+  ANALYSE_NEXT_IP4_LOOKUP,
+  ANALYSE_NEXT_IP4_DROP,
+  ANALYSE_N_NEXT,
+} analyse_next_t;
+
+ip6_ioam_analyser_main_t ioam_analyser_main;
+
+/* packet trace format function */
+static u8 *
+format_analyse_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  analyse_trace_t *t = va_arg (*args, analyse_trace_t *);
+
+  s = format (s, "IP6-ioam-analyse: flow_id %d, next index %d",
+             t->flow_id, t->next_index);
+  return s;
+}
+
+always_inline u8
+ioam_analyse_hbh (u32 flow_id,
+                 ip6_hop_by_hop_header_t * hbh0,
+                 ip6_hop_by_hop_option_t * opt0,
+                 ip6_hop_by_hop_option_t * limit0, u16 len)
+{
+  ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
+  u8 type0;
+  u8 error0 = 0;
+
+  while (opt0 < limit0)
+    {
+      type0 = opt0->type;
+      switch (type0)
+       {
+       case 0:         /* Pad1 */
+         opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
+         continue;
+       case 1:         /* PadN */
+         break;
+       default:
+         if (am->analyse_hbh_handler[type0])
+           {
+             if (PREDICT_TRUE
+                 ((*am->analyse_hbh_handler[type0]) (flow_id, opt0,
+                                                     len) < 0))
+               {
+                 error0 = ANALYSE_ERROR_FAILED;
+                 return (error0);
+               }
+           }
+       }
+      opt0 =
+       (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
+                                    sizeof (ip6_hop_by_hop_option_t));
+    }
+  return (error0);
+}
+
+/**
+ * @brief IPv6 InBandOAM Analyse node.
+ * @node ip6-hbh-analyse-local, ip6-hbh-analyse-remote
+ *
+ * This function receives IP-FIX packets containing IPv6-iOAM records, analyses
+ * them and collects/aggregates the statistics.
+ *
+ * @param vm    vlib_main_t corresponding to the current thread.
+ * @param node  vlib_node_runtime_t data for this node.
+ * @param frame vlib_frame_t whose contents should be dispatched.
+ *
+ * @par Graph mechanics: buffer, next index usage
+ *
+ * <em>Uses:</em>
+ * - <code>vlib_buffer_get_current(p0)</code>
+ *     - Walks on each ioam record present in IP-Fix record, analyse them and
+ *       store the statistics.
+ *
+ * <em>Next Index:</em>
+ * - Dispatches the packet to ip4-lookup if executed under ip6-hbh-analyse-local
+ *   node context and to ip4-drop if executed under ip6-hbh-analyse-remote node
+ *   context.
+ */
+static uword
+ip6_ioam_analyse_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                         vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  analyse_next_t next_index;
+  u32 pkts_analysed = 0;
+  u32 pkts_failed = 0;
+  u8 remote = 0;
+  u32 next0 = ANALYSE_NEXT_IP4_LOOKUP;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  if (PREDICT_FALSE (analyse_node_remote.index == node->node_index))
+    {
+      remote = 1;
+      next0 = ANALYSE_NEXT_IP4_DROP;
+    }
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 bi0;
+         vlib_buffer_t *p0;
+         ip4_header_t *ip40;
+         u8 *data, *limit;
+         u16 num_ioam_records;
+
+         /* speculatively enqueue p0 to the current next frame */
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         p0 = vlib_get_buffer (vm, bi0);
+         if (PREDICT_FALSE (remote))
+           {
+             vlib_buffer_advance (p0, -(word) (sizeof (udp_header_t) +
+                                               sizeof (ip4_header_t) +
+                                               sizeof
+                                               (ipfix_message_header_t) +
+                                               sizeof (ipfix_set_header_t)));
+           }
+         data = (u8 *) vlib_buffer_get_current (p0);
+         ip40 = (ip4_header_t *) vlib_buffer_get_current (p0);
+         limit = data + clib_net_to_host_u16 (ip40->length);
+         data += sizeof (ip4_header_t) + sizeof (udp_header_t)
+           + sizeof (ipfix_message_header_t) + sizeof (ipfix_set_header_t);
+
+         num_ioam_records = (limit - data) / DEFAULT_EXPORT_SIZE;
+
+         while (num_ioam_records >= 4)
+           {
+             /* Prefetch next 2 ioam records */
+             {
+               CLIB_PREFETCH (data + (2 * DEFAULT_EXPORT_SIZE),
+                              (DEFAULT_EXPORT_SIZE), LOAD);
+               CLIB_PREFETCH (data + (3 * DEFAULT_EXPORT_SIZE),
+                              (DEFAULT_EXPORT_SIZE), LOAD);
+             }
+
+             num_ioam_records -= 2;
+
+             ip6_header_t *ip60, *ip61;
+             ip6_hop_by_hop_header_t *hbh0, *hbh1;
+             ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
+             u32 flow_id0, flow_id1;
+             u8 error0, error1;
+             ioam_analyser_data_t *data0, *data1;
+             u16 p_len0, p_len1;
+
+             ip60 = (ip6_header_t *) data;
+             ip61 = (ip6_header_t *) (data + DEFAULT_EXPORT_SIZE);
+
+             data += (2 * DEFAULT_EXPORT_SIZE);
+
+             hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
+             hbh1 = (ip6_hop_by_hop_header_t *) (ip61 + 1);
+
+             opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
+             opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
+
+             limit0 =
+               (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
+                                            ((hbh0->length + 1) << 3));
+             limit1 =
+               (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
+                                            ((hbh1->length + 1) << 3));
+
+             flow_id0 =
+               clib_net_to_host_u32
+               (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
+             flow_id1 =
+               clib_net_to_host_u32
+               (ip61->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
+
+             p_len0 = clib_net_to_host_u16 (ip60->payload_length);
+             p_len1 = clib_net_to_host_u16 (ip61->payload_length);
+
+             error0 =
+               ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
+             error1 =
+               ioam_analyse_hbh (flow_id1, hbh1, opt1, limit1, p_len0);
+
+             if (PREDICT_TRUE ((error0 == 0) && (error1 == 0)))
+               {
+                 pkts_analysed += 2;
+                 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
+                 data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
+
+                 while (__sync_lock_test_and_set (data0->writer_lock, 1))
+                   ;
+                 data0->pkt_counter++;
+                 data0->bytes_counter += p_len0;
+                 *(data0->writer_lock) = 0;
+
+                 while (__sync_lock_test_and_set (data1->writer_lock, 1))
+                   ;
+                 data1->pkt_counter++;
+                 data1->bytes_counter += p_len1;
+                 *(data1->writer_lock) = 0;
+               }
+             else if (error0 == 0)
+               {
+                 pkts_analysed++;
+                 pkts_failed++;
+
+                 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
+                 while (__sync_lock_test_and_set (data0->writer_lock, 1))
+                   ;
+                 data0->pkt_counter++;
+                 data0->bytes_counter += p_len0;
+                 *(data0->writer_lock) = 0;
+               }
+             else if (error1 == 0)
+               {
+                 pkts_analysed++;
+                 pkts_failed++;
+
+                 data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
+                 while (__sync_lock_test_and_set (data1->writer_lock, 1))
+                   ;
+                 data1->pkt_counter++;
+                 data1->bytes_counter += p_len1;
+                 *(data1->writer_lock) = 0;
+               }
+             else
+               pkts_failed += 2;
+           }
+
+         while (num_ioam_records > 0)
+           {
+             num_ioam_records--;
+
+             ip6_header_t *ip60;
+             ip6_hop_by_hop_header_t *hbh0;
+             ip6_hop_by_hop_option_t *opt0, *limit0;
+             u32 flow_id0;
+             u8 error0;
+             ioam_analyser_data_t *data0;
+             u16 p_len0;
+
+             ip60 = (ip6_header_t *) data;
+             data += (1 * DEFAULT_EXPORT_SIZE);
+             hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
+             opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
+             limit0 =
+               (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
+                                            ((hbh0->length + 1) << 3));
+
+             flow_id0 =
+               clib_net_to_host_u32
+               (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
+             p_len0 = clib_net_to_host_u16 (ip60->payload_length);
+             error0 =
+               ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
+
+             if (PREDICT_TRUE (error0 == 0))
+               {
+                 pkts_analysed++;
+                 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
+                 while (__sync_lock_test_and_set (data0->writer_lock, 1))
+                   ;
+                 data0->pkt_counter++;
+                 data0->bytes_counter +=
+                   clib_net_to_host_u16 (ip60->payload_length);
+                 *(data0->writer_lock) = 0;
+               }
+             else
+               pkts_failed++;
+           }
+
+         /* verify speculative enqueue, maybe switch current next frame */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_ANALYSED,
+                              pkts_analysed);
+
+  if (PREDICT_FALSE (pkts_failed))
+    vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_FAILED,
+                                pkts_failed);
+
+  return frame->n_vectors;
+}
+
+int
+ip6_ioam_analyse_hbh_trace_internal (u32 flow_id,
+                                    ip6_hop_by_hop_option_t * opt, u16 len)
+{
+  ioam_analyser_data_t *data;
+  ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
+
+  data = ioam_analyse_get_data_from_flow_id (flow_id);
+  ASSERT (data != NULL);
+
+  (void) ip6_ioam_analyse_hbh_trace (data, &trace->trace_hdr, len,
+                                    (trace->hdr.length - 2)
+                                    /*ioam_trace_type,data_list_elts_left */
+    );
+  return 0;
+}
+
+int
+ip6_ioam_analyse_hbh_pot (u32 flow_id, ip6_hop_by_hop_option_t * opt0,
+                         u16 len)
+{
+
+  ioam_pot_option_t *pot0;
+  u64 random = 0;
+  u64 cumulative = 0;
+  pot_profile *pot_profile = 0;
+  int ret;
+  ioam_analyser_data_t *data;
+
+  data = ioam_analyse_get_data_from_flow_id (flow_id);
+
+  pot0 = (ioam_pot_option_t *) opt0;
+  random = clib_net_to_host_u64 (pot0->random);
+  cumulative = clib_net_to_host_u64 (pot0->cumulative);
+  pot_profile = pot_profile_get_active ();
+  ret = pot_validate (pot_profile, cumulative, random);
+
+  while (__sync_lock_test_and_set (data->writer_lock, 1))
+    ;
+
+  (0 == ret) ? (data->pot_data.sfc_validated_count++) :
+    (data->pot_data.sfc_invalidated_count++);
+
+  *(data->writer_lock) = 0;
+  return 0;
+}
+
+int
+ip6_ioam_analyse_hbh_e2e_internal (u32 flow_id, ip6_hop_by_hop_option_t * opt,
+                                  u16 len)
+{
+  ioam_analyser_data_t *data;
+  ioam_e2e_option_t *e2e;
+
+  data = ioam_analyse_get_data_from_flow_id (flow_id);
+  e2e = (ioam_e2e_option_t *) opt;
+  ip6_ioam_analyse_hbh_e2e (data, &e2e->e2e_hdr, len);
+  return 0;
+}
+
+int
+ip6_ioam_analyse_register_hbh_handler (u8 option,
+                                      int options (u32 flow_id,
+                                                   ip6_hop_by_hop_option_t *
+                                                   opt, u16 len))
+{
+  ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
+
+  ASSERT (option < ARRAY_LEN (am->analyse_hbh_handler));
+
+  /* Already registered */
+  if (am->analyse_hbh_handler[option])
+    return (-1);
+
+  am->analyse_hbh_handler[option] = options;
+
+  return (0);
+}
+
+int
+ip6_ioam_analyse_unregister_hbh_handler (u8 option)
+{
+  ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
+
+  ASSERT (option < ARRAY_LEN (am->analyse_hbh_handler));
+
+  /* Not registered */
+  if (!am->analyse_hbh_handler[option])
+    return (-1);
+
+  am->analyse_hbh_handler[option] = NULL;
+  return (0);
+}
+
+void
+ip6_ioam_analyse_register_handlers ()
+{
+  ip6_ioam_analyse_register_hbh_handler (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST,
+                                        ip6_ioam_analyse_hbh_trace_internal);
+  ip6_ioam_analyse_register_hbh_handler
+    (HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_ioam_analyse_hbh_pot);
+  ip6_ioam_analyse_register_hbh_handler (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
+                                        ip6_ioam_analyse_hbh_e2e_internal);
+}
+
+void
+ip6_ioam_analyse_unregister_handlers ()
+{
+  ip6_ioam_analyse_unregister_hbh_handler
+    (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST);
+  ip6_ioam_analyse_unregister_hbh_handler
+    (HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT);
+  ip6_ioam_analyse_unregister_hbh_handler (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE);
+}
+
+/* *INDENT-OFF* */
+
+/*
+ * Node for IP6 analyse - packets
+ */
+VLIB_REGISTER_NODE (analyse_node_local) = {
+  .function = ip6_ioam_analyse_node_fn,
+  .name = "ip6-hbh-analyse-local",
+  .vector_size = sizeof (u32),
+  .format_trace = format_analyse_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (analyse_error_strings),
+  .error_strings = analyse_error_strings,
+  .n_next_nodes = ANALYSE_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
+  },
+};
+
+/*
+ * Node for IP6 analyse - packets
+ */
+VLIB_REGISTER_NODE (analyse_node_remote) =
+{
+  .function = ip6_ioam_analyse_node_fn,
+  .name = "ip6-hbh-analyse-remote",
+  .vector_size = sizeof (u32),
+  .format_trace = format_analyse_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (analyse_error_strings),
+  .error_strings = analyse_error_strings,
+  .n_next_nodes = ANALYSE_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
+  },
+};
+
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 2831a35..cdaf740 100644 (file)
@@ -37,7 +37,7 @@ static u8 * ioam_e2e_trace_handler (u8 * s,
 
   if (e2e)
     {
-      seqno = clib_net_to_host_u32 (e2e->e2e_data);
+      seqno = clib_net_to_host_u32 (e2e->e2e_hdr.e2e_data);
     }
 
   s = format (s, "SeqNo = 0x%Lx", seqno);
@@ -108,7 +108,7 @@ ioam_e2e_flow_handler (u32 ctx, u8 add)
     {
       pool_get(ioam_e2e_main.e2e_data, data);
       data->flow_ctx =  ctx;
-      ioam_seqno_init_bitmap(&data->seqno_data);
+      ioam_seqno_init_data(&data->seqno_data);
       return ((u32) (data - ioam_e2e_main.e2e_data));
     }
 
index 18f35f8..fcec4a1 100644 (file)
 #ifndef __included_ip6_ioam_e2e_h__
 #define __included_ip6_ioam_e2e_h__
 
+#include "../lib-e2e/e2e_util.h"
 #include "ip6_ioam_seqno.h"
 
+/* *INDENT-OFF* */
+typedef CLIB_PACKED(struct {
+  ip6_hop_by_hop_option_t hdr;
+  ioam_e2e_packet_t e2e_hdr;
+}) ioam_e2e_option_t;
+/* *INDENT-ON* */
+
 typedef struct ioam_e2e_data_t_ {
   u32 flow_ctx;
   u32 pad;
@@ -44,4 +52,13 @@ ioam_e2ec_get_seqno_data_from_flow_ctx (u32 flow_ctx)
   return &(data->seqno_data);
 }
 
+static inline u32
+ioam_e2e_get_cur_seqno_from_flow_ctx (u32 flow_ctx)
+{
+  ioam_seqno_data *data = NULL;
+
+  data =  ioam_e2ec_get_seqno_data_from_flow_ctx(flow_ctx);
+  return data->seq_num;
+}
+
 #endif /* __included_ioam_e2e_h__ */
index 05f42c9..9a76123 100644 (file)
 #include <vnet/vnet.h>
 #include <vnet/pg/pg.h>
 #include <vppinfra/error.h>
-
 #include <vnet/ip/ip6.h>
-#include <vnet/ip/ip6_hop_by_hop.h>
-#include <vnet/ip/ip6_hop_by_hop_packet.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
 #include <vppinfra/elog.h>
 
+#include <ioam/encap/ip6_ioam_pot.h>
 #include <ioam/lib-pot/pot_util.h>
 
-typedef CLIB_PACKED(struct {
-  ip6_hop_by_hop_option_t hdr;
-  u8 pot_type;
-#define PROFILE_ID_MASK 0xF
-  u8 reserved_profile_id; /* 4 bits reserved, 4 bits to carry profile id */
-  u64 random;
-  u64 cumulative;
-}) ioam_pot_option_t;
-
 #define foreach_ip6_hop_by_hop_ioam_pot_stats                          \
   _(PROCESSED, "Pkts with ip6 hop-by-hop pot options")                 \
   _(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \
@@ -180,19 +169,19 @@ ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip,
   int rv = 0;
   pot_profile *pot_profile = 0;
   u8 result = 0;
-  
+
   pot0 = (ioam_pot_option_t *) opt0;
   random = clib_net_to_host_u64(pot0->random);
   cumulative = clib_net_to_host_u64(pot0->cumulative);
   pot_profile = pot_profile_get_active();
   result =  pot_validate (pot_profile,
                          cumulative, random);
-         
-  if (result == 1) 
+
+  if (result == 1)
     {
       ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1);
     }
-  else 
+  else
     {
       ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1);
     }
diff --git a/src/plugins/ioam/encap/ip6_ioam_pot.h b/src/plugins/ioam/encap/ip6_ioam_pot.h
new file mode 100644 (file)
index 0000000..01ce4ac
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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 PLUGINS_IOAM_PLUGIN_IOAM_ENCAP_IP6_IOAM_POT_H_
+#define PLUGINS_IOAM_PLUGIN_IOAM_ENCAP_IP6_IOAM_POT_H_
+
+#include <vnet/ip/ip6_hop_by_hop_packet.h>
+
+/* *INDENT-OFF* */
+typedef CLIB_PACKED (struct {
+  ip6_hop_by_hop_option_t hdr;
+  u8 pot_type;
+  #define PROFILE_ID_MASK 0xF
+  u8 reserved_profile_id;      /* 4 bits reserved, 4 bits to carry profile id */
+  u64 random;
+  u64 cumulative;
+}) ioam_pot_option_t;
+/* *INDENT-ON* */
+
+#endif /* PLUGINS_IOAM_PLUGIN_IOAM_ENCAP_IP6_IOAM_POT_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 0b4d419..0197712 100644 (file)
 #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.
@@ -60,7 +46,7 @@ ioam_seqno_encap_handler (vlib_buffer_t *b, ip6_header_t *ip,
 
   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);
+  e2e->e2e_hdr.e2e_data = clib_host_to_net_u32(++data->seq_num);
 
   return (rv);
 }
@@ -79,31 +65,8 @@ ioam_seqno_decap_handler (vlib_buffer_t *b, ip6_header_t *ip,
 
   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));
+  ioam_analyze_seqno(&data->seqno_rx,
+                     (u64) clib_net_to_host_u32(e2e->e2e_hdr.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;
-}
index 13a84db..5c14024 100644 (file)
 
 #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);
+#include <ioam/lib-e2e/e2e_util.h>
 
 int ioam_seqno_encap_handler(vlib_buffer_t *b, ip6_header_t *ip,
                              ip6_hop_by_hop_option_t *opt);
@@ -62,9 +27,4 @@ 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/src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c b/src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c
deleted file mode 100644 (file)
index 4638871..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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 a836dfe..6972ba4 100644 (file)
@@ -27,7 +27,7 @@
 #include <vppinfra/elog.h>
 #include <vnet/plugin/plugin.h>
 
-#include <ioam/lib-trace/trace_util.h>
+#include <ioam/encap/ip6_ioam_trace.h>
 
 /* Timestamp precision multipliers for seconds, milliseconds, microseconds
  * and nanoseconds respectively.
@@ -40,15 +40,6 @@ typedef union
   u32 as_u32[2];
 } time_u64_t;
 
-/* *INDENT-OFF* */
-typedef CLIB_PACKED(struct {
-  ip6_hop_by_hop_option_t hdr;
-  u8 ioam_trace_type;
-  u8 data_list_elts_left;
-  u32 elts[0]; /* Variable type. So keep it generic */
-}) ioam_trace_option_t;
-/* *INDENT-ON* */
-
 
 extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main;
 extern ip6_main_t ip6_main;
@@ -201,8 +192,9 @@ ip6_hop_by_hop_ioam_trace_rewrite_handler (u8 * rewrite_string,
     HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
   trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */  +
     trace_option_elts * trace_data_size;
-  trace_option->ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK;
-  trace_option->data_list_elts_left = trace_option_elts;
+  trace_option->trace_hdr.ioam_trace_type =
+    profile->trace_type & TRACE_TYPE_MASK;
+  trace_option->trace_hdr.data_list_elts_left = trace_option_elts;
   *rewrite_size =
     sizeof (ioam_trace_option_t) + (trace_option_elts * trace_data_size);
 
@@ -238,24 +230,24 @@ ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip,
 
   time_u64.as_u64 = 0;
 
-  if (PREDICT_TRUE (trace->data_list_elts_left))
+  if (PREDICT_TRUE (trace->trace_hdr.data_list_elts_left))
     {
-      trace->data_list_elts_left--;
+      trace->trace_hdr.data_list_elts_left--;
       /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes
        * to skip to this node's location.
        */
       elt_index =
-       trace->data_list_elts_left *
-       fetch_trace_data_size (trace->ioam_trace_type) / 4;
-      elt = &trace->elts[elt_index];
-      if (trace->ioam_trace_type & BIT_TTL_NODEID)
+       trace->trace_hdr.data_list_elts_left *
+       fetch_trace_data_size (trace->trace_hdr.ioam_trace_type) / 4;
+      elt = &trace->trace_hdr.elts[elt_index];
+      if (trace->trace_hdr.ioam_trace_type & BIT_TTL_NODEID)
        {
          *elt =
            clib_host_to_net_u32 ((ip->hop_limit << 24) | profile->node_id);
          elt++;
        }
 
-      if (trace->ioam_trace_type & BIT_ING_INTERFACE)
+      if (trace->trace_hdr.ioam_trace_type & BIT_ING_INTERFACE)
        {
          *elt =
            (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 |
@@ -264,7 +256,7 @@ ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip,
          elt++;
        }
 
-      if (trace->ioam_trace_type & BIT_TIMESTAMP)
+      if (trace->trace_hdr.ioam_trace_type & BIT_TIMESTAMP)
        {
          /* Send least significant 32 bits */
          f64 time_f64 =
@@ -276,7 +268,7 @@ ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip,
          elt++;
        }
 
-      if (trace->ioam_trace_type & BIT_APPDATA)
+      if (trace->trace_hdr.ioam_trace_type & BIT_APPDATA)
        {
          /* $$$ set elt0->app_data */
          *elt = clib_host_to_net_u32 (profile->app_data);
@@ -302,17 +294,19 @@ ip6_hbh_ioam_trace_data_list_trace_handler (u8 * s,
 
   trace = (ioam_trace_option_t *) opt;
   s =
-    format (s, "  Trace Type 0x%x , %d elts left\n", trace->ioam_trace_type,
-           trace->data_list_elts_left);
+    format (s, "  Trace Type 0x%x , %d elts left\n",
+           trace->trace_hdr.ioam_trace_type,
+           trace->trace_hdr.data_list_elts_left);
   trace_data_size_in_words =
-    fetch_trace_data_size (trace->ioam_trace_type) / 4;
-  elt = &trace->elts[0];
-  while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->hdr.length - 2
-                      /* -2 accounts for ioam_trace_type,elts_left */ ))
+    fetch_trace_data_size (trace->trace_hdr.ioam_trace_type) / 4;
+  elt = &trace->trace_hdr.elts[0];
+  while ((u8 *) elt <
+        ((u8 *) (&trace->trace_hdr.elts[0]) + trace->hdr.length - 2
+         /* -2 accounts for ioam_trace_type,elts_left */ ))
     {
       s = format (s, "    [%d] %U\n", elt_index,
                  format_ioam_data_list_element,
-                 elt, &trace->ioam_trace_type);
+                 elt, &trace->trace_hdr.ioam_trace_type);
       elt_index++;
       elt += trace_data_size_in_words;
     }
diff --git a/src/plugins/ioam/encap/ip6_ioam_trace.h b/src/plugins/ioam/encap/ip6_ioam_trace.h
new file mode 100644 (file)
index 0000000..b332b31
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 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 PLUGINS_IOAM_PLUGIN_IOAM_ENCAP_IP6_IOAM_TRACE_H_
+#define PLUGINS_IOAM_PLUGIN_IOAM_ENCAP_IP6_IOAM_TRACE_H_
+
+#include <vnet/ip/ip6_hop_by_hop_packet.h>
+#include <ioam/lib-trace/trace_util.h>
+
+/* *INDENT-OFF* */
+typedef CLIB_PACKED(struct {
+  ip6_hop_by_hop_option_t hdr;
+  ioam_trace_hdr_t trace_hdr;
+}) ioam_trace_option_t;
+/* *INDENT-ON* */
+
+
+#endif /* PLUGINS_IOAM_PLUGIN_IOAM_ENCAP_IP6_IOAM_TRACE_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index e6ab034..e84dab0 100644 (file)
@@ -20,6 +20,7 @@
 #include <vnet/ip/ip_packet.h>
 #include <vnet/ip/ip4_packet.h>
 #include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip6_hop_by_hop.h>
 #include <vnet/ip/udp.h>
 #include <vnet/flow/ipfix_packet.h>
 
@@ -43,6 +44,7 @@ typedef struct
 {
   /* API message ID base */
   u16 msg_id_base;
+  u16 set_id;
 
   /* TODO: to support multiple collectors all this has to be grouped and create a vector here */
   u8 *record_header;
@@ -67,14 +69,15 @@ typedef struct
   /* convenience */
   vlib_main_t *vlib_main;
   vnet_main_t *vnet_main;
-  u32 ip4_lookup_node_index;
+  ethernet_main_t *ethernet_main;
+  u32 next_node_index;
 
   uword my_hbh_slot;
   u32 export_process_node_index;
 } ioam_export_main_t;
 
-ioam_export_main_t ioam_export_main;
-ioam_export_main_t vxlan_gpe_ioam_export_main;
+extern ioam_export_main_t ioam_export_main;
+extern ioam_export_main_t vxlan_gpe_ioam_export_main;
 
 extern vlib_node_registration_t export_node;
 extern vlib_node_registration_t vxlan_export_node;
@@ -86,6 +89,24 @@ extern vlib_node_registration_t vxlan_export_node;
  */
 #define DEFAULT_EXPORT_RECORDS 7
 
+inline static void
+ioam_export_set_next_node (ioam_export_main_t * em, u8 * next_node_name)
+{
+  vlib_node_t *next_node;
+
+  next_node = vlib_get_node_by_name (em->vlib_main, next_node_name);
+  em->next_node_index = next_node->index;
+}
+
+inline static void
+ioam_export_reset_next_node (ioam_export_main_t * em)
+{
+  vlib_node_t *next_node;
+
+  next_node = vlib_get_node_by_name (em->vlib_main, (u8 *) "ip4-lookup");
+  em->next_node_index = next_node->index;
+}
+
 always_inline ioam_export_buffer_t *
 ioam_export_get_my_buffer (ioam_export_main_t * em, u32 thread_id)
 {
@@ -154,15 +175,13 @@ ioam_export_thread_buffer_init (ioam_export_main_t * em, vlib_main_t * vm)
   int no_of_threads = vec_len (vlib_worker_threads);
   int i;
   ioam_export_buffer_t *eb = 0;
-  vlib_node_t *ip4_lookup_node;
 
   pool_alloc_aligned (em->buffer_pool,
                      no_of_threads - 1, CLIB_CACHE_LINE_BYTES);
   vec_validate_aligned (em->buffer_per_thread,
                        no_of_threads - 1, CLIB_CACHE_LINE_BYTES);
   vec_validate_aligned (em->lockp, no_of_threads - 1, CLIB_CACHE_LINE_BYTES);
-  ip4_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
-  em->ip4_lookup_node_index = ip4_lookup_node->index;
+
   if (!em->buffer_per_thread || !em->buffer_pool || !em->lockp)
     {
       return (-1);
@@ -186,6 +205,7 @@ ioam_export_thread_buffer_init (ioam_export_main_t * em, vlib_main_t * vm)
 }
 
 #define IPFIX_IOAM_EXPORT_ID 272
+#define IPFIX_VXLAN_IOAM_EXPORT_ID 273
 
 /* Used to build the rewrite */
 /* data set packet */
@@ -241,8 +261,8 @@ ioam_export_header_create (ioam_export_main_t * em,
   ip->protocol = IP_PROTOCOL_UDP;
   ip->src_address.as_u32 = src_address->as_u32;
   ip->dst_address.as_u32 = collector_address->as_u32;
-  udp->src_port = clib_host_to_net_u16 (4939 /* $$FIXME */ );
-  udp->dst_port = clib_host_to_net_u16 (4939);
+  udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
+  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
   /* FIXUP: UDP length */
   udp->length = clib_host_to_net_u16 (vec_len (rewrite) +
                                      (DEFAULT_EXPORT_RECORDS *
@@ -253,7 +273,7 @@ ioam_export_header_create (ioam_export_main_t * em,
   h->domain_id = clib_host_to_net_u32 (em->domain_id);
 
   /*FIXUP: Setid length in octets if records exported are not default */
-  s->set_id_length = ipfix_set_id_length (IPFIX_IOAM_EXPORT_ID,
+  s->set_id_length = ipfix_set_id_length (em->set_id,
                                          (sizeof (*s) +
                                           (DEFAULT_EXPORT_RECORDS *
                                            DEFAULT_EXPORT_SIZE)));
@@ -309,11 +329,10 @@ ioam_export_send_buffer (ioam_export_main_t * em, vlib_main_t * vm,
   /* FIXUP: lengths if different from default */
   if (PREDICT_FALSE (eb->records_in_this_buffer != DEFAULT_EXPORT_RECORDS))
     {
-      s->set_id_length =
-       ipfix_set_id_length (IPFIX_IOAM_EXPORT_ID /* set_id */ ,
-                            b0->current_length - (sizeof (*ip) +
-                                                  sizeof (*udp) +
-                                                  sizeof (*h)));
+      s->set_id_length = ipfix_set_id_length (em->set_id /* set_id */ ,
+                                             b0->current_length -
+                                             (sizeof (*ip) + sizeof (*udp) +
+                                              sizeof (*h)));
       h->version_length =
        version_length (b0->current_length - (sizeof (*ip) + sizeof (*udp)));
       sum0 = ip->checksum;
@@ -328,12 +347,12 @@ ioam_export_send_buffer (ioam_export_main_t * em, vlib_main_t * vm,
 
   /* Enqueue pkts to ip4-lookup */
 
-  nf = vlib_get_frame_to_node (vm, em->ip4_lookup_node_index);
+  nf = vlib_get_frame_to_node (vm, em->next_node_index);
   nf->n_vectors = 0;
   to_next = vlib_frame_vector_args (nf);
   nf->n_vectors = 1;
   to_next[0] = eb->buffer_index;
-  vlib_put_frame_to_node (vm, em->ip4_lookup_node_index, nf);
+  vlib_put_frame_to_node (vm, em->next_node_index, nf);
   return (1);
 
 }
@@ -452,7 +471,7 @@ ioam_export_process_common (ioam_export_main_t * em, vlib_main_t * vm,
   return 0;                    /* not so much */
 }
 
-#define ioam_export_node_common(EM, VM, N, F, HTYPE, L, V, NEXT)               \
+#define ioam_export_node_common(EM, VM, N, F, HTYPE, L, V, NEXT, FIXUP_FUNC)   \
 do {                                                                           \
   u32 n_left_from, *from, *to_next;                                            \
   export_next_t next_index;                                                    \
@@ -510,6 +529,7 @@ do {                                                                           \
          ip_len1 =                                                            \
            ip_len1 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len1;     \
          copy3cachelines (eb0->data + eb0->current_length, ip0, ip_len0);     \
+         FIXUP_FUNC(eb0, p0);                                                 \
          eb0->current_length += DEFAULT_EXPORT_SIZE;                          \
          my_buf->records_in_this_buffer++;                                    \
          if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS)        \
@@ -522,6 +542,7 @@ do {                                                                           \
          if (PREDICT_FALSE (eb0 == 0))                                        \
            goto NO_BUFFER1;                                                   \
          copy3cachelines (eb0->data + eb0->current_length, ip1, ip_len1);     \
+         FIXUP_FUNC(eb0, p1);                                                 \
          eb0->current_length += DEFAULT_EXPORT_SIZE;                          \
          my_buf->records_in_this_buffer++;                                    \
          if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS)        \
@@ -578,6 +599,7 @@ do {                                                                           \
          ip_len0 =                                                            \
            ip_len0 > DEFAULT_EXPORT_SIZE ? DEFAULT_EXPORT_SIZE : ip_len0;     \
          copy3cachelines (eb0->data + eb0->current_length, ip0, ip_len0);     \
+         FIXUP_FUNC(eb0, p0);                                                 \
          eb0->current_length += DEFAULT_EXPORT_SIZE;                          \
          my_buf->records_in_this_buffer++;                                    \
          if (my_buf->records_in_this_buffer >= DEFAULT_EXPORT_RECORDS)        \
index 0924d68..f05b530 100644 (file)
@@ -83,6 +83,8 @@ do {                                                            \
 #define foreach_vxlan_gpe_ioam_export_plugin_api_msg                        \
 _(VXLAN_GPE_IOAM_EXPORT_ENABLE_DISABLE, vxlan_gpe_ioam_export_enable_disable)
 
+ioam_export_main_t vxlan_gpe_ioam_export_main;
+
 extern void vxlan_gpe_set_next_override (uword next);
 /* Action function shared between message handler and debug CLI */
 int
@@ -242,6 +244,8 @@ vxlan_gpe_ioam_export_init (vlib_main_t * vm)
   clib_error_t *error = 0;
   u8 *name;
 
+  em->set_id = IPFIX_VXLAN_IOAM_EXPORT_ID;
+
   name = format (0, "vxlan_gpe_ioam_export_%08x%c", api_version, 0);
 
   /* Ask for a correctly-sized block of API message decode slots */
@@ -254,6 +258,7 @@ vxlan_gpe_ioam_export_init (vlib_main_t * vm)
   em->my_hbh_slot = ~0;
   em->vlib_main = vm;
   em->vnet_main = vnet_get_main ();
+  ioam_export_reset_next_node (em);
   vec_free (name);
 
   return error;
index f75b708..8120f4a 100644 (file)
@@ -17,9 +17,9 @@
 #include <vnet/pg/pg.h>
 #include <vppinfra/error.h>
 #include <vnet/ip/ip.h>
-#include <ioam/export-common/ioam_export.h>
 #include <vnet/vxlan-gpe/vxlan_gpe.h>
 #include <vnet/vxlan-gpe/vxlan_gpe_packet.h>
+#include <ioam/export-common/ioam_export.h>
 
 typedef struct
 {
@@ -121,6 +121,12 @@ copy3cachelines (void *dst, const void *src, size_t n)
 #endif
 }
 
+static void
+vxlan_gpe_export_fixup_func (vlib_buffer_t * export_buf,
+                            vlib_buffer_t * pak_buf)
+{
+  /* Todo: on implementing VXLAN GPE analyse */
+}
 
 static uword
 vxlan_gpe_export_node_fn (vlib_main_t * vm,
@@ -129,7 +135,8 @@ vxlan_gpe_export_node_fn (vlib_main_t * vm,
   ioam_export_main_t *em = &vxlan_gpe_ioam_export_main;
   ioam_export_node_common (em, vm, node, frame, ip4_header_t, length,
                           ip_version_and_header_length,
-                          EXPORT_NEXT_VXLAN_GPE_INPUT);
+                          EXPORT_NEXT_VXLAN_GPE_INPUT,
+                          vxlan_gpe_export_fixup_func);
   return frame->n_vectors;
 }
 
index 06634ba..1112ce4 100644 (file)
@@ -81,6 +81,10 @@ do {                                                            \
 #define foreach_ioam_export_plugin_api_msg                        \
 _(IOAM_EXPORT_IP6_ENABLE_DISABLE, ioam_export_ip6_enable_disable)
 
+ioam_export_main_t ioam_export_main;
+
+vlib_node_registration_t export_node;
+
 /* Action function shared between message handler and debug CLI */
 
 int
@@ -232,6 +236,8 @@ ioam_export_init (vlib_main_t * vm)
 
   em->vlib_main = vm;
   em->vnet_main = vnet_get_main ();
+  em->set_id = IPFIX_IOAM_EXPORT_ID;
+  ioam_export_reset_next_node (em);
 
   name = format (0, "ioam_export_%08x%c", api_version, 0);
 
index 19f143d..b32d784 100644 (file)
 #include <vnet/pg/pg.h>
 #include <vppinfra/error.h>
 #include <vnet/ip/ip.h>
+#include <vnet/ip/ip6_hop_by_hop.h>
 #include <ioam/export-common/ioam_export.h>
 
+
 typedef struct
 {
   u32 next_index;
@@ -119,6 +121,20 @@ copy3cachelines (void *dst, const void *src, size_t n)
 #endif
 }
 
+static void
+ip6_export_fixup_func (vlib_buffer_t * export_buf, vlib_buffer_t * pak_buf)
+{
+  ip6_header_t *ip6_temp =
+      (ip6_header_t *) (export_buf->data + export_buf->current_length);
+  u32 flow_label_temp =
+      clib_net_to_host_u32(ip6_temp->ip_version_traffic_class_and_flow_label)
+      & 0xFFF00000;
+  flow_label_temp |=
+      IOAM_MASK_DECAP_BIT((vnet_buffer(pak_buf)->l2_classify.opaque_index));
+  ip6_temp->ip_version_traffic_class_and_flow_label =
+      clib_host_to_net_u32(flow_label_temp);
+}
+
 static uword
 ip6_export_node_fn (vlib_main_t * vm,
                    vlib_node_runtime_t * node, vlib_frame_t * frame)
@@ -126,7 +142,7 @@ ip6_export_node_fn (vlib_main_t * vm,
   ioam_export_main_t *em = &ioam_export_main;
   ioam_export_node_common(em, vm, node, frame, ip6_header_t, payload_length,
                           ip_version_traffic_class_and_flow_label, 
-                          EXPORT_NEXT_POP_HBYH);
+                          EXPORT_NEXT_POP_HBYH, ip6_export_fixup_func);
   return frame->n_vectors;
 }
 
diff --git a/src/plugins/ioam/ipfixcollector/ipfixcollector.c b/src/plugins/ioam/ipfixcollector/ipfixcollector.c
new file mode 100644 (file)
index 0000000..4ae47ed
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 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/ip/ip.h>
+#include <vnet/plugin/plugin.h>
+#include <vnet/ip/udp.h>
+#include <ioam/ipfixcollector/ipfixcollector.h>
+
+ipfix_collector_main_t ipfix_collector_main;
+
+/**
+ * @brief IP-FIX SetID registration function.
+ *
+ * This function can be used by other VPP graph nodes to receive IP-FIX packets
+ * with a particular setid.
+ *
+ * @param vlib_main_t Vlib main of the graph node which is interseted in
+ *                    getting IP-Fix packet.
+ * @param ipfix_client_add_del_t Structure describing the client node which
+ *                               is interested in getting the IP-Fix packets for
+ *                               a SetID.
+ *
+ * @returns 0 on success.
+ * @returns Error codes(<0) otherwise.
+ */
+int
+ipfix_collector_reg_setid (vlib_main_t * vm, ipfix_client_add_del_t * info)
+{
+  ipfix_collector_main_t *cm = &ipfix_collector_main;
+  uword *p = NULL;
+  int i;
+  ipfix_client *client = 0;
+
+  if ((!info) || (!info->client_name))
+    return IPFIX_COLLECTOR_ERR_INVALID_PARAM;
+
+  p = hash_get (cm->client_reg_table, info->ipfix_setid);
+  client = p ? pool_elt_at_index (cm->client_reg_pool, (*p)) : NULL;
+
+  if (info->del)
+    {
+      if (!client)
+       return 0;               //There is no registered handler, so send success
+
+      hash_unset (cm->client_reg_table, info->ipfix_setid);
+      vec_free (client->client_name);
+      pool_put (cm->client_reg_pool, client);
+      return 0;
+    }
+
+  if (client)
+    return IPFIX_COLLECTOR_ERR_REG_EXISTS;
+
+  pool_get (cm->client_reg_pool, client);
+  i = client - cm->client_reg_pool;
+  client->client_name = vec_dup (info->client_name);
+  client->client_node = info->client_node;
+  client->client_next_node = vlib_node_add_next (vm,
+                                                ipfix_collector_node.index,
+                                                client->client_node);
+  client->set_id = info->ipfix_setid;
+
+  hash_set (cm->client_reg_table, info->ipfix_setid, i);
+  return 0;
+}
+
+static clib_error_t *
+ipfix_collector_init (vlib_main_t * vm)
+{
+  clib_error_t *error = 0;
+  ipfix_collector_main_t *cm = &ipfix_collector_main;
+
+  cm->vlib_main = vm;
+  cm->vnet_main = vnet_get_main ();
+
+  cm->client_reg_pool = NULL;
+  cm->client_reg_table = hash_create (0, sizeof (uword));
+
+  udp_register_dst_port (vm,
+                        UDP_DST_PORT_ipfix,
+                        ipfix_collector_node.index, 1 /* is_ip4 */ );
+  return error;
+}
+
+VLIB_INIT_FUNCTION (ipfix_collector_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/ipfixcollector/ipfixcollector.h b/src/plugins/ioam/ipfixcollector/ipfixcollector.h
new file mode 100644 (file)
index 0000000..ee57031
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017 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 PLUGINS_IPFIXCOLLECTOR_PLUGIN_IPFIXCOLLECTOR_IPFIXCOLLECTOR_H_
+#define PLUGINS_IPFIXCOLLECTOR_PLUGIN_IPFIXCOLLECTOR_IPFIXCOLLECTOR_H_
+
+#include <vppinfra/pool.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+
+#define IPFIX_COLLECTOR_CLIENT_NAME_MAX 64
+
+#define IPFIX_COLLECTOR_ERR_INVALID_PARAM -1
+#define IPFIX_COLLECTOR_ERR_REG_EXISTS -2
+
+/** @brief Structure other nodes to use for registering with IP-FIX collector.
+*/
+typedef struct
+{
+  /** String containing name of the client interested in getting
+      ip-fix packets. */
+  u8 *client_name;
+
+  /** Node index where packets have to be redirected. */
+  u32 client_node;
+
+  /** Setid of IPFix for which client is intereseted in getting packets. */
+  u16 ipfix_setid;
+
+  /** Add(0) or del(1) operation. */
+  u16 del;
+} ipfix_client_add_del_t;
+
+/** @brief IP-FIX collector internal client structure to store SetID to
+     client node ID.
+*/
+typedef struct
+{
+  /** String containing name of the client interested in getting
+        ip-fix packets. */
+  u8 *client_name;
+
+  /** Node index where packets have to be redirected. */
+  u32 client_node;
+
+  /** ipfix-collector next index where packets have to be redirected. */
+  u32 client_next_node;
+
+  /** Setid of IPFix for which client is intereseted in getting packets. */
+  u16 set_id;
+} ipfix_client;
+
+/** @brief IP-FIX collector main structure to SetID to client node ID mapping.
+    @note cache aligned.
+*/
+typedef struct
+{
+  /** Hash table to map IP-FIX setid to a client registration pool. SetId is
+      key to hash map. */
+  uword *client_reg_table;
+
+  /** Pool of Client node information for the IP-FIX SetID. */
+  ipfix_client *client_reg_pool;
+
+  /** Pointer to VLib main for the node - ipfix-collector. */
+  vlib_main_t *vlib_main;
+
+  /** Pointer to vnet main for convenience. */
+  vnet_main_t *vnet_main;
+} ipfix_collector_main_t;
+
+extern vlib_node_registration_t ipfix_collector_node;
+
+extern ipfix_collector_main_t ipfix_collector_main;
+
+/**
+ * @brief IP-FIX SetID registration function.
+ *
+ * This function can be used by other VPP graph nodes to receive IP-FIX packets
+ * with a particular setid.
+ *
+ * @param vlib_main_t Vlib main of the graph node which is interseted in
+ *                    getting IP-Fix packet.
+ * @param ipfix_client_add_del_t Structure describing the client node which
+ *                               is interested in getting the IP-Fix packets for
+ *                               a SetID.
+ *
+ * @returns 0 on success.
+ * @returns Error codes(<0) otherwise.
+ */
+int
+ipfix_collector_reg_setid (vlib_main_t * vm, ipfix_client_add_del_t * info);
+
+always_inline ipfix_client *
+ipfix_collector_get_client (u16 set_id)
+{
+  ipfix_collector_main_t *cm = &ipfix_collector_main;
+  uword *p;
+
+  p = hash_get (cm->client_reg_table, set_id);
+  return (p ? pool_elt_at_index (cm->client_reg_pool, (*p)) : NULL);
+}
+
+#endif /* PLUGINS_IPFIXCOLLECTOR_PLUGIN_IPFIXCOLLECTOR_IPFIXCOLLECTOR_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/ipfixcollector/node.c b/src/plugins/ioam/ipfixcollector/node.c
new file mode 100644 (file)
index 0000000..fce997a
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2017 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 <ioam/ipfixcollector/ipfixcollector.h>
+#include <vnet/flow/ipfix_packet.h>
+
+#define foreach_ipfix_collector_error \
+_(PROCESSED, "Number of IP-Fix packets processed") \
+_(NO_LISTENER, "Number of IP-Fix packets with no listener")
+
+typedef enum
+{
+#define _(sym,str) IPFIX_COLLECTOR_ERROR_##sym,
+  foreach_ipfix_collector_error
+#undef _
+    IPFIX_COLLECTOR_N_ERROR,
+} flowperpkt_error_t;
+
+static char *ipfix_collector_error_strings[] = {
+#define _(sym,string) string,
+  foreach_ipfix_collector_error
+#undef _
+};
+
+typedef enum
+{
+  IPFIX_COLLECTOR_NEXT_DROP,
+  IPFIX_COLLECTOR_N_NEXT,
+} ipfix_collector_next_t;
+
+typedef struct
+{
+  u32 next_node;
+  u16 set_id;
+  u16 pad;
+} ipfix_collector_trace_t;
+
+vlib_node_registration_t ipfix_collector_node;
+
+/* packet trace format function */
+static u8 *
+format_ipfix_collector_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  ipfix_collector_trace_t *t = va_arg (*args, ipfix_collector_trace_t *);
+
+  s = format (s,
+             "IPFIX_COLLECTOR: set_id %u, next_node %u", t->set_id,
+             t->next_node);
+  return s;
+}
+
+/**
+ * @brief Node to receive IP-Fix packets.
+ * @node ipfix-collector
+ *
+ * This function receives IP-FIX packets and forwards them to other graph nodes
+ * based on SetID field in IP-FIX.
+ *
+ * @param vm    vlib_main_t corresponding to the current thread.
+ * @param node  vlib_node_runtime_t data for this node.
+ * @param frame vlib_frame_t whose contents should be dispatched.
+ *
+ * @par Graph mechanics: buffer, next index usage
+ *
+ * <em>Uses:</em>
+ * - <code>vlib_buffer_get_current(p0)</code>
+ *     - Parses IP-Fix packet to extract SetId which will be used to decide
+ *       next node where packets should be enqueued.
+ *
+ * <em>Next Index:</em>
+ * - Dispatches the packet to other VPP graph nodes based on their registartion
+ *   for the IP-Fix SetId using API ipfix_collector_reg_setid().
+ */
+uword
+ipfix_collector_node_fn (vlib_main_t * vm,
+                        vlib_node_runtime_t * node,
+                        vlib_frame_t * from_frame)
+{
+  u32 n_left_from, next_index, *from, *to_next;
+  word n_no_listener = 0;
+  word n_listener = 0;
+
+  from = vlib_frame_vector_args (from_frame);
+  n_left_from = from_frame->n_vectors;
+
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         u32 bi0, bi1;
+         vlib_buffer_t *b0, *b1;
+         u32 next0, next1;
+         ipfix_message_header_t *ipfix0, *ipfix1;
+         ipfix_set_header_t *set0, *set1;
+         u16 set_id0, set_id1;
+         ipfix_client *client0, *client1;
+
+         /* Prefetch next iteration. */
+         {
+           vlib_buffer_t *p2, *p3;
+
+           p2 = vlib_get_buffer (vm, from[2]);
+           p3 = vlib_get_buffer (vm, from[3]);
+
+           vlib_prefetch_buffer_header (p2, LOAD);
+           vlib_prefetch_buffer_header (p3, LOAD);
+
+           CLIB_PREFETCH (p2->data,
+                          (sizeof (ipfix_message_header_t) +
+                           sizeof (ipfix_set_header_t)), LOAD);
+           CLIB_PREFETCH (p3->data,
+                          (sizeof (ipfix_message_header_t) +
+                           sizeof (ipfix_set_header_t)), LOAD);
+         }
+
+         bi0 = from[0];
+         bi1 = from[1];
+         to_next[0] = bi0;
+         to_next[1] = bi1;
+         from += 2;
+         to_next += 2;
+         n_left_to_next -= 2;
+         n_left_from -= 2;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+
+         ipfix0 = vlib_buffer_get_current (b0);
+         ipfix1 = vlib_buffer_get_current (b1);
+
+         set0 = (ipfix_set_header_t *) (ipfix0 + 1);
+         set1 = (ipfix_set_header_t *) (ipfix1 + 1);
+
+         set_id0 = (u16) (clib_net_to_host_u32 (set0->set_id_length) >> 16);
+         set_id1 = (u16) (clib_net_to_host_u32 (set1->set_id_length) >> 16);
+
+         client0 = ipfix_collector_get_client (set_id0);
+         client1 = ipfix_collector_get_client (set_id1);
+
+         if (PREDICT_TRUE (NULL != client0))
+           {
+             next0 = client0->client_next_node;
+             n_listener++;
+           }
+         else
+           {
+             next0 = IPFIX_COLLECTOR_NEXT_DROP;
+             n_no_listener++;
+           }
+
+         if (PREDICT_TRUE (NULL != client1))
+           {
+             next1 = client1->client_next_node;
+             n_listener++;
+           }
+         else
+           {
+             next1 = IPFIX_COLLECTOR_NEXT_DROP;
+             n_no_listener++;
+           }
+
+         vlib_buffer_advance (b0,
+                              (sizeof (ipfix_message_header_t)
+                               + sizeof (ipfix_set_header_t)));
+         vlib_buffer_advance (b1,
+                              (sizeof (ipfix_message_header_t)
+                               + sizeof (ipfix_set_header_t)));
+
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ipfix_collector_trace_t *tr = vlib_add_trace (vm, node,
+                                                           b0, sizeof (*tr));
+             tr->next_node = (client0 ? client0->client_node : 0xFFFFFFFF);
+             tr->set_id = set_id0;
+           }
+         if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ipfix_collector_trace_t *tr = vlib_add_trace (vm, node,
+                                                           b1, sizeof (*tr));
+             tr->next_node = (client1 ? client1->client_node : 0xFFFFFFFF);
+             tr->set_id = set_id1;
+           }
+
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, bi1, next0, next1);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 bi0;
+         vlib_buffer_t *b0;
+         u32 next0;
+         ipfix_message_header_t *ipfix0;
+         ipfix_set_header_t *set0;
+         u16 set_id0;
+         ipfix_client *client0;
+
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         ipfix0 = vlib_buffer_get_current (b0);
+
+         set0 = (ipfix_set_header_t *) (ipfix0 + 1);
+
+         set_id0 = (u16) (clib_net_to_host_u32 (set0->set_id_length) >> 16);
+
+         client0 = ipfix_collector_get_client (set_id0);
+
+         if (PREDICT_TRUE (NULL != client0))
+           {
+             next0 = client0->client_next_node;
+             n_listener++;
+           }
+         else
+           {
+             next0 = IPFIX_COLLECTOR_NEXT_DROP;
+             n_no_listener++;
+           }
+
+         vlib_buffer_advance (b0,
+                              (sizeof (ipfix_message_header_t)
+                               + sizeof (ipfix_set_header_t)));
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ipfix_collector_trace_t *tr = vlib_add_trace (vm, node,
+                                                           b0, sizeof (*tr));
+             tr->next_node = (client0 ? client0->client_node : 0xFFFFFFFF);
+             tr->set_id = set_id0;
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+  vlib_error_count (vm, node->node_index,
+                   IPFIX_COLLECTOR_ERROR_NO_LISTENER, n_no_listener);
+  vlib_error_count (vm, node->node_index,
+                   IPFIX_COLLECTOR_ERROR_PROCESSED, n_listener);
+  return from_frame->n_vectors;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ipfix_collector_node) = {
+  .function = ipfix_collector_node_fn,
+  .name = "ipfix-collector",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ipfix_collector_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_errors = ARRAY_LEN(ipfix_collector_error_strings),
+  .error_strings = ipfix_collector_error_strings,
+
+  .n_next_nodes = IPFIX_COLLECTOR_N_NEXT,
+
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [IPFIX_COLLECTOR_NEXT_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/lib-e2e/e2e_util.h b/src/plugins/ioam/lib-e2e/e2e_util.h
new file mode 100644 (file)
index 0000000..f8a4ebd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 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 PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_E2E_UTIL_H_
+#define PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_E2E_UTIL_H_
+
+#include <ioam/lib-e2e/ioam_seqno_lib.h>
+
+/* *INDENT-OFF* */
+typedef CLIB_PACKED(struct {
+  u8 e2e_type;
+  u8 reserved;
+  u32 e2e_data;
+}) ioam_e2e_packet_t;
+/* *INDENT-ON* */
+
+#endif /* PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_E2E_UTIL_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/lib-e2e/ioam_seqno_lib.c b/src/plugins/ioam/lib-e2e/ioam_seqno_lib.c
new file mode 100644 (file)
index 0000000..bf78c1e
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017 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 <ioam/lib-e2e/ioam_seqno_lib.h>
+
+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 = show_ioam_seqno_analyse_data_fn (s, rx);
+    }
+
+  format (s, "\n");
+  return s;
+}
+
+u8 *
+show_ioam_seqno_analyse_data_fn (u8 * s, seqno_rx_info * 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;
+}
+
+void
+ioam_seqno_init_data (ioam_seqno_data * data)
+{
+  data->seq_num = 0;
+  ioam_seqno_init_rx_info (&data->seqno_rx);
+  return;
+}
+
+void
+ioam_seqno_init_rx_info (seqno_rx_info * data)
+{
+  seqno_bitmap *bitmap = &data->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->dup_packets = 0;
+  data->lost_packets = 0;
+  data->reordered_packets = 0;
+  data->rx_packets = 0;
+  return;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ioam/lib-e2e/ioam_seqno_lib.h b/src/plugins/ioam/lib-e2e/ioam_seqno_lib.h
new file mode 100644 (file)
index 0000000..6bd38ff
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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 PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_
+#define PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_
+
+#include <vppinfra/types.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;
+
+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
+ */
+inline static 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;
+}
+
+u8 *show_ioam_seqno_analyse_data_fn (u8 * s, seqno_rx_info * rx);
+
+u8 *show_ioam_seqno_cmd_fn (u8 * s, ioam_seqno_data * seqno_data, u8 enc);
+
+void ioam_seqno_init_data (ioam_seqno_data * data);
+
+void ioam_seqno_init_rx_info (seqno_rx_info * data);
+
+#endif /* PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 556f07e..60802ad 100644 (file)
@@ -89,7 +89,14 @@ int trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts,
 
 void clear_trace_profiles (void);
 
-
+/* *INDENT-OFF* */
+typedef CLIB_PACKED (struct
+{
+  u8 ioam_trace_type;
+  u8 data_list_elts_left;
+  u32 elts[0]; /* Variable type. So keep it generic */
+}) ioam_trace_hdr_t;
+/* *INDENT-ON* */
 
 #define    BIT_TTL_NODEID       (1<<0)
 #define    BIT_ING_INTERFACE    (1<<1)
index 1526987..1844d72 100644 (file)
@@ -492,9 +492,6 @@ int ip6_hbh_register_option (u8 option,
 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   0x80000000
-
 #endif /* included_ip_ip6_h */
 
 /*
index 06c20bb..ae5c19b 100644 (file)
@@ -49,6 +49,9 @@
 
 #include <vppinfra/bihash_template.c>
 
+/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
+#define OI_DECAP   0x80000000
+
 /**
  * @file
  * @brief IPv6 Forwarding.
index 3a820b3..df2a932 100644 (file)
@@ -56,32 +56,6 @@ typedef enum
     IP6_HBYH_IOAM_INPUT_N_NEXT,
 } 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)
 {
index acfaa37..9574f0a 100644 (file)
@@ -92,8 +92,6 @@ 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_seqno_option,
@@ -206,6 +204,32 @@ is_seqno_enabled (void)
 }
 
 int ip6_trace_profile_setup ();
+
+static inline 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);
+}
+
 #endif /* __included_ip6_hop_by_hop_ioam_h__ */
 
 /*
index 543ba8b..dd8c7d5 100644 (file)
@@ -45,16 +45,6 @@ typedef struct
 #define HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT 60       /* Third highest bit set (change en-route) */
 #define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE 29
 
-
-/* *INDENT-OFF* */
-typedef CLIB_PACKED(struct {
-  ip6_hop_by_hop_option_t hdr;
-  u8 e2e_type;
-  u8 reserved;
-  u32 e2e_data;
-}) ioam_e2e_option_t;
-/* *INDENT-ON* */
-
 #endif /* __included_ip6_hop_by_hop_packet_h__ */
 
 /*