2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vppinfra/error.h>
19 #include <vnet/ethernet/ethernet.h>
20 #include <vnet/ip/ip.h>
21 #include <ioam/export-common/ioam_export.h>
22 #include <ioam/encap/ip6_ioam_trace.h>
23 #include <ioam/encap/ip6_ioam_pot.h>
24 #include <ioam/lib-pot/pot_util.h>
25 #include <ioam/encap/ip6_ioam_e2e.h>
26 #include <ioam/analyse/ioam_analyse.h>
27 #include <ioam/analyse/ip6/ip6_ioam_analyse.h>
28 #include <vnet/plugin/plugin.h>
36 vlib_node_registration_t analyse_node_local;
37 vlib_node_registration_t analyse_node_remote;
39 #define foreach_analyse_error \
40 _(ANALYSED, "Packets analysed for summarization") \
41 _(FAILED, "Packets analysis failed") \
45 #define _(sym,str) ANALYSE_ERROR_##sym,
51 static char *analyse_error_strings[] = {
52 #define _(sym,string) string,
59 ANALYSE_NEXT_IP4_LOOKUP,
60 ANALYSE_NEXT_IP4_DROP,
64 ip6_ioam_analyser_main_t ioam_analyser_main;
66 /* packet trace format function */
68 format_analyse_trace (u8 * s, va_list * args)
70 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
71 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
72 analyse_trace_t *t = va_arg (*args, analyse_trace_t *);
74 s = format (s, "IP6-ioam-analyse: flow_id %d, next index %d",
75 t->flow_id, t->next_index);
80 ioam_analyse_hbh (u32 flow_id,
81 ip6_hop_by_hop_header_t * hbh0,
82 ip6_hop_by_hop_option_t * opt0,
83 ip6_hop_by_hop_option_t * limit0, u16 len)
85 ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
95 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
100 if (am->analyse_hbh_handler[type0])
103 ((*am->analyse_hbh_handler[type0]) (flow_id, opt0,
106 error0 = ANALYSE_ERROR_FAILED;
112 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
113 sizeof (ip6_hop_by_hop_option_t));
119 * @brief IPv6 InBandOAM Analyse node.
120 * @node ip6-hbh-analyse-local, ip6-hbh-analyse-remote
122 * This function receives IP-FIX packets containing IPv6-iOAM records, analyses
123 * them and collects/aggregates the statistics.
125 * @param vm vlib_main_t corresponding to the current thread.
126 * @param node vlib_node_runtime_t data for this node.
127 * @param frame vlib_frame_t whose contents should be dispatched.
129 * @par Graph mechanics: buffer, next index usage
132 * - <code>vlib_buffer_get_current(p0)</code>
133 * - Walks on each ioam record present in IP-Fix record, analyse them and
134 * store the statistics.
136 * <em>Next Index:</em>
137 * - Dispatches the packet to ip4-lookup if executed under ip6-hbh-analyse-local
138 * node context and to ip4-drop if executed under ip6-hbh-analyse-remote node
142 ip6_ioam_analyse_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
143 vlib_frame_t * frame)
145 u32 n_left_from, *from, *to_next;
146 analyse_next_t next_index;
147 u32 pkts_analysed = 0;
150 u32 next0 = ANALYSE_NEXT_IP4_LOOKUP;
152 from = vlib_frame_vector_args (frame);
153 n_left_from = frame->n_vectors;
154 next_index = node->cached_next_index;
156 if (PREDICT_FALSE (analyse_node_remote.index == node->node_index))
159 next0 = ANALYSE_NEXT_IP4_DROP;
162 while (n_left_from > 0)
166 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
168 while (n_left_from > 0 && n_left_to_next > 0)
174 u16 num_ioam_records;
176 /* speculatively enqueue p0 to the current next frame */
184 p0 = vlib_get_buffer (vm, bi0);
185 if (PREDICT_FALSE (remote))
187 vlib_buffer_advance (p0, -(word) (sizeof (udp_header_t) +
188 sizeof (ip4_header_t) +
190 (ipfix_message_header_t) +
191 sizeof (ipfix_set_header_t)));
193 data = (u8 *) vlib_buffer_get_current (p0);
194 ip40 = (ip4_header_t *) vlib_buffer_get_current (p0);
195 limit = data + clib_net_to_host_u16 (ip40->length);
196 data += sizeof (ip4_header_t) + sizeof (udp_header_t)
197 + sizeof (ipfix_message_header_t) + sizeof (ipfix_set_header_t);
199 num_ioam_records = (limit - data) / DEFAULT_EXPORT_SIZE;
201 while (num_ioam_records >= 4)
203 /* Prefetch next 2 ioam records */
205 CLIB_PREFETCH (data + (2 * DEFAULT_EXPORT_SIZE),
206 (DEFAULT_EXPORT_SIZE), LOAD);
207 CLIB_PREFETCH (data + (3 * DEFAULT_EXPORT_SIZE),
208 (DEFAULT_EXPORT_SIZE), LOAD);
211 num_ioam_records -= 2;
213 ip6_header_t *ip60, *ip61;
214 ip6_hop_by_hop_header_t *hbh0, *hbh1;
215 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
216 u32 flow_id0, flow_id1;
218 ioam_analyser_data_t *data0, *data1;
221 ip60 = (ip6_header_t *) data;
222 ip61 = (ip6_header_t *) (data + DEFAULT_EXPORT_SIZE);
224 data += (2 * DEFAULT_EXPORT_SIZE);
226 hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
227 hbh1 = (ip6_hop_by_hop_header_t *) (ip61 + 1);
229 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
230 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
233 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
234 ((hbh0->length + 1) << 3));
236 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
237 ((hbh1->length + 1) << 3));
241 (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
244 (ip61->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
246 p_len0 = clib_net_to_host_u16 (ip60->payload_length);
247 p_len1 = clib_net_to_host_u16 (ip61->payload_length);
250 ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
252 ioam_analyse_hbh (flow_id1, hbh1, opt1, limit1, p_len0);
254 if (PREDICT_TRUE ((error0 == 0) && (error1 == 0)))
257 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
258 data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
260 clib_spinlock_lock (&data0->writer_lock);
261 data0->pkt_counter++;
262 data0->bytes_counter += p_len0;
263 clib_spinlock_unlock (&data0->writer_lock);
265 clib_spinlock_lock (&data1->writer_lock);
266 data1->pkt_counter++;
267 data1->bytes_counter += p_len1;
268 clib_spinlock_unlock (&data1->writer_lock);
270 else if (error0 == 0)
275 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
276 clib_spinlock_lock (&data0->writer_lock);
277 data0->pkt_counter++;
278 data0->bytes_counter += p_len0;
279 clib_spinlock_unlock (&data0->writer_lock);
281 else if (error1 == 0)
286 data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
287 clib_spinlock_lock (&data1->writer_lock);
288 data1->pkt_counter++;
289 data1->bytes_counter += p_len1;
290 clib_spinlock_unlock (&data1->writer_lock);
296 while (num_ioam_records > 0)
301 ip6_hop_by_hop_header_t *hbh0;
302 ip6_hop_by_hop_option_t *opt0, *limit0;
305 ioam_analyser_data_t *data0;
308 ip60 = (ip6_header_t *) data;
309 data += (1 * DEFAULT_EXPORT_SIZE);
310 hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
311 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
313 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
314 ((hbh0->length + 1) << 3));
318 (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
319 p_len0 = clib_net_to_host_u16 (ip60->payload_length);
321 ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
323 if (PREDICT_TRUE (error0 == 0))
326 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
327 clib_spinlock_lock (&data0->writer_lock);
328 data0->pkt_counter++;
329 data0->bytes_counter +=
330 clib_net_to_host_u16 (ip60->payload_length);
331 clib_spinlock_unlock (&data0->writer_lock);
337 /* verify speculative enqueue, maybe switch current next frame */
338 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
339 n_left_to_next, bi0, next0);
342 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
345 vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_ANALYSED,
348 if (PREDICT_FALSE (pkts_failed))
349 vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_FAILED,
352 return frame->n_vectors;
356 ip6_ioam_analyse_hbh_trace_internal (u32 flow_id,
357 ip6_hop_by_hop_option_t * opt, u16 len)
359 ioam_analyser_data_t *data;
360 ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
362 data = ioam_analyse_get_data_from_flow_id (flow_id);
363 ASSERT (data != NULL);
365 (void) ip6_ioam_analyse_hbh_trace (data, &trace->trace_hdr, len,
366 (trace->hdr.length - 2)
367 /*ioam_trace_type,data_list_elts_left */
373 ip6_ioam_analyse_hbh_pot (u32 flow_id, ip6_hop_by_hop_option_t * opt0,
377 ioam_pot_option_t *pot0;
380 pot_profile *pot_profile = 0;
382 ioam_analyser_data_t *data;
384 data = ioam_analyse_get_data_from_flow_id (flow_id);
386 pot0 = (ioam_pot_option_t *) opt0;
387 random = clib_net_to_host_u64 (pot0->random);
388 cumulative = clib_net_to_host_u64 (pot0->cumulative);
389 pot_profile = pot_profile_get_active ();
390 ret = pot_validate (pot_profile, cumulative, random);
392 clib_spinlock_lock (&data->writer_lock);
394 (0 == ret) ? (data->pot_data.sfc_validated_count++) :
395 (data->pot_data.sfc_invalidated_count++);
397 clib_spinlock_unlock (&data->writer_lock);
402 ip6_ioam_analyse_hbh_e2e_internal (u32 flow_id, ip6_hop_by_hop_option_t * opt,
405 ioam_analyser_data_t *data;
406 ioam_e2e_option_t *e2e;
408 data = ioam_analyse_get_data_from_flow_id (flow_id);
409 e2e = (ioam_e2e_option_t *) opt;
410 ip6_ioam_analyse_hbh_e2e (data, &e2e->e2e_hdr, len);
415 ip6_ioam_analyse_register_hbh_handler (u8 option,
416 int options (u32 flow_id,
417 ip6_hop_by_hop_option_t *
420 ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
422 ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
424 /* Already registered */
425 if (am->analyse_hbh_handler[option])
428 am->analyse_hbh_handler[option] = options;
434 ip6_ioam_analyse_unregister_hbh_handler (u8 option)
436 ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
438 ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
441 if (!am->analyse_hbh_handler[option])
444 am->analyse_hbh_handler[option] = NULL;
449 ip6_ioam_analyse_register_handlers ()
451 ip6_ioam_analyse_register_hbh_handler (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST,
452 ip6_ioam_analyse_hbh_trace_internal);
453 ip6_ioam_analyse_register_hbh_handler
454 (HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_ioam_analyse_hbh_pot);
455 ip6_ioam_analyse_register_hbh_handler (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
456 ip6_ioam_analyse_hbh_e2e_internal);
460 ip6_ioam_analyse_unregister_handlers ()
462 ip6_ioam_analyse_unregister_hbh_handler
463 (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST);
464 ip6_ioam_analyse_unregister_hbh_handler
465 (HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT);
466 ip6_ioam_analyse_unregister_hbh_handler (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE);
471 * Node for IP6 analyse - packets
473 VLIB_REGISTER_NODE (analyse_node_local) = {
474 .function = ip6_ioam_analyse_node_fn,
475 .name = "ip6-hbh-analyse-local",
476 .vector_size = sizeof (u32),
477 .format_trace = format_analyse_trace,
478 .type = VLIB_NODE_TYPE_INTERNAL,
479 .n_errors = ARRAY_LEN (analyse_error_strings),
480 .error_strings = analyse_error_strings,
481 .n_next_nodes = ANALYSE_N_NEXT,
482 /* edit / add dispositions here */
484 [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
485 [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
490 * Node for IP6 analyse - packets
492 VLIB_REGISTER_NODE (analyse_node_remote) =
494 .function = ip6_ioam_analyse_node_fn,
495 .name = "ip6-hbh-analyse-remote",
496 .vector_size = sizeof (u32),
497 .format_trace = format_analyse_trace,
498 .type = VLIB_NODE_TYPE_INTERNAL,
499 .n_errors = ARRAY_LEN (analyse_error_strings),
500 .error_strings = analyse_error_strings,
501 .n_next_nodes = ANALYSE_N_NEXT,
502 /* edit / add dispositions here */
504 [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
505 [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
511 * fd.io coding-style-patch-verification: ON
514 * eval: (c-set-style "gnu")