FD.io VPP  v17.04-9-g99c0734
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 
82  ip6_hop_by_hop_option_t * limit0, u16 len)
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 
259  while (__sync_lock_test_and_set (data0->writer_lock, 1))
260  ;
261  data0->pkt_counter++;
262  data0->bytes_counter += p_len0;
263  *(data0->writer_lock) = 0;
264 
265  while (__sync_lock_test_and_set (data1->writer_lock, 1))
266  ;
267  data1->pkt_counter++;
268  data1->bytes_counter += p_len1;
269  *(data1->writer_lock) = 0;
270  }
271  else if (error0 == 0)
272  {
273  pkts_analysed++;
274  pkts_failed++;
275 
276  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
277  while (__sync_lock_test_and_set (data0->writer_lock, 1))
278  ;
279  data0->pkt_counter++;
280  data0->bytes_counter += p_len0;
281  *(data0->writer_lock) = 0;
282  }
283  else if (error1 == 0)
284  {
285  pkts_analysed++;
286  pkts_failed++;
287 
288  data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
289  while (__sync_lock_test_and_set (data1->writer_lock, 1))
290  ;
291  data1->pkt_counter++;
292  data1->bytes_counter += p_len1;
293  *(data1->writer_lock) = 0;
294  }
295  else
296  pkts_failed += 2;
297  }
298 
299  while (num_ioam_records > 0)
300  {
301  num_ioam_records--;
302 
303  ip6_header_t *ip60;
305  ip6_hop_by_hop_option_t *opt0, *limit0;
306  u32 flow_id0;
307  u8 error0;
308  ioam_analyser_data_t *data0;
309  u16 p_len0;
310 
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);
315  limit0 =
316  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
317  ((hbh0->length + 1) << 3));
318 
319  flow_id0 =
320  clib_net_to_host_u32
321  (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
322  p_len0 = clib_net_to_host_u16 (ip60->payload_length);
323  error0 =
324  ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
325 
326  if (PREDICT_TRUE (error0 == 0))
327  {
328  pkts_analysed++;
329  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
330  while (__sync_lock_test_and_set (data0->writer_lock, 1))
331  ;
332  data0->pkt_counter++;
333  data0->bytes_counter +=
334  clib_net_to_host_u16 (ip60->payload_length);
335  *(data0->writer_lock) = 0;
336  }
337  else
338  pkts_failed++;
339  }
340 
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);
344  }
345 
346  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
347  }
348 
349  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_ANALYSED,
350  pkts_analysed);
351 
352  if (PREDICT_FALSE (pkts_failed))
353  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_FAILED,
354  pkts_failed);
355 
356  return frame->n_vectors;
357 }
358 
359 int
361  ip6_hop_by_hop_option_t * opt, u16 len)
362 {
363  ioam_analyser_data_t *data;
364  ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
365 
366  data = ioam_analyse_get_data_from_flow_id (flow_id);
367  ASSERT (data != NULL);
368 
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 */
372  );
373  return 0;
374 }
375 
376 int
378  u16 len)
379 {
380 
381  ioam_pot_option_t *pot0;
382  u64 random = 0;
383  u64 cumulative = 0;
385  int ret;
386  ioam_analyser_data_t *data;
387 
388  data = ioam_analyse_get_data_from_flow_id (flow_id);
389 
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);
395 
396  while (__sync_lock_test_and_set (data->writer_lock, 1))
397  ;
398 
399  (0 == ret) ? (data->pot_data.sfc_validated_count++) :
401 
402  *(data->writer_lock) = 0;
403  return 0;
404 }
405 
406 int
408  u16 len)
409 {
410  ioam_analyser_data_t *data;
411  ioam_e2e_option_t *e2e;
412 
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);
416  return 0;
417 }
418 
419 int
421  int options (u32 flow_id,
423  opt, u16 len))
424 {
426 
427  ASSERT (option < ARRAY_LEN (am->analyse_hbh_handler));
428 
429  /* Already registered */
430  if (am->analyse_hbh_handler[option])
431  return (-1);
432 
433  am->analyse_hbh_handler[option] = options;
434 
435  return (0);
436 }
437 
438 int
440 {
442 
443  ASSERT (option < ARRAY_LEN (am->analyse_hbh_handler));
444 
445  /* Not registered */
446  if (!am->analyse_hbh_handler[option])
447  return (-1);
448 
449  am->analyse_hbh_handler[option] = NULL;
450  return (0);
451 }
452 
453 void
455 {
462 }
463 
464 void
466 {
472 }
473 
474 /* *INDENT-OFF* */
475 
476 /*
477  * Node for IP6 analyse - packets
478  */
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 */
489  .next_nodes = {
490  [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
491  [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
492  },
493 };
494 
495 /*
496  * Node for IP6 analyse - packets
497  */
498 VLIB_REGISTER_NODE (analyse_node_remote) =
499 {
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 */
509  .next_nodes = {
510  [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
511  [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
512  },
513 };
514 
515 /* *INDENT-ON* */
516 
517 /*
518  * fd.io coding-style-patch-verification: ON
519  *
520  * Local Variables:
521  * eval: (c-set-style "gnu")
522  * End:
523  */
static pot_profile * pot_profile_get_active(void)
Definition: pot_util.h:170
#define CLIB_UNUSED(x)
Definition: clib.h:79
static int ip6_ioam_analyse_hbh_e2e(ioam_analyser_data_t *data, ioam_e2e_packet_t *e2e, u16 len)
Definition: ioam_analyse.h:415
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: memory_vlib.c:1172
int ip6_ioam_analyse_hbh_trace_internal(u32 flow_id, ip6_hop_by_hop_option_t *opt, u16 len)
Definition: node.c:360
int ip6_ioam_analyse_hbh_pot(u32 flow_id, ip6_hop_by_hop_option_t *opt0, u16 len)
Definition: node.c:377
#define PREDICT_TRUE(x)
Definition: clib.h:98
u32 bytes_counter
Num of bytes matching this flow.
Definition: ioam_analyse.h:109
#define NULL
Definition: clib.h:55
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:459
ioam_analyse_pot_data pot_data
Analysed iOAM pot data.
Definition: ioam_analyse.h:115
static ioam_analyser_data_t * ioam_analyse_get_data_from_flow_id(u32 flow_id)
volatile u32 * writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:124
struct _vlib_node_registration vlib_node_registration_t
int ip6_ioam_analyse_unregister_hbh_handler(u8 option)
Definition: node.c:439
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
IP6-iOAM analyser main structure.
void ip6_ioam_analyse_unregister_handlers()
Definition: node.c:465
#define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE
#define always_inline
Definition: clib.h:84
u32 pkt_counter
Num of pkts matching this flow.
Definition: ioam_analyse.h:106
ip6_ioam_analyser_main_t ioam_analyser_main
Definition: node.c:63
unsigned long u64
Definition: types.h:89
static u8 * format_analyse_trace(u8 *s, va_list *args)
Definition: node.c:67
analyse_next_t
Definition: node.c:56
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
#define PREDICT_FALSE(x)
Definition: clib.h:97
u32 sfc_invalidated_count
Number of packets invalidated (failed through the service chain) within the timestamps.
Definition: ioam_analyse.h:91
u32 node_index
Node index.
Definition: node.h:436
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:216
#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:350
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1112
vlib_node_registration_t analyse_node_remote
(constructor) VLIB_REGISTER_NODE (analyse_node_remote)
Definition: node.c:36
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:276
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:59
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:455
u32 sfc_validated_count
Number of packets validated (passes through the service chain) within the timestamps.
Definition: ioam_analyse.h:87
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#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:407
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:201
#define HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST
u64 uword
Definition: types.h:112
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:328
unsigned short u16
Definition: types.h:57
u16 payload_length
Definition: ip6_packet.h:332
i64 word
Definition: types.h:111
static char * analyse_error_strings[]
Definition: node.c:50
unsigned char u8
Definition: types.h:56
Analysed iOAM data.
Definition: ioam_analyse.h:97
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
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:282
#define DEFAULT_EXPORT_SIZE
Definition: ioam_export.h:80
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
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
void ip6_ioam_analyse_register_handlers()
Definition: node.c:454
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:420