Harmonize vec/pool_get_aligned object sizes and alignment requests
[vpp.git] / src / plugins / ioam / analyse / ioam_analyse.h
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>
23 #include <ioam/lib-trace/trace_util.h>
24 #include <ioam/lib-trace/trace_config.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 {
32   u16 ingress_if;
33   u16 egress_if;
34   u32 node_id;
35   u32 state_up;
36 } ioam_path_map_t;
37
38 /** @brief Analysed iOAM trace data.
39     @note cache aligned.
40 */
41 typedef struct
42 {
43   /** No of nodes in path. */
44   u8 num_nodes;
45
46   /** Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp. */
47   u8 trace_type;
48
49   /** Flag to indicate whether node is allocated. */
50   u8 is_free;
51
52   u8 pad[5];
53
54   /** Actual PATH flow has taken. */
55   ioam_path_map_t path[IOAM_TRACE_MAX_NODES];
56
57   /** Num of pkts in the flow going over path. */
58   u32 pkt_counter;
59
60   /** Num of bytes in the flow going over path. */
61   u32 bytes_counter;
62
63   /** Minumum Dealay for the flow. */
64   u32 min_delay;
65
66   /** Maximum Dealay for the flow. */
67   u32 max_delay;
68
69   /** Average Dealay for the flow. */
70   u32 mean_delay;
71
72   u32 reserve;
73 } ioam_analyse_trace_record;
74
75 typedef struct
76 {
77   ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW];
78 } ioam_analyse_trace_data;
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. */
87   u32 sfc_validated_count;
88
89   /** Number of packets invalidated (failed through the service chain)
90       within the timestamps. */
91   u32 sfc_invalidated_count;
92 } ioam_analyse_pot_data;
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
101   u8 is_free;
102   u8 pad[3];
103
104   /** Num of pkts sent for this flow. */
105   u32 pkt_sent;
106
107   /** Num of pkts matching this flow. */
108   u32 pkt_counter;
109
110   /** Num of bytes matching this flow. */
111   u32 bytes_counter;
112
113   /** Analysed iOAM trace data. */
114   ioam_analyse_trace_data trace_data;
115
116   /** Analysed iOAM pot data. */
117   ioam_analyse_pot_data pot_data;
118
119   /** Analysed iOAM seqno data. */
120   seqno_rx_info seqno_data;
121
122   /** Cache of previously analysed data, useful for export. */
123   struct ioam_analyser_data_t_ *chached_data_list;
124
125   /** Lock to since we use this to export the data in other thread. */
126   volatile u32 *writer_lock;
127 } ioam_analyser_data_t;
128
129 always_inline f64
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
187 ip6_ioam_analyse_set_paths_down (ioam_analyser_data_t * data)
188 {
189   ioam_analyse_trace_data *trace_data;
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
215 ip6_ioam_analyse_hbh_trace_loopback (ioam_analyser_data_t * data,
216                                      ioam_trace_hdr_t * trace, u16 trace_len)
217 {
218   ioam_analyse_trace_data *trace_data;
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
284 ip6_ioam_analyse_hbh_trace (ioam_analyser_data_t * data,
285                             ioam_trace_hdr_t * trace, u16 pak_len,
286                             u16 trace_len)
287 {
288   ioam_analyse_trace_data *trace_data;
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
417 ip6_ioam_analyse_hbh_e2e (ioam_analyser_data_t * data,
418                           ioam_e2e_packet_t * e2e, u16 len)
419 {
420   while (__sync_lock_test_and_set (data->writer_lock, 1))
421     ;
422
423   ioam_analyze_seqno (&data->seqno_data,
424                       (u64) clib_net_to_host_u32 (e2e->e2e_data));
425
426   *(data->writer_lock) = 0;
427   return 0;
428 }
429
430 always_inline u8 *
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
450 always_inline u8 *
451 print_analyse_flow (u8 * s, ioam_analyser_data_t * record)
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",
482               record->pot_data.sfc_invalidated_count);
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
500 ioam_analyse_init_data (ioam_analyser_data_t * data)
501 {
502   u16 j;
503   ioam_analyse_trace_data *trace_data;
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 */
509   vec_validate_aligned (data->chached_data_list, 0, CLIB_CACHE_LINE_BYTES);
510
511   data->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
512                                               CLIB_CACHE_LINE_BYTES);
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  */