FD.io VPP  v19.08-27-gf4dcae4
Vector Packet Processing
node.c
Go to the documentation of this file.
1 /*
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:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vppinfra/error.h>
19 #include <vnet/ip/ip.h>
23 #include <ioam/lib-pot/pot_util.h>
27 #include <vnet/plugin/plugin.h>
28 
29 typedef struct
30 {
34 
37 
38 #define foreach_analyse_error \
39 _(ANALYSED, "Packets analysed for summarization") \
40 _(FAILED, "Packets analysis failed") \
41 
42 typedef enum
43 {
44 #define _(sym,str) ANALYSE_ERROR_##sym,
46 #undef _
49 
50 static char *analyse_error_strings[] = {
51 #define _(sym,string) string,
53 #undef _
54 };
55 
56 typedef enum
57 {
62 
64 
65 /* packet trace format function */
66 static u8 *
67 format_analyse_trace (u8 * s, va_list * args)
68 {
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 *);
72 
73  s = format (s, "IP6-ioam-analyse: flow_id %d, next index %d",
74  t->flow_id, t->next_index);
75  return s;
76 }
77 
83 {
85  u8 type0;
86  u8 error0 = 0;
87 
88  while (opt0 < limit0)
89  {
90  type0 = opt0->type;
91  switch (type0)
92  {
93  case 0: /* Pad1 */
94  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
95  continue;
96  case 1: /* PadN */
97  break;
98  default:
99  if (am->analyse_hbh_handler[type0])
100  {
101  if (PREDICT_TRUE
102  ((*am->analyse_hbh_handler[type0]) (flow_id, opt0,
103  len) < 0))
104  {
105  error0 = ANALYSE_ERROR_FAILED;
106  return (error0);
107  }
108  }
109  }
110  opt0 =
111  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
112  sizeof (ip6_hop_by_hop_option_t));
113  }
114  return (error0);
115 }
116 
117 /**
118  * @brief IPv6 InBandOAM Analyse node.
119  * @node ip6-hbh-analyse-local, ip6-hbh-analyse-remote
120  *
121  * This function receives IP-FIX packets containing IPv6-iOAM records, analyses
122  * them and collects/aggregates the statistics.
123  *
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.
127  *
128  * @par Graph mechanics: buffer, next index usage
129  *
130  * <em>Uses:</em>
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.
134  *
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
138  * context.
139  */
140 static uword
142  vlib_frame_t * frame)
143 {
144  u32 n_left_from, *from, *to_next;
145  analyse_next_t next_index;
146  u32 pkts_analysed = 0;
147  u32 pkts_failed = 0;
148  u8 remote = 0;
150 
151  from = vlib_frame_vector_args (frame);
152  n_left_from = frame->n_vectors;
153  next_index = node->cached_next_index;
154 
155  if (PREDICT_FALSE (analyse_node_remote.index == node->node_index))
156  {
157  remote = 1;
158  next0 = ANALYSE_NEXT_IP4_DROP;
159  }
160 
161  while (n_left_from > 0)
162  {
163  u32 n_left_to_next;
164 
165  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
166 
167  while (n_left_from > 0 && n_left_to_next > 0)
168  {
169  u32 bi0;
170  vlib_buffer_t *p0;
171  ip4_header_t *ip40;
172  u8 *data, *limit;
173  u16 num_ioam_records;
174 
175  /* speculatively enqueue p0 to the current next frame */
176  bi0 = from[0];
177  to_next[0] = bi0;
178  from += 1;
179  to_next += 1;
180  n_left_from -= 1;
181  n_left_to_next -= 1;
182 
183  p0 = vlib_get_buffer (vm, bi0);
184  if (PREDICT_FALSE (remote))
185  {
186  vlib_buffer_advance (p0, -(word) (sizeof (udp_header_t) +
187  sizeof (ip4_header_t) +
188  sizeof
190  sizeof (ipfix_set_header_t)));
191  }
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);
197 
198  num_ioam_records = (limit - data) / DEFAULT_EXPORT_SIZE;
199 
200  while (num_ioam_records >= 4)
201  {
202  /* Prefetch next 2 ioam records */
203  {
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);
208  }
209 
210  num_ioam_records -= 2;
211 
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;
216  u8 error0, error1;
217  ioam_analyser_data_t *data0, *data1;
218  u16 p_len0, p_len1;
219 
220  ip60 = (ip6_header_t *) data;
221  ip61 = (ip6_header_t *) (data + DEFAULT_EXPORT_SIZE);
222 
223  data += (2 * DEFAULT_EXPORT_SIZE);
224 
225  hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
226  hbh1 = (ip6_hop_by_hop_header_t *) (ip61 + 1);
227 
228  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
229  opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
230 
231  limit0 =
232  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
233  ((hbh0->length + 1) << 3));
234  limit1 =
235  (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
236  ((hbh1->length + 1) << 3));
237 
238  flow_id0 =
239  clib_net_to_host_u32
240  (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
241  flow_id1 =
242  clib_net_to_host_u32
243  (ip61->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
244 
245  p_len0 = clib_net_to_host_u16 (ip60->payload_length);
246  p_len1 = clib_net_to_host_u16 (ip61->payload_length);
247 
248  error0 =
249  ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
250  error1 =
251  ioam_analyse_hbh (flow_id1, hbh1, opt1, limit1, p_len0);
252 
253  if (PREDICT_TRUE ((error0 == 0) && (error1 == 0)))
254  {
255  pkts_analysed += 2;
256  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
257  data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
258 
260  data0->pkt_counter++;
261  data0->bytes_counter += p_len0;
263 
265  data1->pkt_counter++;
266  data1->bytes_counter += p_len1;
268  }
269  else if (error0 == 0)
270  {
271  pkts_analysed++;
272  pkts_failed++;
273 
274  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
276  data0->pkt_counter++;
277  data0->bytes_counter += p_len0;
279  }
280  else if (error1 == 0)
281  {
282  pkts_analysed++;
283  pkts_failed++;
284 
285  data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
287  data1->pkt_counter++;
288  data1->bytes_counter += p_len1;
290  }
291  else
292  pkts_failed += 2;
293  }
294 
295  while (num_ioam_records > 0)
296  {
297  num_ioam_records--;
298 
299  ip6_header_t *ip60;
301  ip6_hop_by_hop_option_t *opt0, *limit0;
302  u32 flow_id0;
303  u8 error0;
304  ioam_analyser_data_t *data0;
305  u16 p_len0;
306 
307  ip60 = (ip6_header_t *) data;
308  data += (1 * DEFAULT_EXPORT_SIZE);
309  hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
310  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
311  limit0 =
312  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
313  ((hbh0->length + 1) << 3));
314 
315  flow_id0 =
316  clib_net_to_host_u32
317  (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
318  p_len0 = clib_net_to_host_u16 (ip60->payload_length);
319  error0 =
320  ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
321 
322  if (PREDICT_TRUE (error0 == 0))
323  {
324  pkts_analysed++;
325  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
327  data0->pkt_counter++;
328  data0->bytes_counter +=
329  clib_net_to_host_u16 (ip60->payload_length);
331  }
332  else
333  pkts_failed++;
334  }
335 
336  /* verify speculative enqueue, maybe switch current next frame */
337  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
338  n_left_to_next, bi0, next0);
339  }
340 
341  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
342  }
343 
344  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_ANALYSED,
345  pkts_analysed);
346 
347  if (PREDICT_FALSE (pkts_failed))
348  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_FAILED,
349  pkts_failed);
350 
351  return frame->n_vectors;
352 }
353 
354 int
357 {
359  ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
360 
361  data = ioam_analyse_get_data_from_flow_id (flow_id);
362  ASSERT (data != NULL);
363 
364  (void) ip6_ioam_analyse_hbh_trace (data, &trace->trace_hdr, len,
365  (trace->hdr.length - 2)
366  /*ioam_trace_type,data_list_elts_left */
367  );
368  return 0;
369 }
370 
371 int
373  u16 len)
374 {
375 
376  ioam_pot_option_t *pot0;
377  u64 random = 0;
378  u64 cumulative = 0;
380  int ret;
382 
383  data = ioam_analyse_get_data_from_flow_id (flow_id);
384 
385  pot0 = (ioam_pot_option_t *) opt0;
386  random = clib_net_to_host_u64 (pot0->random);
387  cumulative = clib_net_to_host_u64 (pot0->cumulative);
388  pot_profile = pot_profile_get_active ();
389  ret = pot_validate (pot_profile, cumulative, random);
390 
392 
393  (0 == ret) ? (data->pot_data.sfc_validated_count++) :
395 
397  return 0;
398 }
399 
400 int
402  u16 len)
403 {
405  ioam_e2e_option_t *e2e;
406 
407  data = ioam_analyse_get_data_from_flow_id (flow_id);
408  e2e = (ioam_e2e_option_t *) opt;
409  ip6_ioam_analyse_hbh_e2e (data, &e2e->e2e_hdr, len);
410  return 0;
411 }
412 
413 int
415  int options (u32 flow_id,
417  opt, u16 len))
418 {
420 
421  ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
422 
423  /* Already registered */
424  if (am->analyse_hbh_handler[option])
425  return (-1);
426 
427  am->analyse_hbh_handler[option] = options;
428 
429  return (0);
430 }
431 
432 int
434 {
436 
437  ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
438 
439  /* Not registered */
440  if (!am->analyse_hbh_handler[option])
441  return (-1);
442 
443  am->analyse_hbh_handler[option] = NULL;
444  return (0);
445 }
446 
447 void
449 {
456 }
457 
458 void
460 {
466 }
467 
468 /* *INDENT-OFF* */
469 
470 /*
471  * Node for IP6 analyse - packets
472  */
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,
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 */
483  .next_nodes = {
484  [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
485  [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
486  },
487 };
488 
489 /*
490  * Node for IP6 analyse - packets
491  */
492 VLIB_REGISTER_NODE (analyse_node_remote) =
493 {
494  .function = ip6_ioam_analyse_node_fn,
495  .name = "ip6-hbh-analyse-remote",
496  .vector_size = sizeof (u32),
497  .format_trace = format_analyse_trace,
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 */
503  .next_nodes = {
504  [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
505  [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
506  },
507 };
508 
509 /* *INDENT-ON* */
510 
511 /*
512  * fd.io coding-style-patch-verification: ON
513  *
514  * Local Variables:
515  * eval: (c-set-style "gnu")
516  * End:
517  */
static pot_profile * pot_profile_get_active(void)
Definition: pot_util.h:170
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:870
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:100
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:78
#define CLIB_UNUSED(x)
Definition: clib.h:82
static int ip6_ioam_analyse_hbh_e2e(ioam_analyser_data_t *data, ioam_e2e_packet_t *e2e, u16 len)
Definition: ioam_analyse.h:415
int ip6_ioam_analyse_hbh_trace_internal(u32 flow_id, ip6_hop_by_hop_option_t *opt, u16 len)
Definition: node.c:355
int ip6_ioam_analyse_hbh_pot(u32 flow_id, ip6_hop_by_hop_option_t *opt0, u16 len)
Definition: node.c:372
#define PREDICT_TRUE(x)
Definition: clib.h:112
unsigned long u64
Definition: types.h:89
u32 bytes_counter
Num of bytes matching this flow.
Definition: ioam_analyse.h:112
#define NULL
Definition: clib.h:58
ioam_analyse_pot_data pot_data
Analysed iOAM pot data.
Definition: ioam_analyse.h:118
static ioam_analyser_data_t * ioam_analyse_get_data_from_flow_id(u32 flow_id)
int ip6_ioam_analyse_unregister_hbh_handler(u8 option)
Definition: node.c:433
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u8 data[128]
Definition: ipsec.api:249
unsigned char u8
Definition: types.h:56
#define HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
i64 word
Definition: types.h:111
IP6-iOAM analyser main structure.
void ip6_ioam_analyse_unregister_handlers()
Definition: node.c:459
#define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE
#define always_inline
Definition: clib.h:98
u32 pkt_counter
Num of pkts matching this flow.
Definition: ioam_analyse.h:109
ip6_ioam_analyser_main_t ioam_analyser_main
Definition: node.c:63
unsigned int u32
Definition: types.h:88
static u8 * format_analyse_trace(u8 *s, va_list *args)
Definition: node.c:67
analyse_next_t
Definition: node.c:56
vl_api_fib_path_type_t type
Definition: fib_types.api:123
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:111
u32 sfc_invalidated_count
Number of packets invalidated (failed through the service chain) within the timestamps.
Definition: ioam_analyse.h:92
u32 node_index
Node index.
Definition: node.h:494
u8 pot_validate(pot_profile *profile, u64 cumulative, u64 random)
Definition: pot_util.c:197
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
u8 len
Definition: ip_types.api:90
vlib_node_registration_t analyse_node_remote
(constructor) VLIB_REGISTER_NODE (analyse_node_remote)
Definition: node.c:36
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:395
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
vlib_main_t * vm
Definition: buffer.c:312
u32 flow_id
Definition: node.c:32
Usage:
Definition: pot_util.h:54
static uword ip6_ioam_analyse_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
IPv6 InBandOAM Analyse node.
Definition: node.c:141
#define ARRAY_LEN(x)
Definition: clib.h:62
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:458
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:513
u32 sfc_validated_count
Number of packets validated (passes through the service chain) within the timestamps.
Definition: ioam_analyse.h:88
#define ASSERT(truth)
#define foreach_analyse_error
Definition: node.c:38
static 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)
Definition: node.c:79
int ip6_ioam_analyse_hbh_e2e_internal(u32 flow_id, ip6_hop_by_hop_option_t *opt, u16 len)
Definition: node.c:401
int(* analyse_hbh_handler[MAX_IP6_HBH_OPTION])(u32 flow_id, ip6_hop_by_hop_option_t *opt, u16 len)
Array of function pointer to analyse each hop-by-hop option.
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:248
clib_spinlock_t writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:127
#define HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST
struct _vlib_node_registration vlib_node_registration_t
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:370
u16 payload_length
Definition: ip6_packet.h:374
static char * analyse_error_strings[]
Definition: node.c:50
Analysed iOAM data.
Definition: ioam_analyse.h:98
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
static int ip6_ioam_analyse_hbh_trace(ioam_analyser_data_t *data, ioam_trace_hdr_t *trace, u16 pak_len, u16 trace_len)
Definition: ioam_analyse.h:283
#define DEFAULT_EXPORT_SIZE
Definition: ioam_export.h:83
analyse_error_t
Definition: node.c:42
vlib_node_registration_t analyse_node_local
(constructor) VLIB_REGISTER_NODE (analyse_node_local)
Definition: node.c:35
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
void ip6_ioam_analyse_register_handlers()
Definition: node.c:448
u32 next_index
Definition: node.c:31
int ip6_ioam_analyse_register_hbh_handler(u8 option, int options(u32 flow_id, ip6_hop_by_hop_option_t *opt, u16 len))
Definition: node.c:414