FD.io VPP  v17.07-30-g839fa73
Vector Packet Processing
ioam_analyse.h
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 #ifndef PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_
17 #define PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_
18 
19 #include <vlib/vlib.h>
20 #include <vnet/vnet.h>
21 #include <vppinfra/types.h>
22 #include <ioam/lib-e2e/e2e_util.h>
25 
26 #define IOAM_FLOW_TEMPLATE_ID 260
27 #define IOAM_TRACE_MAX_NODES 10
28 #define IOAM_MAX_PATHS_PER_FLOW 10
29 
30 typedef struct
31 {
37 
38 /** @brief Analysed iOAM trace data.
39  @note cache aligned.
40 */
41 typedef struct
42 {
43  /** No of nodes in path. */
45 
46  /** Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp. */
48 
49  /** Flag to indicate whether node is allocated. */
51 
52  u8 pad[5];
53 
54  /** Actual PATH flow has taken. */
56 
57  /** Num of pkts in the flow going over path. */
59 
60  /** Num of bytes in the flow going over path. */
62 
63  /** Minumum Dealay for the flow. */
65 
66  /** Maximum Dealay for the flow. */
68 
69  /** Average Dealay for the flow. */
71 
74 
75 typedef struct
76 {
79 
80 /** @brief Analysed iOAM pot data.
81  @note cache aligned.
82 */
83 typedef struct
84 {
85  /** Number of packets validated (passes through the service chain)
86  within the timestamps. */
88 
89  /** Number of packets invalidated (failed through the service chain)
90  within the timestamps. */
93 
94 /** @brief Analysed iOAM data.
95  @note cache aligned.
96 */
97 typedef struct ioam_analyser_data_t_
98 {
100  u8 pad[3];
101 
102  /** Num of pkts sent for this flow. */
104 
105  /** Num of pkts matching this flow. */
107 
108  /** Num of bytes matching this flow. */
110 
111  /** Analysed iOAM trace data. */
113 
114  /** Analysed iOAM pot data. */
116 
117  /** Analysed iOAM seqno data. */
119 
120  /** Cache of previously analysed data, useful for export. */
122 
123  /** Lock to since we use this to export the data in other thread. */
124  volatile u32 *writer_lock;
126 
128 ip6_ioam_analyse_calc_delay (ioam_trace_hdr_t * trace, u16 trace_len,
129  u8 oneway)
130 {
131  u16 size_of_all_traceopts;
132  u8 size_of_traceopt_per_node;
133  u8 num_nodes;
134  u32 *start_elt, *end_elt, *uturn_elt;;
135  u32 start_time, end_time;
136  u8 done = 0;
137 
138  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
139  // Unknown trace type
140  if (size_of_traceopt_per_node == 0)
141  return 0;
142  size_of_all_traceopts = trace_len; /*ioam_trace_type,data_list_elts_left */
143 
144  num_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
145  if ((num_nodes == 0) || (num_nodes <= trace->data_list_elts_left))
146  return 0;
147 
148  num_nodes -= trace->data_list_elts_left;
149 
150  start_elt = trace->elts;
151  end_elt =
152  trace->elts +
153  (u32) ((size_of_traceopt_per_node / sizeof (u32)) * (num_nodes - 1));
154 
155  if (oneway && (trace->ioam_trace_type & BIT_TTL_NODEID))
156  {
157  done = 0;
158  do
159  {
160  uturn_elt = start_elt - size_of_traceopt_per_node / sizeof (u32);
161 
162  if ((clib_net_to_host_u32 (*start_elt) >> 24) <=
163  (clib_net_to_host_u32 (*uturn_elt) >> 24))
164  done = 1;
165  }
166  while (!done && (start_elt = uturn_elt) != end_elt);
167  }
168  if (trace->ioam_trace_type & BIT_TTL_NODEID)
169  {
170  start_elt++;
171  end_elt++;
172  }
173  if (trace->ioam_trace_type & BIT_ING_INTERFACE)
174  {
175  start_elt++;
176  end_elt++;
177  }
178  start_time = clib_net_to_host_u32 (*start_elt);
179  end_time = clib_net_to_host_u32 (*end_elt);
180 
181  return (f64) (end_time - start_time);
182 }
183 
184 always_inline void
186 {
188  ioam_analyse_trace_record *trace_record;
189  ioam_path_map_t *path;
190  u8 k, i;
191 
192  while (__sync_lock_test_and_set (data->writer_lock, 1))
193  ;
194 
195  trace_data = &data->trace_data;
196 
197  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
198  {
199  trace_record = trace_data->path_data + i;
200 
201  if (trace_record->is_free)
202  continue;
203 
204  path = trace_record->path;
205 
206  for (k = 0; k < trace_record->num_nodes; k++)
207  path[k].state_up = 0;
208  }
209  *(data->writer_lock) = 0;
210 }
211 
212 always_inline void
214  ioam_trace_hdr_t * trace, u16 trace_len)
215 {
217  ioam_analyse_trace_record *trace_record;
218  ioam_path_map_t *path;
219  u8 i, j, k, num_nodes, max_nodes;
220  u8 *ptr;
221  u32 nodeid;
222  u16 ingress_if, egress_if;
223  u16 size_of_traceopt_per_node;
224  u16 size_of_all_traceopts;
225 
226  while (__sync_lock_test_and_set (data->writer_lock, 1))
227  ;
228 
229  trace_data = &data->trace_data;
230 
231  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
232  if (0 == size_of_traceopt_per_node)
233  goto end;
234 
235  size_of_all_traceopts = trace_len;
236 
237  ptr = (u8 *) trace->elts;
238  max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
239  num_nodes = max_nodes - trace->data_list_elts_left;
240 
241  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
242  {
243  trace_record = trace_data->path_data + i;
244  path = trace_record->path;
245 
246  if (trace_record->is_free)
247  continue;
248 
249  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
250  {
251  ptr =
252  (u8 *) ((u8 *) trace->elts +
253  (size_of_traceopt_per_node * (j - 1)));
254 
255  nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
256  ptr += 4;
257 
258  if (nodeid != path[k].node_id)
259  goto end;
260 
261  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
262  (trace->ioam_trace_type == TRACE_TYPE_IF))
263  {
264  ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
265  ptr += 2;
266  egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
267  if ((ingress_if != path[k].ingress_if) ||
268  (egress_if != path[k].egress_if))
269  {
270  goto end;
271  }
272  }
273  /* Found Match - set path hop state to up */
274  path[k].state_up = 1;
275  }
276  }
277 end:
278  *(data->writer_lock) = 0;
279 }
280 
281 always_inline int
283  ioam_trace_hdr_t * trace, u16 pak_len,
284  u16 trace_len)
285 {
287  u16 size_of_traceopt_per_node;
288  u16 size_of_all_traceopts;
289  u8 i, j, k, num_nodes, max_nodes;
290  u8 *ptr;
291  u32 nodeid;
292  u16 ingress_if, egress_if;
293  ioam_path_map_t *path = NULL;
294  ioam_analyse_trace_record *trace_record;
295 
296  while (__sync_lock_test_and_set (data->writer_lock, 1))
297  ;
298 
299  trace_data = &data->trace_data;
300 
301  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
302  // Unknown trace type
303  if (size_of_traceopt_per_node == 0)
304  goto DONE;
305  size_of_all_traceopts = trace_len;
306 
307  ptr = (u8 *) trace->elts;
308  max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
309  num_nodes = max_nodes - trace->data_list_elts_left;
310 
311  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
312  {
313  trace_record = trace_data->path_data + i;
314 
315  if (trace_record->is_free ||
316  (num_nodes != trace_record->num_nodes) ||
317  (trace->ioam_trace_type != trace_record->trace_type))
318  continue;
319 
320  path = trace_record->path;
321 
322  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
323  {
324  ptr =
325  (u8 *) ((u8 *) trace->elts +
326  (size_of_traceopt_per_node * (j - 1)));
327 
328  nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
329  ptr += 4;
330 
331  if (nodeid != path[k].node_id)
332  break;
333 
334  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
335  (trace->ioam_trace_type == TRACE_TYPE_IF))
336  {
337  ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
338  ptr += 2;
339  egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
340  if ((ingress_if != path[k].ingress_if) ||
341  (egress_if != path[k].egress_if))
342  {
343  break;
344  }
345  }
346  }
347 
348  if (k == num_nodes)
349  {
350  goto found_match;
351  }
352  }
353 
354  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
355  {
356  trace_record = trace_data->path_data + i;
357  if (trace_record->is_free)
358  {
359  trace_record->is_free = 0;
360  trace_record->num_nodes = num_nodes;
361  trace_record->trace_type = trace->ioam_trace_type;
362  path = trace_data->path_data[i].path;
363  trace_record->pkt_counter = 0;
364  trace_record->bytes_counter = 0;
365  trace_record->min_delay = 0xFFFFFFFF;
366  trace_record->max_delay = 0;
367  trace_record->mean_delay = 0;
368  break;
369  }
370  }
371 
372  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
373  {
374  ptr =
375  (u8 *) ((u8 *) trace->elts + (size_of_traceopt_per_node * (j - 1)));
376 
377  path[k].node_id = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
378  ptr += 4;
379 
380  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
381  (trace->ioam_trace_type == TRACE_TYPE_IF))
382  {
383  path[k].ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
384  ptr += 2;
385  path[k].egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
386  }
387  }
388 
389 found_match:
390  /* Set path state to UP */
391  for (k = 0; k < num_nodes; k++)
392  path[k].state_up = 1;
393 
394  trace_record->pkt_counter++;
395  trace_record->bytes_counter += pak_len;
396  if (trace->ioam_trace_type & BIT_TIMESTAMP)
397  {
398  /* Calculate time delay */
399  u32 delay = (u32) ip6_ioam_analyse_calc_delay (trace, trace_len, 0);
400  if (delay < trace_record->min_delay)
401  trace_record->min_delay = delay;
402  else if (delay > trace_record->max_delay)
403  trace_record->max_delay = delay;
404 
405  u64 sum = (trace_record->mean_delay * data->seqno_data.rx_packets);
406  trace_record->mean_delay =
407  (u32) ((sum + delay) / (data->seqno_data.rx_packets + 1));
408  }
409 DONE:
410  *(data->writer_lock) = 0;
411  return 0;
412 }
413 
414 always_inline int
416  ioam_e2e_packet_t * e2e, u16 len)
417 {
418  while (__sync_lock_test_and_set (data->writer_lock, 1))
419  ;
420 
422  (u64) clib_net_to_host_u32 (e2e->e2e_data));
423 
424  *(data->writer_lock) = 0;
425  return 0;
426 }
427 
429 format_path_map (u8 * s, va_list * args)
430 {
431  ioam_path_map_t *pm = va_arg (*args, ioam_path_map_t *);
432  u32 num_of_elts = va_arg (*args, u32);
433  u32 i;
434 
435  for (i = 0; i < num_of_elts; i++)
436  {
437  s =
438  format (s,
439  "node_id: 0x%x, ingress_if: 0x%x, egress_if:0x%x, state:%s\n",
440  pm->node_id, pm->ingress_if, pm->egress_if,
441  pm->state_up ? "UP" : "DOWN");
442  pm++;
443  }
444 
445  return (s);
446 }
447 
450 {
451  int j;
452  ioam_analyse_trace_record *trace_record;
453 
454  s = format (s, "pkt_sent : %u\n", record->pkt_sent);
455  s = format (s, "pkt_counter : %u\n", record->pkt_counter);
456  s = format (s, "bytes_counter : %u\n", record->bytes_counter);
457 
458  s = format (s, "Trace data: \n");
459 
460  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
461  {
462  trace_record = record->trace_data.path_data + j;
463  if (trace_record->is_free)
464  continue;
465 
466  s = format (s, "path_map:\n%U", format_path_map,
467  trace_record->path, trace_record->num_nodes);
468  s = format (s, "pkt_counter: %u\n", trace_record->pkt_counter);
469  s = format (s, "bytes_counter: %u\n", trace_record->bytes_counter);
470 
471  s = format (s, "min_delay: %u\n", trace_record->min_delay);
472  s = format (s, "max_delay: %u\n", trace_record->max_delay);
473  s = format (s, "mean_delay: %u\n", trace_record->mean_delay);
474  }
475 
476  s = format (s, "\nPOT data: \n");
477  s = format (s, "sfc_validated_count : %u\n",
478  record->pot_data.sfc_validated_count);
479  s = format (s, "sfc_invalidated_count : %u\n",
481 
482  s = format (s, "\nSeqno Data:\n");
483  s = format (s,
484  "RX Packets : %lu\n"
485  "Lost Packets : %lu\n"
486  "Duplicate Packets : %lu\n"
487  "Reordered Packets : %lu\n",
488  record->seqno_data.rx_packets,
489  record->seqno_data.lost_packets,
490  record->seqno_data.dup_packets,
491  record->seqno_data.reordered_packets);
492 
493  s = format (s, "\n");
494  return s;
495 }
496 
497 always_inline void
499 {
500  u16 j;
502 
503  data->is_free = 1;
504 
505  /* We maintain data corresponding to last IP-Fix export, this may
506  * get extended in future to maintain history of data */
508 
511  *(data->writer_lock) = 0;
512 
513  trace_data = &(data->trace_data);
514  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
515  trace_data->path_data[j].is_free = 1;
516 }
517 
518 #endif /* PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_ */
519 
520 /*
521  * fd.io coding-style-patch-verification: ON
522  *
523  * Local Variables:
524  * eval: (c-set-style "gnu")
525  * End:
526  */
u32 bytes_counter
Num of bytes in the flow going over path.
Definition: ioam_analyse.h:61
u8 pad[3]
log2 (size of the packing page block)
Definition: bihash_doc.h:61
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
u32 max_delay
Maximum Dealay for the flow.
Definition: ioam_analyse.h:67
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 u8 * print_analyse_flow(u8 *s, ioam_analyser_data_t *record)
Definition: ioam_analyse.h:449
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: memory_vlib.c:1173
ioam_path_map_t path[IOAM_TRACE_MAX_NODES]
Actual PATH flow has taken.
Definition: ioam_analyse.h:55
u32 min_delay
Minumum Dealay for the flow.
Definition: ioam_analyse.h:64
#define TRACE_TYPE_IF_TS_APP
Definition: trace_util.h:116
seqno_rx_info seqno_data
Analysed iOAM seqno data.
Definition: ioam_analyse.h:118
u32 bytes_counter
Num of bytes matching this flow.
Definition: ioam_analyse.h:109
static void ioam_analyse_init_data(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:498
#define NULL
Definition: clib.h:55
ioam_analyse_pot_data pot_data
Analysed iOAM pot data.
Definition: ioam_analyse.h:115
volatile u32 * writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:124
#define IOAM_TRACE_MAX_NODES
Definition: ioam_analyse.h:27
u32 pkt_sent
Num of pkts sent for this flow.
Definition: ioam_analyse.h:103
static u8 fetch_trace_data_size(u16 trace_type)
Definition: trace_util.h:209
static f64 ip6_ioam_analyse_calc_delay(ioam_trace_hdr_t *trace, u16 trace_len, u8 oneway)
Definition: ioam_analyse.h:128
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
static void ioam_analyze_seqno(seqno_rx_info *seqno_rx, u64 seqno)
Analysed iOAM trace data.
Definition: ioam_analyse.h:41
static void ip6_ioam_analyse_set_paths_down(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:185
u32 pkt_counter
Num of pkts in the flow going over path.
Definition: ioam_analyse.h:58
#define always_inline
Definition: clib.h:84
u32 pkt_counter
Num of pkts matching this flow.
Definition: ioam_analyse.h:106
unsigned long u64
Definition: types.h:89
static u8 * format_path_map(u8 *s, va_list *args)
Definition: ioam_analyse.h:429
#define IOAM_MAX_PATHS_PER_FLOW
Definition: ioam_analyse.h:28
ioam_analyse_trace_data trace_data
Analysed iOAM trace data.
Definition: ioam_analyse.h:112
u32 sfc_invalidated_count
Number of packets invalidated (failed through the service chain) within the timestamps.
Definition: ioam_analyse.h:91
#define TRACE_TYPE_IF
Definition: trace_util.h:138
struct ioam_analyser_data_t_ * chached_data_list
Cache of previously analysed data, useful for export.
Definition: ioam_analyse.h:121
#define BIT_ING_INTERFACE
Definition: trace_util.h:90
struct ioam_analyser_data_t_ ioam_analyser_data_t
Analysed iOAM data.
#define BIT_TTL_NODEID
Definition: trace_util.h:89
u32 sfc_validated_count
Number of packets validated (passes through the service chain) within the timestamps.
Definition: ioam_analyse.h:87
unsigned int u32
Definition: types.h:88
Analysed iOAM pot data.
Definition: ioam_analyse.h:83
unsigned short u16
Definition: types.h:57
u8 trace_type
Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp.
Definition: ioam_analyse.h:47
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
Analysed iOAM data.
Definition: ioam_analyse.h:97
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
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
u8 is_free
Flag to indicate whether node is allocated.
Definition: ioam_analyse.h:50
u8 num_nodes
No of nodes in path.
Definition: ioam_analyse.h:44
static void ip6_ioam_analyse_hbh_trace_loopback(ioam_analyser_data_t *data, ioam_trace_hdr_t *trace, u16 trace_len)
Definition: ioam_analyse.h:213
u32 mean_delay
Average Dealay for the flow.
Definition: ioam_analyse.h:70
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW]
Definition: ioam_analyse.h:77
#define BIT_TIMESTAMP
Definition: trace_util.h:92