FD.io VPP  v19.08-27-gf4dcae4
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 #include <vppinfra/lock.h>
26 
27 #define IOAM_FLOW_TEMPLATE_ID 260
28 #define IOAM_TRACE_MAX_NODES 10
29 #define IOAM_MAX_PATHS_PER_FLOW 10
30 
31 typedef struct
32 {
38 
39 /** @brief Analysed iOAM trace data.
40  @note cache aligned.
41 */
42 typedef struct
43 {
44  /** No of nodes in path. */
46 
47  /** Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp. */
49 
50  /** Flag to indicate whether node is allocated. */
52 
53  u8 pad[5];
54 
55  /** Actual PATH flow has taken. */
57 
58  /** Num of pkts in the flow going over path. */
60 
61  /** Num of bytes in the flow going over path. */
63 
64  /** Minumum Dealay for the flow. */
66 
67  /** Maximum Dealay for the flow. */
69 
70  /** Average Dealay for the flow. */
72 
75 
76 typedef struct
77 {
80 
81 /** @brief Analysed iOAM pot data.
82  @note cache aligned.
83 */
84 typedef struct
85 {
86  /** Number of packets validated (passes through the service chain)
87  within the timestamps. */
89 
90  /** Number of packets invalidated (failed through the service chain)
91  within the timestamps. */
94 
95 /** @brief Analysed iOAM data.
96  @note cache aligned.
97 */
98 typedef struct ioam_analyser_data_t_
99 {
100  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
101 
103  u8 pad[3];
104 
105  /** Num of pkts sent for this flow. */
107 
108  /** Num of pkts matching this flow. */
110 
111  /** Num of bytes matching this flow. */
113 
114  /** Analysed iOAM trace data. */
116 
117  /** Analysed iOAM pot data. */
119 
120  /** Analysed iOAM seqno data. */
122 
123  /** Cache of previously analysed data, useful for export. */
125 
126  /** Lock to since we use this to export the data in other thread. */
129 
131 ip6_ioam_analyse_calc_delay (ioam_trace_hdr_t * trace, u16 trace_len,
132  u8 oneway)
133 {
134  u16 size_of_all_traceopts;
135  u8 size_of_traceopt_per_node;
136  u8 num_nodes;
137  u32 *start_elt, *end_elt, *uturn_elt;;
138  u32 start_time, end_time;
139  u8 done = 0;
140 
141  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
142  // Unknown trace type
143  if (size_of_traceopt_per_node == 0)
144  return 0;
145  size_of_all_traceopts = trace_len; /*ioam_trace_type,data_list_elts_left */
146 
147  num_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
148  if ((num_nodes == 0) || (num_nodes <= trace->data_list_elts_left))
149  return 0;
150 
151  num_nodes -= trace->data_list_elts_left;
152 
153  start_elt = trace->elts;
154  end_elt =
155  trace->elts +
156  (u32) ((size_of_traceopt_per_node / sizeof (u32)) * (num_nodes - 1));
157 
158  if (oneway && (trace->ioam_trace_type & BIT_TTL_NODEID))
159  {
160  done = 0;
161  do
162  {
163  uturn_elt = start_elt - size_of_traceopt_per_node / sizeof (u32);
164 
165  if ((clib_net_to_host_u32 (*start_elt) >> 24) <=
166  (clib_net_to_host_u32 (*uturn_elt) >> 24))
167  done = 1;
168  }
169  while (!done && (start_elt = uturn_elt) != end_elt);
170  }
171  if (trace->ioam_trace_type & BIT_TTL_NODEID)
172  {
173  start_elt++;
174  end_elt++;
175  }
176  if (trace->ioam_trace_type & BIT_ING_INTERFACE)
177  {
178  start_elt++;
179  end_elt++;
180  }
181  start_time = clib_net_to_host_u32 (*start_elt);
182  end_time = clib_net_to_host_u32 (*end_elt);
183 
184  return (f64) (end_time - start_time);
185 }
186 
187 always_inline void
189 {
191  ioam_analyse_trace_record *trace_record;
192  ioam_path_map_t *path;
193  u8 k, i;
194 
196 
197  trace_data = &data->trace_data;
198 
199  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
200  {
201  trace_record = trace_data->path_data + i;
202 
203  if (trace_record->is_free)
204  continue;
205 
206  path = trace_record->path;
207 
208  for (k = 0; k < trace_record->num_nodes; k++)
209  path[k].state_up = 0;
210  }
212 }
213 
214 always_inline void
216  ioam_trace_hdr_t * trace, u16 trace_len)
217 {
219  ioam_analyse_trace_record *trace_record;
220  ioam_path_map_t *path;
221  u8 i, j, k, num_nodes, max_nodes;
222  u8 *ptr;
223  u32 nodeid;
224  u16 ingress_if, egress_if;
225  u16 size_of_traceopt_per_node;
226  u16 size_of_all_traceopts;
227 
229 
230  trace_data = &data->trace_data;
231 
232  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
233  if (0 == size_of_traceopt_per_node)
234  goto end;
235 
236  size_of_all_traceopts = trace_len;
237 
238  ptr = (u8 *) trace->elts;
239  max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
240  num_nodes = max_nodes - trace->data_list_elts_left;
241 
242  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
243  {
244  trace_record = trace_data->path_data + i;
245  path = trace_record->path;
246 
247  if (trace_record->is_free)
248  continue;
249 
250  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
251  {
252  ptr =
253  (u8 *) ((u8 *) trace->elts +
254  (size_of_traceopt_per_node * (j - 1)));
255 
256  nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
257  ptr += 4;
258 
259  if (nodeid != path[k].node_id)
260  goto end;
261 
262  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
263  (trace->ioam_trace_type == TRACE_TYPE_IF))
264  {
265  ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
266  ptr += 2;
267  egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
268  if ((ingress_if != path[k].ingress_if) ||
269  (egress_if != path[k].egress_if))
270  {
271  goto end;
272  }
273  }
274  /* Found Match - set path hop state to up */
275  path[k].state_up = 1;
276  }
277  }
278 end:
280 }
281 
282 always_inline int
284  ioam_trace_hdr_t * trace, u16 pak_len,
285  u16 trace_len)
286 {
288  u16 size_of_traceopt_per_node;
289  u16 size_of_all_traceopts;
290  u8 i, j, k, num_nodes, max_nodes;
291  u8 *ptr;
292  u32 nodeid;
293  u16 ingress_if, egress_if;
294  ioam_path_map_t *path = NULL;
295  ioam_analyse_trace_record *trace_record;
296 
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:
411  return 0;
412 }
413 
414 always_inline int
416  ioam_e2e_packet_t * e2e, u16 len)
417 {
419 
421  (u64) clib_net_to_host_u32 (e2e->e2e_data));
422 
424 
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 
510 
511  trace_data = &(data->trace_data);
512  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
513  trace_data->path_data[j].is_free = 1;
514 }
515 
516 #endif /* PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_ */
517 
518 /*
519  * fd.io coding-style-patch-verification: ON
520  *
521  * Local Variables:
522  * eval: (c-set-style "gnu")
523  * End:
524  */
u32 bytes_counter
Num of bytes in the flow going over path.
Definition: ioam_analyse.h:62
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:870
u8 pad[3]
log2 (size of the packing page block)
Definition: bihash_doc.h:61
u32 max_delay
Maximum Dealay for the flow.
Definition: ioam_analyse.h:68
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
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
ioam_path_map_t path[IOAM_TRACE_MAX_NODES]
Actual PATH flow has taken.
Definition: ioam_analyse.h:56
u32 min_delay
Minumum Dealay for the flow.
Definition: ioam_analyse.h:65
#define TRACE_TYPE_IF_TS_APP
Definition: trace_util.h:116
seqno_rx_info seqno_data
Analysed iOAM seqno data.
Definition: ioam_analyse.h:121
unsigned long u64
Definition: types.h:89
u32 bytes_counter
Num of bytes matching this flow.
Definition: ioam_analyse.h:112
static void ioam_analyse_init_data(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:498
#define NULL
Definition: clib.h:58
ioam_analyse_pot_data pot_data
Analysed iOAM pot data.
Definition: ioam_analyse.h:118
#define IOAM_TRACE_MAX_NODES
Definition: ioam_analyse.h:28
u32 pkt_sent
Num of pkts sent for this flow.
Definition: ioam_analyse.h:106
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:131
CLIB_CACHE_LINE_ALIGN_MARK(cacheline0)
int i
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u8 data[128]
Definition: ipsec.api:249
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:450
unsigned char u8
Definition: types.h:56
static void ioam_analyze_seqno(seqno_rx_info *seqno_rx, u64 seqno)
double f64
Definition: types.h:142
Analysed iOAM trace data.
Definition: ioam_analyse.h:42
static void ip6_ioam_analyse_set_paths_down(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:188
u32 pkt_counter
Num of pkts in the flow going over path.
Definition: ioam_analyse.h:59
#define always_inline
Definition: clib.h:98
u32 pkt_counter
Num of pkts matching this flow.
Definition: ioam_analyse.h:109
unsigned int u32
Definition: types.h:88
static u8 * format_path_map(u8 *s, va_list *args)
Definition: ioam_analyse.h:429
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:61
#define IOAM_MAX_PATHS_PER_FLOW
Definition: ioam_analyse.h:29
ioam_analyse_trace_data trace_data
Analysed iOAM trace data.
Definition: ioam_analyse.h:115
unsigned short u16
Definition: types.h:57
u32 sfc_invalidated_count
Number of packets invalidated (failed through the service chain) within the timestamps.
Definition: ioam_analyse.h:92
#define TRACE_TYPE_IF
Definition: trace_util.h:138
u8 len
Definition: ip_types.api:90
struct ioam_analyser_data_t_ * chached_data_list
Cache of previously analysed data, useful for export.
Definition: ioam_analyse.h:124
#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:88
Analysed iOAM pot data.
Definition: ioam_analyse.h:84
clib_spinlock_t writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:127
u8 trace_type
Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp.
Definition: ioam_analyse.h:48
Analysed iOAM data.
Definition: ioam_analyse.h:98
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
u8 is_free
Flag to indicate whether node is allocated.
Definition: ioam_analyse.h:51
u8 num_nodes
No of nodes in path.
Definition: ioam_analyse.h:45
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:215
u32 mean_delay
Average Dealay for the flow.
Definition: ioam_analyse.h:71
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW]
Definition: ioam_analyse.h:78
#define BIT_TIMESTAMP
Definition: trace_util.h:92