LCOV - code coverage report
Current view: top level - plugins/ioam/analyse - ioam_analyse.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 8 198 4.0 %
Date: 2023-07-05 22:20:52 Functions: 1 8 12.5 %

          Line data    Source code
       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             : #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             : {
      33             :   u16 ingress_if;
      34             :   u16 egress_if;
      35             :   u32 node_id;
      36             :   u32 state_up;
      37             : } ioam_path_map_t;
      38             : 
      39             : /** @brief Analysed iOAM trace data.
      40             :     @note cache aligned.
      41             : */
      42             : typedef struct
      43             : {
      44             :   /** No of nodes in path. */
      45             :   u8 num_nodes;
      46             : 
      47             :   /** Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp. */
      48             :   u8 trace_type;
      49             : 
      50             :   /** Flag to indicate whether node is allocated. */
      51             :   u8 is_free;
      52             : 
      53             :   u8 pad[5];
      54             : 
      55             :   /** Actual PATH flow has taken. */
      56             :   ioam_path_map_t path[IOAM_TRACE_MAX_NODES];
      57             : 
      58             :   /** Num of pkts in the flow going over path. */
      59             :   u32 pkt_counter;
      60             : 
      61             :   /** Num of bytes in the flow going over path. */
      62             :   u32 bytes_counter;
      63             : 
      64             :   /** Minumum Dealay for the flow. */
      65             :   u32 min_delay;
      66             : 
      67             :   /** Maximum Dealay for the flow. */
      68             :   u32 max_delay;
      69             : 
      70             :   /** Average Dealay for the flow. */
      71             :   u32 mean_delay;
      72             : 
      73             :   u32 reserve;
      74             : } ioam_analyse_trace_record;
      75             : 
      76             : typedef struct
      77             : {
      78             :   ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW];
      79             : } ioam_analyse_trace_data;
      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. */
      88             :   u32 sfc_validated_count;
      89             : 
      90             :   /** Number of packets invalidated (failed through the service chain)
      91             :       within the timestamps. */
      92             :   u32 sfc_invalidated_count;
      93             : } ioam_analyse_pot_data;
      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             : 
     102             :   u8 is_free;
     103             :   u8 pad[3];
     104             : 
     105             :   /** Num of pkts sent for this flow. */
     106             :   u32 pkt_sent;
     107             : 
     108             :   /** Num of pkts matching this flow. */
     109             :   u32 pkt_counter;
     110             : 
     111             :   /** Num of bytes matching this flow. */
     112             :   u32 bytes_counter;
     113             : 
     114             :   /** Analysed iOAM trace data. */
     115             :   ioam_analyse_trace_data trace_data;
     116             : 
     117             :   /** Analysed iOAM pot data. */
     118             :   ioam_analyse_pot_data pot_data;
     119             : 
     120             :   /** Analysed iOAM seqno data. */
     121             :   seqno_rx_info seqno_data;
     122             : 
     123             :   /** Cache of previously analysed data, useful for export. */
     124             :   struct ioam_analyser_data_t_ *chached_data_list;
     125             : 
     126             :   /** Lock to since we use this to export the data in other thread. */
     127             :   clib_spinlock_t writer_lock;
     128             : } ioam_analyser_data_t;
     129             : 
     130             : always_inline f64
     131           0 : 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           0 :   u8 done = 0;
     140             : 
     141           0 :   size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
     142             :   // Unknown trace type
     143           0 :   if (size_of_traceopt_per_node == 0)
     144           0 :     return 0;
     145           0 :   size_of_all_traceopts = trace_len;    /*ioam_trace_type,data_list_elts_left */
     146             : 
     147           0 :   num_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
     148           0 :   if ((num_nodes == 0) || (num_nodes <= trace->data_list_elts_left))
     149           0 :     return 0;
     150             : 
     151           0 :   num_nodes -= trace->data_list_elts_left;
     152             : 
     153           0 :   start_elt = trace->elts;
     154           0 :   end_elt =
     155           0 :     trace->elts +
     156           0 :     (u32) ((size_of_traceopt_per_node / sizeof (u32)) * (num_nodes - 1));
     157             : 
     158           0 :   if (oneway && (trace->ioam_trace_type & BIT_TTL_NODEID))
     159             :     {
     160           0 :       done = 0;
     161             :       do
     162             :         {
     163           0 :           uturn_elt = start_elt - size_of_traceopt_per_node / sizeof (u32);
     164             : 
     165           0 :           if ((clib_net_to_host_u32 (*start_elt) >> 24) <=
     166           0 :               (clib_net_to_host_u32 (*uturn_elt) >> 24))
     167           0 :             done = 1;
     168             :         }
     169           0 :       while (!done && (start_elt = uturn_elt) != end_elt);
     170             :     }
     171           0 :   if (trace->ioam_trace_type & BIT_TTL_NODEID)
     172             :     {
     173           0 :       start_elt++;
     174           0 :       end_elt++;
     175             :     }
     176           0 :   if (trace->ioam_trace_type & BIT_ING_INTERFACE)
     177             :     {
     178           0 :       start_elt++;
     179           0 :       end_elt++;
     180             :     }
     181           0 :   start_time = clib_net_to_host_u32 (*start_elt);
     182           0 :   end_time = clib_net_to_host_u32 (*end_elt);
     183             : 
     184           0 :   return (f64) (end_time - start_time);
     185             : }
     186             : 
     187             : always_inline void
     188           0 : ip6_ioam_analyse_set_paths_down (ioam_analyser_data_t * data)
     189             : {
     190             :   ioam_analyse_trace_data *trace_data;
     191             :   ioam_analyse_trace_record *trace_record;
     192             :   ioam_path_map_t *path;
     193             :   u8 k, i;
     194             : 
     195           0 :   clib_spinlock_lock (&data->writer_lock);
     196             : 
     197           0 :   trace_data = &data->trace_data;
     198             : 
     199           0 :   for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
     200             :     {
     201           0 :       trace_record = trace_data->path_data + i;
     202             : 
     203           0 :       if (trace_record->is_free)
     204           0 :         continue;
     205             : 
     206           0 :       path = trace_record->path;
     207             : 
     208           0 :       for (k = 0; k < trace_record->num_nodes; k++)
     209           0 :         path[k].state_up = 0;
     210             :     }
     211           0 :   clib_spinlock_unlock (&data->writer_lock);
     212           0 : }
     213             : 
     214             : always_inline void
     215           0 : 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           0 :   clib_spinlock_lock (&data->writer_lock);
     229             : 
     230           0 :   trace_data = &data->trace_data;
     231             : 
     232           0 :   size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
     233           0 :   if (0 == size_of_traceopt_per_node)
     234           0 :     goto end;
     235             : 
     236           0 :   size_of_all_traceopts = trace_len;
     237             : 
     238           0 :   ptr = (u8 *) trace->elts;
     239           0 :   max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
     240           0 :   num_nodes = max_nodes - trace->data_list_elts_left;
     241             : 
     242           0 :   for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
     243             :     {
     244           0 :       trace_record = trace_data->path_data + i;
     245           0 :       path = trace_record->path;
     246             : 
     247           0 :       if (trace_record->is_free)
     248           0 :         continue;
     249             : 
     250           0 :       for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
     251             :         {
     252           0 :           ptr =
     253           0 :             (u8 *) ((u8 *) trace->elts +
     254           0 :                     (size_of_traceopt_per_node * (j - 1)));
     255             : 
     256           0 :           nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
     257           0 :           ptr += 4;
     258             : 
     259           0 :           if (nodeid != path[k].node_id)
     260           0 :             goto end;
     261             : 
     262           0 :           if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
     263           0 :               (trace->ioam_trace_type == TRACE_TYPE_IF))
     264             :             {
     265           0 :               ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
     266           0 :               ptr += 2;
     267           0 :               egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
     268           0 :               if ((ingress_if != path[k].ingress_if) ||
     269           0 :                   (egress_if != path[k].egress_if))
     270             :                 {
     271           0 :                   goto end;
     272             :                 }
     273             :             }
     274             :           /* Found Match - set path hop state to up */
     275           0 :           path[k].state_up = 1;
     276             :         }
     277             :     }
     278           0 : end:
     279           0 :   clib_spinlock_unlock (&data->writer_lock);
     280           0 : }
     281             : 
     282             : always_inline int
     283           0 : ip6_ioam_analyse_hbh_trace (ioam_analyser_data_t * data,
     284             :                             ioam_trace_hdr_t * trace, u16 pak_len,
     285             :                             u16 trace_len)
     286             : {
     287             :   ioam_analyse_trace_data *trace_data;
     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           0 :   ioam_path_map_t *path = NULL;
     295             :   ioam_analyse_trace_record *trace_record;
     296             : 
     297           0 :   clib_spinlock_lock (&data->writer_lock);
     298             : 
     299           0 :   trace_data = &data->trace_data;
     300             : 
     301           0 :   size_of_traceopt_per_node = fetch_trace_data_size (trace->ioam_trace_type);
     302             :   // Unknown trace type
     303           0 :   if (size_of_traceopt_per_node == 0)
     304           0 :     goto DONE;
     305           0 :   size_of_all_traceopts = trace_len;
     306             : 
     307           0 :   ptr = (u8 *) trace->elts;
     308           0 :   max_nodes = (u8) (size_of_all_traceopts / size_of_traceopt_per_node);
     309           0 :   num_nodes = max_nodes - trace->data_list_elts_left;
     310             : 
     311           0 :   for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
     312             :     {
     313           0 :       trace_record = trace_data->path_data + i;
     314             : 
     315           0 :       if (trace_record->is_free ||
     316           0 :           (num_nodes != trace_record->num_nodes) ||
     317           0 :           (trace->ioam_trace_type != trace_record->trace_type))
     318           0 :         continue;
     319             : 
     320           0 :       path = trace_record->path;
     321             : 
     322           0 :       for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
     323             :         {
     324           0 :           ptr =
     325           0 :             (u8 *) ((u8 *) trace->elts +
     326           0 :                     (size_of_traceopt_per_node * (j - 1)));
     327             : 
     328           0 :           nodeid = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
     329           0 :           ptr += 4;
     330             : 
     331           0 :           if (nodeid != path[k].node_id)
     332           0 :             break;
     333             : 
     334           0 :           if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
     335           0 :               (trace->ioam_trace_type == TRACE_TYPE_IF))
     336             :             {
     337           0 :               ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
     338           0 :               ptr += 2;
     339           0 :               egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
     340           0 :               if ((ingress_if != path[k].ingress_if) ||
     341           0 :                   (egress_if != path[k].egress_if))
     342             :                 {
     343             :                   break;
     344             :                 }
     345             :             }
     346             :         }
     347             : 
     348           0 :       if (k == num_nodes)
     349             :         {
     350           0 :           goto found_match;
     351             :         }
     352             :     }
     353             : 
     354           0 :   for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
     355             :     {
     356           0 :       trace_record = trace_data->path_data + i;
     357           0 :       if (trace_record->is_free)
     358             :         {
     359           0 :           trace_record->is_free = 0;
     360           0 :           trace_record->num_nodes = num_nodes;
     361           0 :           trace_record->trace_type = trace->ioam_trace_type;
     362           0 :           path = trace_data->path_data[i].path;
     363           0 :           trace_record->pkt_counter = 0;
     364           0 :           trace_record->bytes_counter = 0;
     365           0 :           trace_record->min_delay = 0xFFFFFFFF;
     366           0 :           trace_record->max_delay = 0;
     367           0 :           trace_record->mean_delay = 0;
     368           0 :           break;
     369             :         }
     370             :     }
     371             : 
     372           0 :   for (j = max_nodes, k = 0; k < num_nodes; j--, k++)
     373             :     {
     374           0 :       ptr =
     375           0 :         (u8 *) ((u8 *) trace->elts + (size_of_traceopt_per_node * (j - 1)));
     376             : 
     377           0 :       path[k].node_id = clib_net_to_host_u32 (*((u32 *) ptr)) & 0x00ffffff;
     378           0 :       ptr += 4;
     379             : 
     380           0 :       if ((trace->ioam_trace_type == TRACE_TYPE_IF_TS_APP) ||
     381           0 :           (trace->ioam_trace_type == TRACE_TYPE_IF))
     382             :         {
     383           0 :           path[k].ingress_if = clib_net_to_host_u16 (*((u16 *) ptr));
     384           0 :           ptr += 2;
     385           0 :           path[k].egress_if = clib_net_to_host_u16 (*((u16 *) ptr));
     386             :         }
     387             :     }
     388             : 
     389           0 : found_match:
     390             :   /* Set path state to UP */
     391           0 :   for (k = 0; k < num_nodes; k++)
     392           0 :     path[k].state_up = 1;
     393             : 
     394           0 :   trace_record->pkt_counter++;
     395           0 :   trace_record->bytes_counter += pak_len;
     396           0 :   if (trace->ioam_trace_type & BIT_TIMESTAMP)
     397             :     {
     398             :       /* Calculate time delay */
     399           0 :       u32 delay = (u32) ip6_ioam_analyse_calc_delay (trace, trace_len, 0);
     400           0 :       if (delay < trace_record->min_delay)
     401           0 :         trace_record->min_delay = delay;
     402           0 :       else if (delay > trace_record->max_delay)
     403           0 :         trace_record->max_delay = delay;
     404             : 
     405           0 :       u64 sum = (trace_record->mean_delay * data->seqno_data.rx_packets);
     406           0 :       trace_record->mean_delay =
     407           0 :         (u32) ((sum + delay) / (data->seqno_data.rx_packets + 1));
     408             :     }
     409           0 : DONE:
     410           0 :   clib_spinlock_unlock (&data->writer_lock);
     411           0 :   return 0;
     412             : }
     413             : 
     414             : always_inline int
     415           0 : ip6_ioam_analyse_hbh_e2e (ioam_analyser_data_t * data,
     416             :                           ioam_e2e_packet_t * e2e, u16 len)
     417             : {
     418           0 :   clib_spinlock_lock (&data->writer_lock);
     419             : 
     420           0 :   ioam_analyze_seqno (&data->seqno_data,
     421           0 :                       (u64) clib_net_to_host_u32 (e2e->e2e_data));
     422             : 
     423           0 :   clib_spinlock_unlock (&data->writer_lock);
     424             : 
     425           0 :   return 0;
     426             : }
     427             : 
     428             : always_inline u8 *
     429           0 : format_path_map (u8 * s, va_list * args)
     430             : {
     431           0 :   ioam_path_map_t *pm = va_arg (*args, ioam_path_map_t *);
     432           0 :   u32 num_of_elts = va_arg (*args, u32);
     433             :   u32 i;
     434             : 
     435           0 :   for (i = 0; i < num_of_elts; i++)
     436             :     {
     437             :       s =
     438           0 :         format (s,
     439             :                 "node_id: 0x%x, ingress_if: 0x%x, egress_if:0x%x, state:%s\n",
     440           0 :                 pm->node_id, pm->ingress_if, pm->egress_if,
     441           0 :                 pm->state_up ? "UP" : "DOWN");
     442           0 :       pm++;
     443             :     }
     444             : 
     445           0 :   return (s);
     446             : }
     447             : 
     448             : always_inline u8 *
     449           0 : print_analyse_flow (u8 * s, ioam_analyser_data_t * record)
     450             : {
     451             :   int j;
     452             :   ioam_analyse_trace_record *trace_record;
     453             : 
     454           0 :   s = format (s, "pkt_sent : %u\n", record->pkt_sent);
     455           0 :   s = format (s, "pkt_counter : %u\n", record->pkt_counter);
     456           0 :   s = format (s, "bytes_counter : %u\n", record->bytes_counter);
     457             : 
     458           0 :   s = format (s, "Trace data: \n");
     459             : 
     460           0 :   for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
     461             :     {
     462           0 :       trace_record = record->trace_data.path_data + j;
     463           0 :       if (trace_record->is_free)
     464           0 :         continue;
     465             : 
     466           0 :       s = format (s, "path_map:\n%U", format_path_map,
     467           0 :                   trace_record->path, trace_record->num_nodes);
     468           0 :       s = format (s, "pkt_counter: %u\n", trace_record->pkt_counter);
     469           0 :       s = format (s, "bytes_counter: %u\n", trace_record->bytes_counter);
     470             : 
     471           0 :       s = format (s, "min_delay: %u\n", trace_record->min_delay);
     472           0 :       s = format (s, "max_delay: %u\n", trace_record->max_delay);
     473           0 :       s = format (s, "mean_delay: %u\n", trace_record->mean_delay);
     474             :     }
     475             : 
     476           0 :   s = format (s, "\nPOT data: \n");
     477           0 :   s = format (s, "sfc_validated_count : %u\n",
     478             :               record->pot_data.sfc_validated_count);
     479           0 :   s = format (s, "sfc_invalidated_count : %u\n",
     480             :               record->pot_data.sfc_invalidated_count);
     481             : 
     482           0 :   s = format (s, "\nSeqno Data:\n");
     483           0 :   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           0 :   s = format (s, "\n");
     494           0 :   return s;
     495             : }
     496             : 
     497             : always_inline void
     498       28509 : ioam_analyse_init_data (ioam_analyser_data_t * data)
     499             : {
     500             :   u16 j;
     501             :   ioam_analyse_trace_data *trace_data;
     502             : 
     503       28509 :   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 */
     507       28509 :   vec_validate_aligned (data->chached_data_list, 0, CLIB_CACHE_LINE_BYTES);
     508             : 
     509       28509 :   clib_spinlock_init (&data->writer_lock);
     510             : 
     511       28509 :   trace_data = &(data->trace_data);
     512      313599 :   for (j = 0; j < IOAM_MAX_PATHS_PER_FLOW; j++)
     513      285090 :     trace_data->path_data[j].is_free = 1;
     514       28509 : }
     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             :  */

Generated by: LCOV version 1.14