LCOV - code coverage report
Current view: top level - plugins/nsh/nsh-md2-ioam - nsh_md2_ioam_trace.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 13 170 7.6 %
Date: 2023-10-26 01:39:38 Functions: 5 17 29.4 %

          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             : #include <vlib/vlib.h>
      16             : #include <vnet/vnet.h>
      17             : #include <vppinfra/error.h>
      18             : 
      19             : #include <vppinfra/hash.h>
      20             : #include <vppinfra/error.h>
      21             : #include <vppinfra/elog.h>
      22             : 
      23             : #include <ioam/lib-trace/trace_util.h>
      24             : #include <nsh/nsh-md2-ioam/nsh_md2_ioam.h>
      25             : #include <nsh/nsh_packet.h>
      26             : 
      27             : /* Timestamp precision multipliers for seconds, milliseconds, microseconds
      28             :  * and nanoseconds respectively.
      29             :  */
      30             : static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 };
      31             : 
      32             : #define NSH_MD2_IOAM_TRACE_SIZE_DUMMY 20
      33             : 
      34             : typedef union
      35             : {
      36             :   u64 as_u64;
      37             :   u32 as_u32[2];
      38             : } time_u64_t;
      39             : 
      40             : 
      41             : /* *INDENT-OFF* */
      42             : typedef CLIB_PACKED(struct {
      43             :   u16 class;
      44             :   u8 type;
      45             :   u8 length;
      46             :   u8 data_list_elts_left;
      47             :   u16 ioam_trace_type;
      48             :   u8 reserve;
      49             :   u32 elts[0]; /* Variable type. So keep it generic */
      50             : }) nsh_md2_ioam_trace_option_t;
      51             : /* *INDENT-ON* */
      52             : 
      53             : 
      54             : #define foreach_nsh_md2_ioam_trace_stats                                \
      55             :   _(SUCCESS, "Pkts updated with TRACE records")                                       \
      56             :   _(FAILED, "Errors in TRACE due to lack of TRACE records")
      57             : 
      58             : static char *nsh_md2_ioam_trace_stats_strings[] = {
      59             : #define _(sym,string) string,
      60             :   foreach_nsh_md2_ioam_trace_stats
      61             : #undef _
      62             : };
      63             : 
      64             : typedef enum
      65             : {
      66             : #define _(sym,str) NSH_MD2_IOAM_TRACE_##sym,
      67             :   foreach_nsh_md2_ioam_trace_stats
      68             : #undef _
      69             :     NSH_MD2_IOAM_TRACE_N_STATS,
      70             : } nsh_md2_ioam_trace_stats_t;
      71             : 
      72             : 
      73             : typedef struct
      74             : {
      75             :   /* stats */
      76             :   u64 counters[ARRAY_LEN (nsh_md2_ioam_trace_stats_strings)];
      77             : 
      78             :   /* convenience */
      79             :   vlib_main_t *vlib_main;
      80             :   vnet_main_t *vnet_main;
      81             : } nsh_md2_ioam_trace_main_t;
      82             : 
      83             : nsh_md2_ioam_trace_main_t nsh_md2_ioam_trace_main;
      84             : 
      85             : /*
      86             :  * Find a trace profile
      87             :  */
      88             : 
      89             : extern u8 *nsh_trace_main;
      90             : always_inline trace_profile *
      91           0 : nsh_trace_profile_find (void)
      92             : {
      93           0 :   trace_main_t *sm = (trace_main_t *) nsh_trace_main;
      94             : 
      95           0 :   return (&(sm->profile));
      96             : }
      97             : 
      98             : 
      99             : always_inline void
     100           0 : nsh_md2_ioam_trace_stats_increment_counter (u32 counter_index, u64 increment)
     101             : {
     102           0 :   nsh_md2_ioam_trace_main_t *hm = &nsh_md2_ioam_trace_main;
     103             : 
     104           0 :   hm->counters[counter_index] += increment;
     105           0 : }
     106             : 
     107             : 
     108             : static u8 *
     109           0 : format_ioam_data_list_element (u8 * s, va_list * args)
     110             : {
     111           0 :   u32 *elt = va_arg (*args, u32 *);
     112           0 :   u8 *trace_type_p = va_arg (*args, u8 *);
     113           0 :   u8 trace_type = *trace_type_p;
     114             : 
     115             : 
     116           0 :   if (trace_type & BIT_TTL_NODEID)
     117             :     {
     118           0 :       u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt);
     119           0 :       s = format (s, "ttl 0x%x node id 0x%x ",
     120             :                   ttl_node_id_host_byte_order >> 24,
     121             :                   ttl_node_id_host_byte_order & 0x00FFFFFF);
     122             : 
     123           0 :       elt++;
     124             :     }
     125             : 
     126           0 :   if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE)
     127             :     {
     128           0 :       u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt);
     129           0 :       s = format (s, "ingress 0x%x egress 0x%x ",
     130             :                   ingress_host_byte_order >> 16,
     131             :                   ingress_host_byte_order & 0xFFFF);
     132           0 :       elt++;
     133             :     }
     134             : 
     135           0 :   if (trace_type & BIT_TIMESTAMP)
     136             :     {
     137           0 :       u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt);
     138           0 :       s = format (s, "ts 0x%x \n", ts_in_host_byte_order);
     139           0 :       elt++;
     140             :     }
     141             : 
     142           0 :   if (trace_type & BIT_APPDATA)
     143             :     {
     144           0 :       u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt);
     145           0 :       s = format (s, "app 0x%x ", appdata_in_host_byte_order);
     146           0 :       elt++;
     147             :     }
     148             : 
     149           0 :   return s;
     150             : }
     151             : 
     152             : 
     153             : 
     154             : int
     155           0 : nsh_md2_ioam_trace_rewrite_handler (u8 * rewrite_string, u8 * rewrite_size)
     156             : {
     157           0 :   nsh_md2_ioam_trace_option_t *trace_option = NULL;
     158           0 :   u8 trace_data_size = 0;
     159           0 :   u8 trace_option_elts = 0;
     160           0 :   trace_profile *profile = NULL;
     161             : 
     162           0 :   profile = nsh_trace_profile_find ();
     163             : 
     164           0 :   if (PREDICT_FALSE (!profile))
     165             :     {
     166           0 :       return (-1);
     167             :     }
     168             : 
     169           0 :   if (PREDICT_FALSE (!rewrite_string))
     170           0 :     return -1;
     171             : 
     172           0 :   trace_option_elts = profile->num_elts;
     173           0 :   trace_data_size = fetch_trace_data_size (profile->trace_type);
     174             : 
     175           0 :   trace_option = (nsh_md2_ioam_trace_option_t *) rewrite_string;
     176           0 :   trace_option->class = clib_host_to_net_u16 (0x9);
     177           0 :   trace_option->type = NSH_MD2_IOAM_OPTION_TYPE_TRACE;
     178           0 :   trace_option->length = (trace_option_elts * trace_data_size) + 4;
     179           0 :   trace_option->data_list_elts_left = trace_option_elts;
     180           0 :   trace_option->ioam_trace_type =
     181           0 :     clib_host_to_net_u16 (profile->trace_type & TRACE_TYPE_MASK);
     182             : 
     183           0 :   *rewrite_size =
     184           0 :     sizeof (nsh_md2_ioam_trace_option_t) +
     185           0 :     (trace_option_elts * trace_data_size);
     186             : 
     187           0 :   return 0;
     188             : }
     189             : 
     190             : 
     191             : int
     192           0 : nsh_md2_ioam_trace_data_list_handler (vlib_buffer_t * b,
     193             :                                       nsh_tlv_header_t * opt)
     194             : {
     195           0 :   u8 elt_index = 0;
     196           0 :   nsh_md2_ioam_trace_option_t *trace =
     197             :     (nsh_md2_ioam_trace_option_t *) ((u8 *) opt);
     198             :   time_u64_t time_u64;
     199             :   u32 *elt;
     200           0 :   int rv = 0;
     201           0 :   trace_profile *profile = NULL;
     202           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     203           0 :   nsh_main_t *gm = &nsh_main;
     204           0 :   u16 ioam_trace_type = 0;
     205             : 
     206           0 :   profile = nsh_trace_profile_find ();
     207             : 
     208           0 :   if (PREDICT_FALSE (!profile))
     209             :     {
     210           0 :       return (-1);
     211             :     }
     212             : 
     213             : 
     214           0 :   ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK;
     215           0 :   time_u64.as_u64 = 0;
     216             : 
     217           0 :   if (PREDICT_TRUE (trace->data_list_elts_left))
     218             :     {
     219           0 :       trace->data_list_elts_left--;
     220             :       /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes
     221             :        * to skip to this node's location.
     222             :        */
     223           0 :       elt_index =
     224           0 :         trace->data_list_elts_left *
     225           0 :         fetch_trace_data_size (ioam_trace_type) / 4;
     226           0 :       elt = &trace->elts[elt_index];
     227           0 :       if (ioam_trace_type & BIT_TTL_NODEID)
     228             :         {
     229           0 :           ip4_header_t *ip0 = vlib_buffer_get_current (b);
     230           0 :           *elt = clib_host_to_net_u32 (((ip0->ttl - 1) << 24) |
     231           0 :                                        profile->node_id);
     232           0 :           elt++;
     233             :         }
     234             : 
     235           0 :       if (ioam_trace_type & BIT_ING_INTERFACE)
     236             :         {
     237           0 :           u16 tx_if = vnet_buffer (b)->sw_if_index[VLIB_TX];
     238             : 
     239           0 :           *elt =
     240           0 :             (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 | tx_if;
     241           0 :           *elt = clib_host_to_net_u32 (*elt);
     242           0 :           elt++;
     243             :         }
     244             : 
     245             : 
     246           0 :       if (ioam_trace_type & BIT_TIMESTAMP)
     247             :         {
     248             :           /* Send least significant 32 bits */
     249           0 :           f64 time_f64 =
     250           0 :             (f64) (((f64) hm->unix_time_0) +
     251           0 :                    (vlib_time_now (gm->vlib_main) - hm->vlib_time_0));
     252             : 
     253           0 :           time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp];
     254           0 :           *elt = clib_host_to_net_u32 (time_u64.as_u32[0]);
     255           0 :           elt++;
     256             :         }
     257             : 
     258           0 :       if (ioam_trace_type & BIT_APPDATA)
     259             :         {
     260             :           /* $$$ set elt0->app_data */
     261           0 :           *elt = clib_host_to_net_u32 (profile->app_data);
     262           0 :           elt++;
     263             :         }
     264           0 :       nsh_md2_ioam_trace_stats_increment_counter
     265             :         (NSH_MD2_IOAM_TRACE_SUCCESS, 1);
     266             :     }
     267             :   else
     268             :     {
     269           0 :       nsh_md2_ioam_trace_stats_increment_counter
     270             :         (NSH_MD2_IOAM_TRACE_FAILED, 1);
     271             :     }
     272           0 :   return (rv);
     273             : }
     274             : 
     275             : 
     276             : 
     277             : u8 *
     278           0 : nsh_md2_ioam_trace_data_list_trace_handler (u8 * s, nsh_tlv_header_t * opt)
     279             : {
     280             :   nsh_md2_ioam_trace_option_t *trace;
     281           0 :   u8 trace_data_size_in_words = 0;
     282             :   u32 *elt;
     283           0 :   int elt_index = 0;
     284           0 :   u16 ioam_trace_type = 0;
     285             : 
     286           0 :   trace = (nsh_md2_ioam_trace_option_t *) ((u8 *) opt);
     287           0 :   ioam_trace_type = clib_net_to_host_u16 (trace->ioam_trace_type);
     288           0 :   trace_data_size_in_words = fetch_trace_data_size (ioam_trace_type) / 4;
     289           0 :   elt = &trace->elts[0];
     290             :   s =
     291           0 :     format (s, "  Trace Type 0x%x , %d elts left\n", ioam_trace_type,
     292           0 :             trace->data_list_elts_left);
     293           0 :   while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->length - 4
     294             :                        /* -2 accounts for ioam_trace_type,elts_left */ ))
     295             :     {
     296           0 :       s = format (s, "    [%d] %U\n", elt_index,
     297             :                   format_ioam_data_list_element, elt, &ioam_trace_type);
     298           0 :       elt_index++;
     299           0 :       elt += trace_data_size_in_words;
     300             :     }
     301           0 :   return (s);
     302             : }
     303             : 
     304             : int
     305           0 : nsh_md2_ioam_trace_swap_handler (vlib_buffer_t * b,
     306             :                                  nsh_tlv_header_t * old_opt,
     307             :                                  nsh_tlv_header_t * new_opt)
     308             : {
     309             : 
     310           0 :   clib_memcpy_fast (new_opt, old_opt,
     311           0 :                     new_opt->length + sizeof (nsh_tlv_header_t));
     312           0 :   return nsh_md2_ioam_trace_data_list_handler (b, new_opt);
     313             : }
     314             : 
     315             : static clib_error_t *
     316           0 : nsh_md2_ioam_show_ioam_trace_cmd_fn (vlib_main_t * vm,
     317             :                                      unformat_input_t * input,
     318             :                                      vlib_cli_command_t * cmd)
     319             : {
     320           0 :   nsh_md2_ioam_trace_main_t *hm = &nsh_md2_ioam_trace_main;
     321           0 :   u8 *s = 0;
     322           0 :   int i = 0;
     323             : 
     324           0 :   for (i = 0; i < NSH_MD2_IOAM_TRACE_N_STATS; i++)
     325             :     {
     326           0 :       s = format (s, " %s - %lu\n", nsh_md2_ioam_trace_stats_strings[i],
     327             :                   hm->counters[i]);
     328             :     }
     329             : 
     330           0 :   vlib_cli_output (vm, "%v", s);
     331           0 :   vec_free (s);
     332           0 :   return 0;
     333             : }
     334             : 
     335             : 
     336             : /* *INDENT-OFF* */
     337       58901 : VLIB_CLI_COMMAND (nsh_md2_ioam_show_ioam_trace_cmd, static) = {
     338             :   .path = "show ioam nsh-lisp-gpe trace",
     339             :   .short_help = "iOAM trace statistics",
     340             :   .function = nsh_md2_ioam_show_ioam_trace_cmd_fn,
     341             : };
     342             : /* *INDENT-ON* */
     343             : 
     344             : 
     345             : int
     346           0 : nsh_md2_ioam_trace_pop_handler (vlib_buffer_t * b, nsh_tlv_header_t * opt)
     347             : {
     348           0 :   return nsh_md2_ioam_trace_data_list_handler (b, opt);
     349             : }
     350             : 
     351             : static clib_error_t *
     352         575 : nsh_md2_ioam_trace_init (vlib_main_t * vm)
     353             : {
     354         575 :   nsh_md2_ioam_trace_main_t *hm = &nsh_md2_ioam_trace_main;
     355         575 :   nsh_md2_ioam_main_t *gm = &nsh_md2_ioam_main;
     356             : 
     357         575 :   hm->vlib_main = vm;
     358         575 :   hm->vnet_main = vnet_get_main ();
     359         575 :   gm->unix_time_0 = (u32) time (0);  /* Store starting time */
     360         575 :   gm->vlib_time_0 = vlib_time_now (vm);
     361             : 
     362         575 :   clib_memset (hm->counters, 0, sizeof (hm->counters));
     363             : 
     364         575 :   if (nsh_md2_register_option
     365         575 :       (clib_host_to_net_u16 (0x9),
     366             :        NSH_MD2_IOAM_OPTION_TYPE_TRACE,
     367             :        NSH_MD2_IOAM_TRACE_SIZE_DUMMY,
     368             :        nsh_md2_ioam_trace_rewrite_handler,
     369             :        nsh_md2_ioam_trace_data_list_handler,
     370             :        nsh_md2_ioam_trace_swap_handler,
     371             :        nsh_md2_ioam_trace_pop_handler,
     372             :        nsh_md2_ioam_trace_data_list_trace_handler) < 0)
     373           0 :     return (clib_error_create
     374             :             ("registration of NSH_MD2_IOAM_OPTION_TYPE_TRACE failed"));
     375             : 
     376         575 :   return (0);
     377             : }
     378             : 
     379             : /* *INDENT-OFF* */
     380        1727 : VLIB_INIT_FUNCTION (nsh_md2_ioam_trace_init) =
     381             : {
     382             :   .runs_after = VLIB_INITS ("nsh_init", "nsh_md2_ioam_init"),
     383             : };
     384             : /* *INDENT-ON* */
     385             : 
     386             : int
     387           0 : nsh_md2_ioam_trace_profile_cleanup (void)
     388             : {
     389           0 :   nsh_main_t *hm = &nsh_main;
     390             : 
     391           0 :   hm->options_size[NSH_MD2_IOAM_OPTION_TYPE_TRACE] = 0;
     392             : 
     393           0 :   return 0;
     394             : 
     395             : }
     396             : 
     397             : static int
     398           0 : nsh_md2_ioam_trace_get_sizeof_handler (u32 * result)
     399             : {
     400           0 :   u16 size = 0;
     401           0 :   u8 trace_data_size = 0;
     402           0 :   trace_profile *profile = NULL;
     403             : 
     404           0 :   *result = 0;
     405             : 
     406           0 :   profile = nsh_trace_profile_find ();
     407             : 
     408           0 :   if (PREDICT_FALSE (!profile))
     409             :     {
     410           0 :       return (-1);
     411             :     }
     412             : 
     413           0 :   trace_data_size = fetch_trace_data_size (profile->trace_type);
     414           0 :   if (PREDICT_FALSE (trace_data_size == 0))
     415           0 :     return VNET_API_ERROR_INVALID_VALUE;
     416             : 
     417           0 :   if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254))
     418           0 :     return VNET_API_ERROR_INVALID_VALUE;
     419             : 
     420           0 :   size +=
     421             :     sizeof (nsh_md2_ioam_trace_option_t) +
     422           0 :     profile->num_elts * trace_data_size;
     423           0 :   *result = size;
     424             : 
     425           0 :   return 0;
     426             : }
     427             : 
     428             : 
     429             : int
     430           0 : nsh_md2_ioam_trace_profile_setup (void)
     431             : {
     432           0 :   u32 trace_size = 0;
     433           0 :   nsh_main_t *hm = &nsh_main;
     434             : 
     435           0 :   trace_profile *profile = NULL;
     436             : 
     437             : 
     438           0 :   profile = nsh_trace_profile_find ();
     439             : 
     440           0 :   if (PREDICT_FALSE (!profile))
     441             :     {
     442           0 :       return (-1);
     443             :     }
     444             : 
     445             : 
     446           0 :   if (nsh_md2_ioam_trace_get_sizeof_handler (&trace_size) < 0)
     447           0 :     return (-1);
     448             : 
     449           0 :   hm->options_size[NSH_MD2_IOAM_OPTION_TYPE_TRACE] = trace_size;
     450             : 
     451           0 :   return (0);
     452             : }
     453             : 
     454             : 
     455             : 
     456             : /*
     457             :  * fd.io coding-style-patch-verification: ON
     458             :  *
     459             :  * Local Variables:
     460             :  * eval: (c-set-style "gnu")
     461             :  * End:
     462             :  */

Generated by: LCOV version 1.14