aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/ioam.am36
-rw-r--r--src/plugins/ioam/analyse/ioam_analyse.h398
-rw-r--r--src/plugins/ioam/analyse/ioam_summary_export.c437
-rwxr-xr-xsrc/plugins/ioam/analyse/ioam_summary_export.h86
-rw-r--r--src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.c162
-rw-r--r--src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.h68
-rw-r--r--src/plugins/ioam/analyse/ip6/node.c523
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_e2e.c4
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_e2e.h17
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_pot.c21
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_pot.h40
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_seqno.c43
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_seqno.h42
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c141
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_trace.c50
-rw-r--r--src/plugins/ioam/encap/ip6_ioam_trace.h38
-rw-r--r--src/plugins/ioam/export-common/ioam_export.h56
-rw-r--r--src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c5
-rw-r--r--src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c11
-rw-r--r--src/plugins/ioam/export/ioam_export.c6
-rw-r--r--src/plugins/ioam/export/node.c18
-rw-r--r--src/plugins/ioam/ipfixcollector/ipfixcollector.c105
-rw-r--r--src/plugins/ioam/ipfixcollector/ipfixcollector.h124
-rw-r--r--src/plugins/ioam/ipfixcollector/node.c301
-rw-r--r--src/plugins/ioam/lib-e2e/e2e_util.h37
-rw-r--r--src/plugins/ioam/lib-e2e/ioam_seqno_lib.c84
-rw-r--r--src/plugins/ioam/lib-e2e/ioam_seqno_lib.h201
-rw-r--r--src/plugins/ioam/lib-trace/trace_util.h9
-rw-r--r--src/vnet/ip/ip6.h3
-rw-r--r--src/vnet/ip/ip6_forward.c3
-rw-r--r--src/vnet/ip/ip6_hop_by_hop.c26
-rw-r--r--src/vnet/ip/ip6_hop_by_hop.h28
-rw-r--r--src/vnet/ip/ip6_hop_by_hop_packet.h10
33 files changed, 2797 insertions, 336 deletions
diff --git a/src/plugins/ioam.am b/src/plugins/ioam.am
index a2b298b130f..14d8a9eb6d9 100644
--- a/src/plugins/ioam.am
+++ b/src/plugins/ioam.am
@@ -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
index 00000000000..a416cb1a597
--- /dev/null
+++ b/src/plugins/ioam/analyse/ioam_analyse.h
@@ -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
index 00000000000..0056732327c
--- /dev/null
+++ b/src/plugins/ioam/analyse/ioam_summary_export.c
@@ -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
index 00000000000..9be31d2e5ed
--- /dev/null
+++ b/src/plugins/ioam/analyse/ioam_summary_export.h
@@ -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
index 00000000000..c22ef0f46fd
--- /dev/null
+++ b/src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.c
@@ -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
index 00000000000..f6abdce3c9a
--- /dev/null
+++ b/src/plugins/ioam/analyse/ip6/ip6_ioam_analyse.h
@@ -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
index 00000000000..6db6355e9f0
--- /dev/null
+++ b/src/plugins/ioam/analyse/ip6/node.c
@@ -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:
+ */
diff --git a/src/plugins/ioam/encap/ip6_ioam_e2e.c b/src/plugins/ioam/encap/ip6_ioam_e2e.c
index 2831a351d4f..cdaf740d251 100644
--- a/src/plugins/ioam/encap/ip6_ioam_e2e.c
+++ b/src/plugins/ioam/encap/ip6_ioam_e2e.c
@@ -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));
}
diff --git a/src/plugins/ioam/encap/ip6_ioam_e2e.h b/src/plugins/ioam/encap/ip6_ioam_e2e.h
index 18f35f80c60..fcec4a1447f 100644
--- a/src/plugins/ioam/encap/ip6_ioam_e2e.h
+++ b/src/plugins/ioam/encap/ip6_ioam_e2e.h
@@ -16,8 +16,16 @@
#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__ */
diff --git a/src/plugins/ioam/encap/ip6_ioam_pot.c b/src/plugins/ioam/encap/ip6_ioam_pot.c
index 05f42c91d0f..9a76123330d 100644
--- a/src/plugins/ioam/encap/ip6_ioam_pot.c
+++ b/src/plugins/ioam/encap/ip6_ioam_pot.c
@@ -16,26 +16,15 @@
#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
index 00000000000..01ce4ac590f
--- /dev/null
+++ b/src/plugins/ioam/encap/ip6_ioam_pot.h
@@ -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:
+ */
diff --git a/src/plugins/ioam/encap/ip6_ioam_seqno.c b/src/plugins/ioam/encap/ip6_ioam_seqno.c
index 0b4d4192975..019771232b4 100644
--- a/src/plugins/ioam/encap/ip6_ioam_seqno.c
+++ b/src/plugins/ioam/encap/ip6_ioam_seqno.c
@@ -28,20 +28,6 @@
#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;
-}
diff --git a/src/plugins/ioam/encap/ip6_ioam_seqno.h b/src/plugins/ioam/encap/ip6_ioam_seqno.h
index 13a84db0d71..5c140246ad2 100644
--- a/src/plugins/ioam/encap/ip6_ioam_seqno.h
+++ b/src/plugins/ioam/encap/ip6_ioam_seqno.h
@@ -18,42 +18,7 @@
#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
index 4638871c224..00000000000
--- a/src/plugins/ioam/encap/ip6_ioam_seqno_analyse.c
+++ /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;
-}
diff --git a/src/plugins/ioam/encap/ip6_ioam_trace.c b/src/plugins/ioam/encap/ip6_ioam_trace.c
index a836dfe817b..6972ba4be96 100644
--- a/src/plugins/ioam/encap/ip6_ioam_trace.c
+++ b/src/plugins/ioam/encap/ip6_ioam_trace.c
@@ -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
index 00000000000..b332b3197e9
--- /dev/null
+++ b/src/plugins/ioam/encap/ip6_ioam_trace.h
@@ -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:
+ */
diff --git a/src/plugins/ioam/export-common/ioam_export.h b/src/plugins/ioam/export-common/ioam_export.h
index e6ab0344958..e84dab0b398 100644
--- a/src/plugins/ioam/export-common/ioam_export.h
+++ b/src/plugins/ioam/export-common/ioam_export.h
@@ -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) \
diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c
index 0924d68f6ff..f05b5303d3c 100644
--- a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c
+++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.c
@@ -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;
diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c
index f75b7081c09..8120f4a768d 100644
--- a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c
+++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_node.c
@@ -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;
}
diff --git a/src/plugins/ioam/export/ioam_export.c b/src/plugins/ioam/export/ioam_export.c
index 06634baaf4b..1112ce4f66d 100644
--- a/src/plugins/ioam/export/ioam_export.c
+++ b/src/plugins/ioam/export/ioam_export.c
@@ -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);
diff --git a/src/plugins/ioam/export/node.c b/src/plugins/ioam/export/node.c
index 19f143dfbf3..b32d7841690 100644
--- a/src/plugins/ioam/export/node.c
+++ b/src/plugins/ioam/export/node.c
@@ -17,8 +17,10 @@
#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
index 00000000000..4ae47edcb3c
--- /dev/null
+++ b/src/plugins/ioam/ipfixcollector/ipfixcollector.c
@@ -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
index 00000000000..ee570316398
--- /dev/null
+++ b/src/plugins/ioam/ipfixcollector/ipfixcollector.h
@@ -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
index 00000000000..fce997aedb7
--- /dev/null
+++ b/src/plugins/ioam/ipfixcollector/node.c
@@ -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
index 00000000000..f8a4ebd4797
--- /dev/null
+++ b/src/plugins/ioam/lib-e2e/e2e_util.h
@@ -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
index 00000000000..bf78c1e3d2d
--- /dev/null
+++ b/src/plugins/ioam/lib-e2e/ioam_seqno_lib.c
@@ -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
index 00000000000..6bd38ff2968
--- /dev/null
+++ b/src/plugins/ioam/lib-e2e/ioam_seqno_lib.h
@@ -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:
+ */
diff --git a/src/plugins/ioam/lib-trace/trace_util.h b/src/plugins/ioam/lib-trace/trace_util.h
index 556f07ee3f1..60802adea64 100644
--- a/src/plugins/ioam/lib-trace/trace_util.h
+++ b/src/plugins/ioam/lib-trace/trace_util.h
@@ -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)
diff --git a/src/vnet/ip/ip6.h b/src/vnet/ip/ip6.h
index 152698733e8..1844d727cc0 100644
--- a/src/vnet/ip/ip6.h
+++ b/src/vnet/ip/ip6.h
@@ -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 */
/*
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index 06c20bbaa12..ae5c19b6966 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -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.
diff --git a/src/vnet/ip/ip6_hop_by_hop.c b/src/vnet/ip/ip6_hop_by_hop.c
index 3a820b3cefc..df2a932e00d 100644
--- a/src/vnet/ip/ip6_hop_by_hop.c
+++ b/src/vnet/ip/ip6_hop_by_hop.c
@@ -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)
{
diff --git a/src/vnet/ip/ip6_hop_by_hop.h b/src/vnet/ip/ip6_hop_by_hop.h
index acfaa37ed2f..9574f0a5ecc 100644
--- a/src/vnet/ip/ip6_hop_by_hop.h
+++ b/src/vnet/ip/ip6_hop_by_hop.h
@@ -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__ */
/*
diff --git a/src/vnet/ip/ip6_hop_by_hop_packet.h b/src/vnet/ip/ip6_hop_by_hop_packet.h
index 543ba8b0533..dd8c7d5e505 100644
--- a/src/vnet/ip/ip6_hop_by_hop_packet.h
+++ b/src/vnet/ip/ip6_hop_by_hop_packet.h
@@ -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__ */
/*