FD.io VPP  v18.07.1-19-g511ce25
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 {
99  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
100 
102  u8 pad[3];
103 
104  /** Num of pkts sent for this flow. */
106 
107  /** Num of pkts matching this flow. */
109 
110  /** Num of bytes matching this flow. */
112 
113  /** Analysed iOAM trace data. */
115 
116  /** Analysed iOAM pot data. */
118 
119  /** Analysed iOAM seqno data. */
121 
122  /** Cache of previously analysed data, useful for export. */
124 
125  /** Lock to since we use this to export the data in other thread. */
126  volatile u32 *writer_lock;
128 
130 ip6_ioam_analyse_calc_delay (ioam_trace_hdr_t * trace, u16 trace_len,
131  u8 oneway)
132 {
133  u16 size_of_all_traceopts;
134  u8 size_of_traceopt_per_node;
135  u8 num_nodes;
136  u32 *start_elt, *end_elt, *uturn_elt;;
137  u32 start_time, end_time;
138  u8 done = 0;
139 
140  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
141  // Unknown trace type
142  if (size_of_traceopt_per_node == 0)
143  return 0;
144  size_of_all_traceopts = trace_len; /*ioam_trace_type,data_list_elts_left */
145 
146  num_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
147  if ((num_nodes == 0) || (num_nodes <= trace->data_list_elts_left))
148  return 0;
149 
150  num_nodes -= trace->data_list_elts_left;
151 
152  start_elt = trace->elts;
153  end_elt =
154  trace->elts +
155  (u32) ((size_of_traceopt_per_node / sizeof (u32)) * (num_nodes - 1));
156 
157  if (oneway && (trace->ioam_trace_type & BIT_TTL_NODEID))
158  {
159  done = 0;
160  do
161  {
162  uturn_elt = start_elt - size_of_traceopt_per_node / sizeof (u32);
163 
164  if ((clib_net_to_host_u32 (*start_elt) >> 24) <=
165  (clib_net_to_host_u32 (*uturn_elt) >> 24))
166  done = 1;
167  }
168  while (!done && (start_elt = uturn_elt) != end_elt);
169  }
170  if (trace->ioam_trace_type & BIT_TTL_NODEID)
171  {
172  start_elt++;
173  end_elt++;
174  }
175  if (trace->ioam_trace_type & BIT_ING_INTERFACE)
176  {
177  start_elt++;
178  end_elt++;
179  }
180  start_time = clib_net_to_host_u32 (*start_elt);
181  end_time = clib_net_to_host_u32 (*end_elt);
182 
183  return (f64) (end_time - start_time);
184 }
185 
186 always_inline void
188 {
190  ioam_analyse_trace_record *trace_record;
191  ioam_path_map_t *path;
192  u8 k, i;
193 
194  while (__sync_lock_test_and_set (data->writer_lock, 1))
195  ;
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  }
211  *(data->writer_lock) = 0;
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 
228  while (__sync_lock_test_and_set (data->writer_lock, 1))
229  ;
230 
231  trace_data = &data->trace_data;
232 
233  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
234  if (0 == size_of_traceopt_per_node)
235  goto end;
236 
237  size_of_all_traceopts = trace_len;
238 
239  ptr = (u8 *) trace->elts;
240  max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
241  num_nodes = max_nodes - trace->data_list_elts_left;
242 
243  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
244  {
245  trace_record = trace_data->path_data + i;
246  path = trace_record->path;
247 
248  if (trace_record->is_free)
249  continue;
250 
251  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
252  {
253  ptr =
254  (u8 *) ((u8 *) trace->elts +
255  (size_of_traceopt_per_node * (j - 1)));
256 
257  nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
258  ptr += 4;
259 
260  if (nodeid != path[k].node_id)
261  goto end;
262 
263  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
264  (trace->ioam_trace_type == TRACE_TYPE_IF))
265  {
266  ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
267  ptr += 2;
268  egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
269  if ((ingress_if != path[k].ingress_if) ||
270  (egress_if != path[k].egress_if))
271  {
272  goto end;
273  }
274  }
275  /* Found Match - set path hop state to up */
276  path[k].state_up = 1;
277  }
278  }
279 end:
280  *(data->writer_lock) = 0;
281 }
282 
283 always_inline int
285  ioam_trace_hdr_t * trace, u16 pak_len,
286  u16 trace_len)
287 {
289  u16 size_of_traceopt_per_node;
290  u16 size_of_all_traceopts;
291  u8 i, j, k, num_nodes, max_nodes;
292  u8 *ptr;
293  u32 nodeid;
294  u16 ingress_if, egress_if;
295  ioam_path_map_t *path = NULL;
296  ioam_analyse_trace_record *trace_record;
297 
298  while (__sync_lock_test_and_set (data->writer_lock, 1))
299  ;
300 
301  trace_data = &data->trace_data;
302 
303  size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
304  // Unknown trace type
305  if (size_of_traceopt_per_node == 0)
306  goto DONE;
307  size_of_all_traceopts = trace_len;
308 
309  ptr = (u8 *) trace->elts;
310  max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
311  num_nodes = max_nodes - trace->data_list_elts_left;
312 
313  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
314  {
315  trace_record = trace_data->path_data + i;
316 
317  if (trace_record->is_free ||
318  (num_nodes != trace_record->num_nodes) ||
319  (trace->ioam_trace_type != trace_record->trace_type))
320  continue;
321 
322  path = trace_record->path;
323 
324  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
325  {
326  ptr =
327  (u8 *) ((u8 *) trace->elts +
328  (size_of_traceopt_per_node * (j - 1)));
329 
330  nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
331  ptr += 4;
332 
333  if (nodeid != path[k].node_id)
334  break;
335 
336  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
337  (trace->ioam_trace_type == TRACE_TYPE_IF))
338  {
339  ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
340  ptr += 2;
341  egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
342  if ((ingress_if != path[k].ingress_if) ||
343  (egress_if != path[k].egress_if))
344  {
345  break;
346  }
347  }
348  }
349 
350  if (k == num_nodes)
351  {
352  goto found_match;
353  }
354  }
355 
356  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
357  {
358  trace_record = trace_data->path_data + i;
359  if (trace_record->is_free)
360  {
361  trace_record->is_free = 0;
362  trace_record->num_nodes = num_nodes;
363  trace_record->trace_type = trace->ioam_trace_type;
364  path = trace_data->path_data[i].path;
365  trace_record->pkt_counter = 0;
366  trace_record->bytes_counter = 0;
367  trace_record->min_delay = 0xFFFFFFFF;
368  trace_record->max_delay = 0;
369  trace_record->mean_delay = 0;
370  break;
371  }
372  }
373 
374  for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
375  {
376  ptr =
377  (u8 *) ((u8 *) trace->elts + (size_of_traceopt_per_node * (j - 1)));
378 
379  path[k].node_id = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
380  ptr += 4;
381 
382  if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
383  (trace->ioam_trace_type == TRACE_TYPE_IF))
384  {
385  path[k].ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
386  ptr += 2;
387  path[k].egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
388  }
389  }
390 
391 found_match:
392  /* Set path state to UP */
393  for (k = 0; k < num_nodes; k++)
394  path[k].state_up = 1;
395 
396  trace_record->pkt_counter++;
397  trace_record->bytes_counter += pak_len;
398  if (trace->ioam_trace_type & BIT_TIMESTAMP)
399  {
400  /* Calculate time delay */
401  u32 delay = (u32) ip6_ioam_analyse_calc_delay (trace, trace_len, 0);
402  if (delay < trace_record->min_delay)
403  trace_record->min_delay = delay;
404  else if (delay > trace_record->max_delay)
405  trace_record->max_delay = delay;
406 
407  u64 sum = (trace_record->mean_delay * data->seqno_data.rx_packets);
408  trace_record->mean_delay =
409  (u32) ((sum + delay) / (data->seqno_data.rx_packets + 1));
410  }
411 DONE:
412  *(data->writer_lock) = 0;
413  return 0;
414 }
415 
416 always_inline int
418  ioam_e2e_packet_t * e2e, u16 len)
419 {
420  while (__sync_lock_test_and_set (data->writer_lock, 1))
421  ;
422 
424  (u64) clib_net_to_host_u32 (e2e->e2e_data));
425 
426  *(data->writer_lock) = 0;
427  return 0;
428 }
429 
431 format_path_map (u8 * s, va_list * args)
432 {
433  ioam_path_map_t *pm = va_arg (*args, ioam_path_map_t *);
434  u32 num_of_elts = va_arg (*args, u32);
435  u32 i;
436 
437  for (i = 0; i < num_of_elts; i++)
438  {
439  s =
440  format (s,
441  "node_id: 0x%x, ingress_if: 0x%x, egress_if:0x%x, state:%s\n",
442  pm->node_id, pm->ingress_if, pm->egress_if,
443  pm->state_up ? "UP" : "DOWN");
444  pm++;
445  }
446 
447  return (s);
448 }
449 
452 {
453  int j;
454  ioam_analyse_trace_record *trace_record;
455 
456  s = format (s, "pkt_sent : %u\n", record->pkt_sent);
457  s = format (s, "pkt_counter : %u\n", record->pkt_counter);
458  s = format (s, "bytes_counter : %u\n", record->bytes_counter);
459 
460  s = format (s, "Trace data: \n");
461 
462  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
463  {
464  trace_record = record->trace_data.path_data + j;
465  if (trace_record->is_free)
466  continue;
467 
468  s = format (s, "path_map:\n%U", format_path_map,
469  trace_record->path, trace_record->num_nodes);
470  s = format (s, "pkt_counter: %u\n", trace_record->pkt_counter);
471  s = format (s, "bytes_counter: %u\n", trace_record->bytes_counter);
472 
473  s = format (s, "min_delay: %u\n", trace_record->min_delay);
474  s = format (s, "max_delay: %u\n", trace_record->max_delay);
475  s = format (s, "mean_delay: %u\n", trace_record->mean_delay);
476  }
477 
478  s = format (s, "\nPOT data: \n");
479  s = format (s, "sfc_validated_count : %u\n",
480  record->pot_data.sfc_validated_count);
481  s = format (s, "sfc_invalidated_count : %u\n",
483 
484  s = format (s, "\nSeqno Data:\n");
485  s = format (s,
486  "RX Packets : %lu\n"
487  "Lost Packets : %lu\n"
488  "Duplicate Packets : %lu\n"
489  "Reordered Packets : %lu\n",
490  record->seqno_data.rx_packets,
491  record->seqno_data.lost_packets,
492  record->seqno_data.dup_packets,
493  record->seqno_data.reordered_packets);
494 
495  s = format (s, "\n");
496  return s;
497 }
498 
499 always_inline void
501 {
502  u16 j;
504 
505  data->is_free = 1;
506 
507  /* We maintain data corresponding to last IP-Fix export, this may
508  * get extended in future to maintain history of data */
510 
513  *(data->writer_lock) = 0;
514 
515  trace_data = &(data->trace_data);
516  for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
517  trace_data->path_data[j].is_free = 1;
518 }
519 
520 #endif /* PLUGINS_IOAM_PLUGIN_IOAM_ANALYSE_IOAM_ANALYSE_H_ */
521 
522 /*
523  * fd.io coding-style-patch-verification: ON
524  *
525  * Local Variables:
526  * eval: (c-set-style "gnu")
527  * End:
528  */
u32 bytes_counter
Num of bytes in the flow going over path.
Definition: ioam_analyse.h:61
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:862
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:67
static int ip6_ioam_analyse_hbh_e2e(ioam_analyser_data_t *data, ioam_e2e_packet_t *e2e, u16 len)
Definition: ioam_analyse.h:417
static u8 * print_analyse_flow(u8 *s, ioam_analyser_data_t *record)
Definition: ioam_analyse.h:451
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:120
unsigned long u64
Definition: types.h:89
u32 bytes_counter
Num of bytes matching this flow.
Definition: ioam_analyse.h:111
static void ioam_analyse_init_data(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:500
#define NULL
Definition: clib.h:55
ioam_analyse_pot_data pot_data
Analysed iOAM pot data.
Definition: ioam_analyse.h:117
volatile u32 * writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:126
#define IOAM_TRACE_MAX_NODES
Definition: ioam_analyse.h:27
u32 pkt_sent
Num of pkts sent for this flow.
Definition: ioam_analyse.h:105
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:130
CLIB_CACHE_LINE_ALIGN_MARK(cacheline0)
int i
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:448
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:41
static void ip6_ioam_analyse_set_paths_down(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:187
u32 pkt_counter
Num of pkts in the flow going over path.
Definition: ioam_analyse.h:58
#define always_inline
Definition: clib.h:92
u32 pkt_counter
Num of pkts matching this flow.
Definition: ioam_analyse.h:108
unsigned int u32
Definition: types.h:88
static u8 * format_path_map(u8 *s, va_list *args)
Definition: ioam_analyse.h:431
#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:114
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: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:123
#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
Analysed iOAM pot data.
Definition: ioam_analyse.h:83
u8 trace_type
Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp.
Definition: ioam_analyse.h:47
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:284
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:120
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:215
u32 mean_delay
Average Dealay for the flow.
Definition: ioam_analyse.h:70
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW]
Definition: ioam_analyse.h:77
#define BIT_TIMESTAMP
Definition: trace_util.h:92