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/ip/ip.h>
20 #include <ioam/export-common/ioam_export.h>
21 #include <ioam/encap/ip6_ioam_trace.h>
22 #include <ioam/encap/ip6_ioam_pot.h>
23 #include <ioam/lib-pot/pot_util.h>
24 #include <ioam/encap/ip6_ioam_e2e.h>
25 #include <ioam/analyse/ioam_analyse.h>
26 #include <ioam/analyse/ip6/ip6_ioam_analyse.h>
27 #include <vnet/plugin/plugin.h>
35 vlib_node_registration_t analyse_node_local;
36 vlib_node_registration_t analyse_node_remote;
38 #define foreach_analyse_error \
39 _(ANALYSED, "Packets analysed for summarization") \
40 _(FAILED, "Packets analysis failed") \
44 #define _(sym,str) ANALYSE_ERROR_##sym,
50 static char *analyse_error_strings[] = {
51 #define _(sym,string) string,
58 ANALYSE_NEXT_IP4_LOOKUP,
59 ANALYSE_NEXT_IP4_DROP,
63 ip6_ioam_analyser_main_t ioam_analyser_main;
65 /* packet trace format function */
67 format_analyse_trace (u8 * s, va_list * args)
69 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71 analyse_trace_t *t = va_arg (*args, analyse_trace_t *);
73 s = format (s, "IP6-ioam-analyse: flow_id %d, next index %d",
74 t->flow_id, t->next_index);
79 ioam_analyse_hbh (u32 flow_id,
80 ip6_hop_by_hop_header_t * hbh0,
81 ip6_hop_by_hop_option_t * opt0,
82 ip6_hop_by_hop_option_t * limit0, u16 len)
84 ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
94 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
99 if (am->analyse_hbh_handler[type0])
102 ((*am->analyse_hbh_handler[type0]) (flow_id, opt0,
105 error0 = ANALYSE_ERROR_FAILED;
111 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
112 sizeof (ip6_hop_by_hop_option_t));
118 * @brief IPv6 InBandOAM Analyse node.
119 * @node ip6-hbh-analyse-local, ip6-hbh-analyse-remote
121 * This function receives IP-FIX packets containing IPv6-iOAM records, analyses
122 * them and collects/aggregates the statistics.
124 * @param vm vlib_main_t corresponding to the current thread.
125 * @param node vlib_node_runtime_t data for this node.
126 * @param frame vlib_frame_t whose contents should be dispatched.
128 * @par Graph mechanics: buffer, next index usage
131 * - <code>vlib_buffer_get_current(p0)</code>
132 * - Walks on each ioam record present in IP-Fix record, analyse them and
133 * store the statistics.
135 * <em>Next Index:</em>
136 * - Dispatches the packet to ip4-lookup if executed under ip6-hbh-analyse-local
137 * node context and to ip4-drop if executed under ip6-hbh-analyse-remote node
141 ip6_ioam_analyse_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
142 vlib_frame_t * frame)
144 u32 n_left_from, *from, *to_next;
145 analyse_next_t next_index;
146 u32 pkts_analysed = 0;
149 u32 next0 = ANALYSE_NEXT_IP4_LOOKUP;
151 from = vlib_frame_vector_args (frame);
152 n_left_from = frame->n_vectors;
153 next_index = node->cached_next_index;
155 if (PREDICT_FALSE (analyse_node_remote.index == node->node_index))
158 next0 = ANALYSE_NEXT_IP4_DROP;
161 while (n_left_from > 0)
165 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
167 while (n_left_from > 0 && n_left_to_next > 0)
173 u16 num_ioam_records;
175 /* speculatively enqueue p0 to the current next frame */
183 p0 = vlib_get_buffer (vm, bi0);
184 if (PREDICT_FALSE (remote))
186 vlib_buffer_advance (p0, -(word) (sizeof (udp_header_t) +
187 sizeof (ip4_header_t) +
189 (ipfix_message_header_t) +
190 sizeof (ipfix_set_header_t)));
192 data = (u8 *) vlib_buffer_get_current (p0);
193 ip40 = (ip4_header_t *) vlib_buffer_get_current (p0);
194 limit = data + clib_net_to_host_u16 (ip40->length);
195 data += sizeof (ip4_header_t) + sizeof (udp_header_t)
196 + sizeof (ipfix_message_header_t) + sizeof (ipfix_set_header_t);
198 num_ioam_records = (limit - data) / DEFAULT_EXPORT_SIZE;
200 while (num_ioam_records >= 4)
202 /* Prefetch next 2 ioam records */
204 CLIB_PREFETCH (data + (2 * DEFAULT_EXPORT_SIZE),
205 (DEFAULT_EXPORT_SIZE), LOAD);
206 CLIB_PREFETCH (data + (3 * DEFAULT_EXPORT_SIZE),
207 (DEFAULT_EXPORT_SIZE), LOAD);
210 num_ioam_records -= 2;
212 ip6_header_t *ip60, *ip61;
213 ip6_hop_by_hop_header_t *hbh0, *hbh1;
214 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
215 u32 flow_id0, flow_id1;
217 ioam_analyser_data_t *data0, *data1;
220 ip60 = (ip6_header_t *) data;
221 ip61 = (ip6_header_t *) (data + DEFAULT_EXPORT_SIZE);
223 data += (2 * DEFAULT_EXPORT_SIZE);
225 hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
226 hbh1 = (ip6_hop_by_hop_header_t *) (ip61 + 1);
228 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
229 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
232 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
233 ((hbh0->length + 1) << 3));
235 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
236 ((hbh1->length + 1) << 3));
240 (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
243 (ip61->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
245 p_len0 = clib_net_to_host_u16 (ip60->payload_length);
246 p_len1 = clib_net_to_host_u16 (ip61->payload_length);
249 ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
251 ioam_analyse_hbh (flow_id1, hbh1, opt1, limit1, p_len0);
253 if (PREDICT_TRUE ((error0 == 0) && (error1 == 0)))
256 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
257 data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
259 while (__sync_lock_test_and_set (data0->writer_lock, 1))
261 data0->pkt_counter++;
262 data0->bytes_counter += p_len0;
263 *(data0->writer_lock) = 0;
265 while (__sync_lock_test_and_set (data1->writer_lock, 1))
267 data1->pkt_counter++;
268 data1->bytes_counter += p_len1;
269 *(data1->writer_lock) = 0;
271 else if (error0 == 0)
276 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
277 while (__sync_lock_test_and_set (data0->writer_lock, 1))
279 data0->pkt_counter++;
280 data0->bytes_counter += p_len0;
281 *(data0->writer_lock) = 0;
283 else if (error1 == 0)
288 data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
289 while (__sync_lock_test_and_set (data1->writer_lock, 1))
291 data1->pkt_counter++;
292 data1->bytes_counter += p_len1;
293 *(data1->writer_lock) = 0;
299 while (num_ioam_records > 0)
304 ip6_hop_by_hop_header_t *hbh0;
305 ip6_hop_by_hop_option_t *opt0, *limit0;
308 ioam_analyser_data_t *data0;
311 ip60 = (ip6_header_t *) data;
312 data += (1 * DEFAULT_EXPORT_SIZE);
313 hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
314 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
316 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
317 ((hbh0->length + 1) << 3));
321 (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
322 p_len0 = clib_net_to_host_u16 (ip60->payload_length);
324 ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
326 if (PREDICT_TRUE (error0 == 0))
329 data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
330 while (__sync_lock_test_and_set (data0->writer_lock, 1))
332 data0->pkt_counter++;
333 data0->bytes_counter +=
334 clib_net_to_host_u16 (ip60->payload_length);
335 *(data0->writer_lock) = 0;
341 /* verify speculative enqueue, maybe switch current next frame */
342 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
343 n_left_to_next, bi0, next0);
346 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
349 vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_ANALYSED,
352 if (PREDICT_FALSE (pkts_failed))
353 vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_FAILED,
356 return frame->n_vectors;
360 ip6_ioam_analyse_hbh_trace_internal (u32 flow_id,
361 ip6_hop_by_hop_option_t * opt, u16 len)
363 ioam_analyser_data_t *data;
364 ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
366 data = ioam_analyse_get_data_from_flow_id (flow_id);
367 ASSERT (data != NULL);
369 (void) ip6_ioam_analyse_hbh_trace (data, &trace->trace_hdr, len,
370 (trace->hdr.length - 2)
371 /*ioam_trace_type,data_list_elts_left */
377 ip6_ioam_analyse_hbh_pot (u32 flow_id, ip6_hop_by_hop_option_t * opt0,
381 ioam_pot_option_t *pot0;
384 pot_profile *pot_profile = 0;
386 ioam_analyser_data_t *data;
388 data = ioam_analyse_get_data_from_flow_id (flow_id);
390 pot0 = (ioam_pot_option_t *) opt0;
391 random = clib_net_to_host_u64 (pot0->random);
392 cumulative = clib_net_to_host_u64 (pot0->cumulative);
393 pot_profile = pot_profile_get_active ();
394 ret = pot_validate (pot_profile, cumulative, random);
396 while (__sync_lock_test_and_set (data->writer_lock, 1))
399 (0 == ret) ? (data->pot_data.sfc_validated_count++) :
400 (data->pot_data.sfc_invalidated_count++);
402 *(data->writer_lock) = 0;
407 ip6_ioam_analyse_hbh_e2e_internal (u32 flow_id, ip6_hop_by_hop_option_t * opt,
410 ioam_analyser_data_t *data;
411 ioam_e2e_option_t *e2e;
413 data = ioam_analyse_get_data_from_flow_id (flow_id);
414 e2e = (ioam_e2e_option_t *) opt;
415 ip6_ioam_analyse_hbh_e2e (data, &e2e->e2e_hdr, len);
420 ip6_ioam_analyse_register_hbh_handler (u8 option,
421 int options (u32 flow_id,
422 ip6_hop_by_hop_option_t *
425 ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
427 ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
429 /* Already registered */
430 if (am->analyse_hbh_handler[option])
433 am->analyse_hbh_handler[option] = options;
439 ip6_ioam_analyse_unregister_hbh_handler (u8 option)
441 ip6_ioam_analyser_main_t *am = &ioam_analyser_main;
443 ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
446 if (!am->analyse_hbh_handler[option])
449 am->analyse_hbh_handler[option] = NULL;
454 ip6_ioam_analyse_register_handlers ()
456 ip6_ioam_analyse_register_hbh_handler (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST,
457 ip6_ioam_analyse_hbh_trace_internal);
458 ip6_ioam_analyse_register_hbh_handler
459 (HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_ioam_analyse_hbh_pot);
460 ip6_ioam_analyse_register_hbh_handler (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE,
461 ip6_ioam_analyse_hbh_e2e_internal);
465 ip6_ioam_analyse_unregister_handlers ()
467 ip6_ioam_analyse_unregister_hbh_handler
468 (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST);
469 ip6_ioam_analyse_unregister_hbh_handler
470 (HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT);
471 ip6_ioam_analyse_unregister_hbh_handler (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE);
477 * Node for IP6 analyse - packets
479 VLIB_REGISTER_NODE (analyse_node_local) = {
480 .function = ip6_ioam_analyse_node_fn,
481 .name = "ip6-hbh-analyse-local",
482 .vector_size = sizeof (u32),
483 .format_trace = format_analyse_trace,
484 .type = VLIB_NODE_TYPE_INTERNAL,
485 .n_errors = ARRAY_LEN (analyse_error_strings),
486 .error_strings = analyse_error_strings,
487 .n_next_nodes = ANALYSE_N_NEXT,
488 /* edit / add dispositions here */
490 [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
491 [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
496 * Node for IP6 analyse - packets
498 VLIB_REGISTER_NODE (analyse_node_remote) =
500 .function = ip6_ioam_analyse_node_fn,
501 .name = "ip6-hbh-analyse-remote",
502 .vector_size = sizeof (u32),
503 .format_trace = format_analyse_trace,
504 .type = VLIB_NODE_TYPE_INTERNAL,
505 .n_errors = ARRAY_LEN (analyse_error_strings),
506 .error_strings = analyse_error_strings,
507 .n_next_nodes = ANALYSE_N_NEXT,
508 /* edit / add dispositions here */
510 [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
511 [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
518 * fd.io coding-style-patch-verification: ON
521 * eval: (c-set-style "gnu")