FD.io VPP  v19.08.1-401-g8e4ed521a
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/ethernet/ethernet.h>
20 #include <vnet/ip/ip.h>
24 #include <ioam/lib-pot/pot_util.h>
28 #include <vnet/plugin/plugin.h>
29 
30 typedef struct
31 {
35 
38 
39 #define foreach_analyse_error \
40 _(ANALYSED, "Packets analysed for summarization") \
41 _(FAILED, "Packets analysis failed") \
42 
43 typedef enum
44 {
45 #define _(sym,str) ANALYSE_ERROR_##sym,
47 #undef _
50 
51 static char *analyse_error_strings[] = {
52 #define _(sym,string) string,
54 #undef _
55 };
56 
57 typedef enum
58 {
63 
65 
66 /* packet trace format function */
67 static u8 *
68 format_analyse_trace (u8 * s, va_list * args)
69 {
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 *);
73 
74  s = format (s, "IP6-ioam-analyse: flow_id %d, next index %d",
75  t->flow_id, t->next_index);
76  return s;
77 }
78 
84 {
86  u8 type0;
87  u8 error0 = 0;
88 
89  while (opt0 < limit0)
90  {
91  type0 = opt0->type;
92  switch (type0)
93  {
94  case 0: /* Pad1 */
95  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
96  continue;
97  case 1: /* PadN */
98  break;
99  default:
100  if (am->analyse_hbh_handler[type0])
101  {
102  if (PREDICT_TRUE
103  ((*am->analyse_hbh_handler[type0]) (flow_id, opt0,
104  len) < 0))
105  {
106  error0 = ANALYSE_ERROR_FAILED;
107  return (error0);
108  }
109  }
110  }
111  opt0 =
112  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
113  sizeof (ip6_hop_by_hop_option_t));
114  }
115  return (error0);
116 }
117 
118 /**
119  * @brief IPv6 InBandOAM Analyse node.
120  * @node ip6-hbh-analyse-local, ip6-hbh-analyse-remote
121  *
122  * This function receives IP-FIX packets containing IPv6-iOAM records, analyses
123  * them and collects/aggregates the statistics.
124  *
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.
128  *
129  * @par Graph mechanics: buffer, next index usage
130  *
131  * <em>Uses:</em>
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.
135  *
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
139  * context.
140  */
141 static uword
143  vlib_frame_t * frame)
144 {
145  u32 n_left_from, *from, *to_next;
146  analyse_next_t next_index;
147  u32 pkts_analysed = 0;
148  u32 pkts_failed = 0;
149  u8 remote = 0;
151 
152  from = vlib_frame_vector_args (frame);
153  n_left_from = frame->n_vectors;
154  next_index = node->cached_next_index;
155 
156  if (PREDICT_FALSE (analyse_node_remote.index == node->node_index))
157  {
158  remote = 1;
159  next0 = ANALYSE_NEXT_IP4_DROP;
160  }
161 
162  while (n_left_from > 0)
163  {
164  u32 n_left_to_next;
165 
166  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
167 
168  while (n_left_from > 0 && n_left_to_next > 0)
169  {
170  u32 bi0;
171  vlib_buffer_t *p0;
172  ip4_header_t *ip40;
173  u8 *data, *limit;
174  u16 num_ioam_records;
175 
176  /* speculatively enqueue p0 to the current next frame */
177  bi0 = from[0];
178  to_next[0] = bi0;
179  from += 1;
180  to_next += 1;
181  n_left_from -= 1;
182  n_left_to_next -= 1;
183 
184  p0 = vlib_get_buffer (vm, bi0);
185  if (PREDICT_FALSE (remote))
186  {
187  vlib_buffer_advance (p0, -(word) (sizeof (udp_header_t) +
188  sizeof (ip4_header_t) +
189  sizeof
191  sizeof (ipfix_set_header_t)));
192  }
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);
198 
199  num_ioam_records = (limit - data) / DEFAULT_EXPORT_SIZE;
200 
201  while (num_ioam_records >= 4)
202  {
203  /* Prefetch next 2 ioam records */
204  {
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);
209  }
210 
211  num_ioam_records -= 2;
212 
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;
217  u8 error0, error1;
218  ioam_analyser_data_t *data0, *data1;
219  u16 p_len0, p_len1;
220 
221  ip60 = (ip6_header_t *) data;
222  ip61 = (ip6_header_t *) (data + DEFAULT_EXPORT_SIZE);
223 
224  data += (2 * DEFAULT_EXPORT_SIZE);
225 
226  hbh0 = (ip6_hop_by_hop_header_t *) (ip60 + 1);
227  hbh1 = (ip6_hop_by_hop_header_t *) (ip61 + 1);
228 
229  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
230  opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
231 
232  limit0 =
233  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
234  ((hbh0->length + 1) << 3));
235  limit1 =
236  (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
237  ((hbh1->length + 1) << 3));
238 
239  flow_id0 =
240  clib_net_to_host_u32
241  (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
242  flow_id1 =
243  clib_net_to_host_u32
244  (ip61->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
245 
246  p_len0 = clib_net_to_host_u16 (ip60->payload_length);
247  p_len1 = clib_net_to_host_u16 (ip61->payload_length);
248 
249  error0 =
250  ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
251  error1 =
252  ioam_analyse_hbh (flow_id1, hbh1, opt1, limit1, p_len0);
253 
254  if (PREDICT_TRUE ((error0 == 0) && (error1 == 0)))
255  {
256  pkts_analysed += 2;
257  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
258  data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
259 
261  data0->pkt_counter++;
262  data0->bytes_counter += p_len0;
264 
266  data1->pkt_counter++;
267  data1->bytes_counter += p_len1;
269  }
270  else if (error0 == 0)
271  {
272  pkts_analysed++;
273  pkts_failed++;
274 
275  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
277  data0->pkt_counter++;
278  data0->bytes_counter += p_len0;
280  }
281  else if (error1 == 0)
282  {
283  pkts_analysed++;
284  pkts_failed++;
285 
286  data1 = ioam_analyse_get_data_from_flow_id (flow_id1);
288  data1->pkt_counter++;
289  data1->bytes_counter += p_len1;
291  }
292  else
293  pkts_failed += 2;
294  }
295 
296  while (num_ioam_records > 0)
297  {
298  num_ioam_records--;
299 
300  ip6_header_t *ip60;
302  ip6_hop_by_hop_option_t *opt0, *limit0;
303  u32 flow_id0;
304  u8 error0;
305  ioam_analyser_data_t *data0;
306  u16 p_len0;
307 
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);
312  limit0 =
313  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
314  ((hbh0->length + 1) << 3));
315 
316  flow_id0 =
317  clib_net_to_host_u32
318  (ip60->ip_version_traffic_class_and_flow_label) & 0xFFFFF;
319  p_len0 = clib_net_to_host_u16 (ip60->payload_length);
320  error0 =
321  ioam_analyse_hbh (flow_id0, hbh0, opt0, limit0, p_len0);
322 
323  if (PREDICT_TRUE (error0 == 0))
324  {
325  pkts_analysed++;
326  data0 = ioam_analyse_get_data_from_flow_id (flow_id0);
328  data0->pkt_counter++;
329  data0->bytes_counter +=
330  clib_net_to_host_u16 (ip60->payload_length);
332  }
333  else
334  pkts_failed++;
335  }
336 
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);
340  }
341 
342  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
343  }
344 
345  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_ANALYSED,
346  pkts_analysed);
347 
348  if (PREDICT_FALSE (pkts_failed))
349  vlib_node_increment_counter (vm, node->node_index, ANALYSE_ERROR_FAILED,
350  pkts_failed);
351 
352  return frame->n_vectors;
353 }
354 
355 int
358 {
360  ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
361 
362  data = ioam_analyse_get_data_from_flow_id (flow_id);
363  ASSERT (data != NULL);
364 
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 */
368  );
369  return 0;
370 }
371 
372 int
374  u16 len)
375 {
376 
377  ioam_pot_option_t *pot0;
378  u64 random = 0;
379  u64 cumulative = 0;
381  int ret;
383 
384  data = ioam_analyse_get_data_from_flow_id (flow_id);
385 
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);
391 
393 
394  (0 == ret) ? (data->pot_data.sfc_validated_count++) :
396 
398  return 0;
399 }
400 
401 int
403  u16 len)
404 {
406  ioam_e2e_option_t *e2e;
407 
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);
411  return 0;
412 }
413 
414 int
416  int options (u32 flow_id,
418  opt, u16 len))
419 {
421 
422  ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
423 
424  /* Already registered */
425  if (am->analyse_hbh_handler[option])
426  return (-1);
427 
428  am->analyse_hbh_handler[option] = options;
429 
430  return (0);
431 }
432 
433 int
435 {
437 
438  ASSERT ((u32) option < ARRAY_LEN (am->analyse_hbh_handler));
439 
440  /* Not registered */
441  if (!am->analyse_hbh_handler[option])
442  return (-1);
443 
444  am->analyse_hbh_handler[option] = NULL;
445  return (0);
446 }
447 
448 void
450 {
457 }
458 
459 void
461 {
467 }
468 
469 /* *INDENT-OFF* */
470 
471 /*
472  * Node for IP6 analyse - packets
473  */
474 VLIB_REGISTER_NODE (analyse_node_local) = {
475  .function = ip6_ioam_analyse_node_fn,
476  .name = "ip6-hbh-analyse-local",
477  .vector_size = sizeof (u32),
478  .format_trace = format_analyse_trace,
480  .n_errors = ARRAY_LEN (analyse_error_strings),
481  .error_strings = analyse_error_strings,
482  .n_next_nodes = ANALYSE_N_NEXT,
483  /* edit / add dispositions here */
484  .next_nodes = {
485  [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
486  [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
487  },
488 };
489 
490 /*
491  * Node for IP6 analyse - packets
492  */
493 VLIB_REGISTER_NODE (analyse_node_remote) =
494 {
495  .function = ip6_ioam_analyse_node_fn,
496  .name = "ip6-hbh-analyse-remote",
497  .vector_size = sizeof (u32),
498  .format_trace = format_analyse_trace,
500  .n_errors = ARRAY_LEN (analyse_error_strings),
501  .error_strings = analyse_error_strings,
502  .n_next_nodes = ANALYSE_N_NEXT,
503  /* edit / add dispositions here */
504  .next_nodes = {
505  [ANALYSE_NEXT_IP4_LOOKUP] = "ip4-lookup",
506  [ANALYSE_NEXT_IP4_DROP] = "ip4-drop",
507  },
508 };
509 
510 /* *INDENT-ON* */
511 
512 /*
513  * fd.io coding-style-patch-verification: ON
514  *
515  * Local Variables:
516  * eval: (c-set-style "gnu")
517  * End:
518  */
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:889
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:102
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:80
#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:356
int ip6_ioam_analyse_hbh_pot(u32 flow_id, ip6_hop_by_hop_option_t *opt0, u16 len)
Definition: node.c:373
#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:434
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u8 data[128]
Definition: ipsec.api:251
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:460
#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:64
unsigned int u32
Definition: types.h:88
static u8 * format_analyse_trace(u8 *s, va_list *args)
Definition: node.c:68
analyse_next_t
Definition: node.c:57
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:496
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:37
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:397
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
vlib_main_t * vm
Definition: buffer.c:323
u32 flow_id
Definition: node.c:33
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:142
#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:456
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
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:39
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:80
int ip6_ioam_analyse_hbh_e2e_internal(u32 flow_id, ip6_hop_by_hop_option_t *opt, u16 len)
Definition: node.c:402
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:51
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:43
static struct option options[]
Definition: main.c:52
vlib_node_registration_t analyse_node_local
(constructor) VLIB_REGISTER_NODE (analyse_node_local)
Definition: node.c:36
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:449
u32 next_index
Definition: node.c:32
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:415