LCOV - code coverage report
Current view: top level - plugins/ioam/lib-vxlan-gpe - vxlan_gpe_ioam_trace.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 22 202 10.9 %
Date: 2023-10-26 01:39:38 Functions: 7 18 38.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 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 <vnet/vxlan-gpe/vxlan_gpe.h>
      20             : #include <vnet/vxlan-gpe/vxlan_gpe_packet.h>
      21             : 
      22             : #include <vppinfra/hash.h>
      23             : #include <vppinfra/error.h>
      24             : #include <vppinfra/elog.h>
      25             : 
      26             : #include <ioam/lib-trace/trace_util.h>
      27             : #include <ioam/lib-trace/trace_config.h>
      28             : #include <ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h>
      29             : 
      30             : /* Timestamp precision multipliers for seconds, milliseconds, microseconds
      31             :  * and nanoseconds respectively.
      32             :  */
      33             : static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 };
      34             : 
      35             : typedef union
      36             : {
      37             :   u64 as_u64;
      38             :   u32 as_u32[2];
      39             : } time_u64_t;
      40             : 
      41             : 
      42             : /* *INDENT-OFF* */
      43             : typedef CLIB_PACKED(struct {
      44             :   vxlan_gpe_ioam_option_t hdr;
      45             :   u8 ioam_trace_type;
      46             :   u8 data_list_elts_left;
      47             :   u32 elts[0]; /* Variable type. So keep it generic */
      48             : }) vxlan_gpe_ioam_trace_option_t;
      49             : /* *INDENT-ON* */
      50             : 
      51             : 
      52             : #define foreach_vxlan_gpe_ioam_trace_stats                              \
      53             :   _(SUCCESS, "Pkts updated with TRACE records")                                       \
      54             :   _(FAILED, "Errors in TRACE due to lack of TRACE records")
      55             : 
      56             : static char *vxlan_gpe_ioam_trace_stats_strings[] = {
      57             : #define _(sym,string) string,
      58             :   foreach_vxlan_gpe_ioam_trace_stats
      59             : #undef _
      60             : };
      61             : 
      62             : typedef enum
      63             : {
      64             : #define _(sym,str) VXLAN_GPE_IOAM_TRACE_##sym,
      65             :   foreach_vxlan_gpe_ioam_trace_stats
      66             : #undef _
      67             :     VXLAN_GPE_IOAM_TRACE_N_STATS,
      68             : } vxlan_gpe_ioam_trace_stats_t;
      69             : 
      70             : 
      71             : typedef struct
      72             : {
      73             :   /* stats */
      74             :   u64 counters[ARRAY_LEN (vxlan_gpe_ioam_trace_stats_strings)];
      75             : 
      76             :   /* convenience */
      77             :   vlib_main_t *vlib_main;
      78             :   vnet_main_t *vnet_main;
      79             : } vxlan_gpe_ioam_trace_main_t;
      80             : 
      81             : vxlan_gpe_ioam_trace_main_t vxlan_gpe_ioam_trace_main;
      82             : 
      83             : int
      84         575 : vxlan_gpe_ioam_add_register_option (u8 option,
      85             :                                     u8 size,
      86             :                                     int rewrite_options (u8 * rewrite_string,
      87             :                                                          u8 * rewrite_size))
      88             : {
      89         575 :   vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
      90             : 
      91             :   ASSERT ((u32) option < ARRAY_LEN (hm->add_options));
      92             : 
      93             :   /* Already registered */
      94         575 :   if (hm->add_options[option])
      95           0 :     return (-1);
      96             : 
      97         575 :   hm->add_options[option] = rewrite_options;
      98         575 :   hm->options_size[option] = size;
      99             : 
     100         575 :   return (0);
     101             : }
     102             : 
     103             : int
     104           0 : vxlan_gpe_add_unregister_option (u8 option)
     105             : {
     106           0 :   vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
     107             : 
     108             :   ASSERT ((u32) option < ARRAY_LEN (hm->add_options));
     109             : 
     110             :   /* Not registered */
     111           0 :   if (!hm->add_options[option])
     112           0 :     return (-1);
     113             : 
     114           0 :   hm->add_options[option] = NULL;
     115           0 :   hm->options_size[option] = 0;
     116           0 :   return (0);
     117             : }
     118             : 
     119             : 
     120             : int
     121         575 : vxlan_gpe_ioam_register_option (u8 option,
     122             :                                 int options (vlib_buffer_t * b,
     123             :                                              vxlan_gpe_ioam_option_t * opt,
     124             :                                              u8 is_ipv4, u8 use_adj),
     125             :                                 u8 * trace (u8 * s,
     126             :                                             vxlan_gpe_ioam_option_t * opt))
     127             : {
     128         575 :   vxlan_gpe_ioam_main_t *im = &vxlan_gpe_ioam_main;
     129             : 
     130             :   ASSERT ((u32) option < ARRAY_LEN (im->options));
     131             : 
     132             :   /* Already registered */
     133         575 :   if (im->options[option])
     134           0 :     return (-1);
     135             : 
     136         575 :   im->options[option] = options;
     137         575 :   im->trace[option] = trace;
     138             : 
     139         575 :   return (0);
     140             : }
     141             : 
     142             : int
     143           0 : vxlan_gpe_ioam_unregister_option (u8 option)
     144             : {
     145           0 :   vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
     146             : 
     147             :   ASSERT ((u32) option < ARRAY_LEN (hm->options));
     148             : 
     149             :   /* Not registered */
     150           0 :   if (!hm->options[option])
     151           0 :     return (-1);
     152             : 
     153           0 :   hm->options[option] = NULL;
     154           0 :   hm->trace[option] = NULL;
     155             : 
     156           0 :   return (0);
     157             : }
     158             : 
     159             : 
     160             : always_inline void
     161           0 : vxlan_gpe_ioam_trace_stats_increment_counter (u32 counter_index,
     162             :                                               u64 increment)
     163             : {
     164           0 :   vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main;
     165             : 
     166           0 :   hm->counters[counter_index] += increment;
     167           0 : }
     168             : 
     169             : 
     170             : static u8 *
     171           0 : format_ioam_data_list_element (u8 * s, va_list * args)
     172             : {
     173           0 :   u32 *elt = va_arg (*args, u32 *);
     174           0 :   u8 *trace_type_p = va_arg (*args, u8 *);
     175           0 :   u8 trace_type = *trace_type_p;
     176             : 
     177             : 
     178           0 :   if (trace_type & BIT_TTL_NODEID)
     179             :     {
     180           0 :       u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt);
     181           0 :       s = format (s, "ttl 0x%x node id 0x%x ",
     182             :                   ttl_node_id_host_byte_order >> 24,
     183             :                   ttl_node_id_host_byte_order & 0x00FFFFFF);
     184             : 
     185           0 :       elt++;
     186             :     }
     187             : 
     188           0 :   if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE)
     189             :     {
     190           0 :       u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt);
     191           0 :       s = format (s, "ingress 0x%x egress 0x%x ",
     192             :                   ingress_host_byte_order >> 16,
     193             :                   ingress_host_byte_order & 0xFFFF);
     194           0 :       elt++;
     195             :     }
     196             : 
     197           0 :   if (trace_type & BIT_TIMESTAMP)
     198             :     {
     199           0 :       u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt);
     200           0 :       s = format (s, "ts 0x%x \n", ts_in_host_byte_order);
     201           0 :       elt++;
     202             :     }
     203             : 
     204           0 :   if (trace_type & BIT_APPDATA)
     205             :     {
     206           0 :       u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt);
     207           0 :       s = format (s, "app 0x%x ", appdata_in_host_byte_order);
     208           0 :       elt++;
     209             :     }
     210             : 
     211           0 :   return s;
     212             : }
     213             : 
     214             : 
     215             : 
     216             : int
     217           0 : vxlan_gpe_ioam_trace_rewrite_handler (u8 * rewrite_string, u8 * rewrite_size)
     218             : {
     219           0 :   vxlan_gpe_ioam_trace_option_t *trace_option = NULL;
     220           0 :   u8 trace_data_size = 0;
     221           0 :   u8 trace_option_elts = 0;
     222           0 :   trace_profile *profile = NULL;
     223             : 
     224             : 
     225           0 :   profile = trace_profile_find ();
     226             : 
     227           0 :   if (PREDICT_FALSE (!profile))
     228             :     {
     229           0 :       return (-1);
     230             :     }
     231             : 
     232           0 :   if (PREDICT_FALSE (!rewrite_string))
     233           0 :     return -1;
     234             : 
     235           0 :   trace_option_elts = profile->num_elts;
     236           0 :   trace_data_size = fetch_trace_data_size (profile->trace_type);
     237           0 :   trace_option = (vxlan_gpe_ioam_trace_option_t *) rewrite_string;
     238           0 :   trace_option->hdr.type = VXLAN_GPE_OPTION_TYPE_IOAM_TRACE;
     239           0 :   trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */  +
     240           0 :     trace_option_elts * trace_data_size;
     241           0 :   trace_option->ioam_trace_type = profile->trace_type & TRACE_TYPE_MASK;
     242           0 :   trace_option->data_list_elts_left = trace_option_elts;
     243           0 :   *rewrite_size =
     244           0 :     sizeof (vxlan_gpe_ioam_trace_option_t) +
     245           0 :     (trace_option_elts * trace_data_size);
     246             : 
     247           0 :   return 0;
     248             : }
     249             : 
     250             : 
     251             : int
     252           0 : vxlan_gpe_ioam_trace_data_list_handler (vlib_buffer_t * b,
     253             :                                         vxlan_gpe_ioam_option_t * opt,
     254             :                                         u8 is_ipv4, u8 use_adj)
     255             : {
     256           0 :   u8 elt_index = 0;
     257           0 :   vxlan_gpe_ioam_trace_option_t *trace =
     258             :     (vxlan_gpe_ioam_trace_option_t *) opt;
     259             :   time_u64_t time_u64;
     260             :   u32 *elt;
     261           0 :   int rv = 0;
     262           0 :   trace_profile *profile = NULL;
     263           0 :   vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
     264             : 
     265             : 
     266           0 :   profile = trace_profile_find ();
     267             : 
     268           0 :   if (PREDICT_FALSE (!profile))
     269             :     {
     270           0 :       return (-1);
     271             :     }
     272             : 
     273             : 
     274           0 :   time_u64.as_u64 = 0;
     275             : 
     276           0 :   if (PREDICT_TRUE (trace->data_list_elts_left))
     277             :     {
     278           0 :       trace->data_list_elts_left--;
     279             :       /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes
     280             :        * to skip to this node's location.
     281             :        */
     282           0 :       elt_index =
     283           0 :         trace->data_list_elts_left *
     284           0 :         fetch_trace_data_size (trace->ioam_trace_type) / 4;
     285           0 :       elt = &trace->elts[elt_index];
     286           0 :       if (is_ipv4)
     287             :         {
     288           0 :           if (trace->ioam_trace_type & BIT_TTL_NODEID)
     289             :             {
     290           0 :               ip4_header_t *ip0 = vlib_buffer_get_current (b);
     291             :               /* The transit case is the only case where the TTL decrement happens
     292             :                * before iOAM processing. For now, use the use_adj flag as an overload.
     293             :                * We can probably use a separate flag instead of overloading the use_adj flag.
     294             :                */
     295           0 :               *elt = clib_host_to_net_u32 (((ip0->ttl - 1 + use_adj) << 24) |
     296           0 :                                            profile->node_id);
     297           0 :               elt++;
     298             :             }
     299             : 
     300           0 :           if (trace->ioam_trace_type & BIT_ING_INTERFACE)
     301             :             {
     302           0 :               u16 tx_if = 0;
     303           0 :               u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX];
     304             : 
     305           0 :               if (use_adj)
     306             :                 {
     307           0 :                   ip_adjacency_t *adj = adj_get (adj_index);
     308           0 :                   tx_if = adj->rewrite_header.sw_if_index & 0xFFFF;
     309             :                 }
     310             : 
     311           0 :               *elt =
     312           0 :                 (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 |
     313             :                 tx_if;
     314           0 :               *elt = clib_host_to_net_u32 (*elt);
     315           0 :               elt++;
     316             :             }
     317             :         }
     318             :       else
     319             :         {
     320           0 :           if (trace->ioam_trace_type & BIT_TTL_NODEID)
     321             :             {
     322           0 :               ip6_header_t *ip0 = vlib_buffer_get_current (b);
     323           0 :               *elt = clib_host_to_net_u32 ((ip0->hop_limit << 24) |
     324           0 :                                            profile->node_id);
     325           0 :               elt++;
     326             :             }
     327           0 :           if (trace->ioam_trace_type & BIT_ING_INTERFACE)
     328             :             {
     329           0 :               u16 tx_if = 0;
     330           0 :               u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX];
     331             : 
     332           0 :               if (use_adj)
     333             :                 {
     334           0 :                   ip_adjacency_t *adj = adj_get (adj_index);
     335           0 :                   tx_if = adj->rewrite_header.sw_if_index & 0xFFFF;
     336             :                 }
     337             : 
     338           0 :               *elt =
     339           0 :                 (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 |
     340             :                 tx_if;
     341           0 :               *elt = clib_host_to_net_u32 (*elt);
     342           0 :               elt++;
     343             :             }
     344             :         }
     345             : 
     346           0 :       if (trace->ioam_trace_type & BIT_TIMESTAMP)
     347             :         {
     348             :           /* Send least significant 32 bits */
     349           0 :           f64 time_f64 =
     350           0 :             (f64) (((f64) hm->unix_time_0) +
     351           0 :                    (vlib_time_now (hm->vlib_main) - hm->vlib_time_0));
     352             : 
     353           0 :           time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp];
     354           0 :           *elt = clib_host_to_net_u32 (time_u64.as_u32[0]);
     355           0 :           elt++;
     356             :         }
     357             : 
     358           0 :       if (trace->ioam_trace_type & BIT_APPDATA)
     359             :         {
     360             :           /* $$$ set elt0->app_data */
     361           0 :           *elt = clib_host_to_net_u32 (profile->app_data);
     362           0 :           elt++;
     363             :         }
     364           0 :       vxlan_gpe_ioam_trace_stats_increment_counter
     365             :         (VXLAN_GPE_IOAM_TRACE_SUCCESS, 1);
     366             :     }
     367             :   else
     368             :     {
     369           0 :       vxlan_gpe_ioam_trace_stats_increment_counter
     370             :         (VXLAN_GPE_IOAM_TRACE_FAILED, 1);
     371             :     }
     372           0 :   return (rv);
     373             : }
     374             : 
     375             : u8 *
     376           0 : vxlan_gpe_ioam_trace_data_list_trace_handler (u8 * s,
     377             :                                               vxlan_gpe_ioam_option_t * opt)
     378             : {
     379             :   vxlan_gpe_ioam_trace_option_t *trace;
     380           0 :   u8 trace_data_size_in_words = 0;
     381             :   u32 *elt;
     382           0 :   int elt_index = 0;
     383             : 
     384           0 :   trace = (vxlan_gpe_ioam_trace_option_t *) opt;
     385             :   s =
     386           0 :     format (s, "  Trace Type 0x%x , %d elts left\n", trace->ioam_trace_type,
     387           0 :             trace->data_list_elts_left);
     388           0 :   trace_data_size_in_words =
     389           0 :     fetch_trace_data_size (trace->ioam_trace_type) / 4;
     390           0 :   elt = &trace->elts[0];
     391           0 :   while ((u8 *) elt < ((u8 *) (&trace->elts[0]) + trace->hdr.length - 2
     392             :                        /* -2 accounts for ioam_trace_type,elts_left */ ))
     393             :     {
     394           0 :       s = format (s, "    [%d] %U\n", elt_index,
     395             :                   format_ioam_data_list_element,
     396             :                   elt, &trace->ioam_trace_type);
     397           0 :       elt_index++;
     398           0 :       elt += trace_data_size_in_words;
     399             :     }
     400           0 :   return (s);
     401             : }
     402             : 
     403             : 
     404             : static clib_error_t *
     405           0 : vxlan_gpe_show_ioam_trace_cmd_fn (vlib_main_t * vm,
     406             :                                   unformat_input_t * input,
     407             :                                   vlib_cli_command_t * cmd)
     408             : {
     409           0 :   vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main;
     410           0 :   u8 *s = 0;
     411           0 :   int i = 0;
     412             : 
     413           0 :   for (i = 0; i < VXLAN_GPE_IOAM_TRACE_N_STATS; i++)
     414             :     {
     415           0 :       s = format (s, " %s - %lu\n", vxlan_gpe_ioam_trace_stats_strings[i],
     416             :                   hm->counters[i]);
     417             :     }
     418             : 
     419           0 :   vlib_cli_output (vm, "%v", s);
     420           0 :   vec_free (s);
     421           0 :   return 0;
     422             : }
     423             : 
     424             : 
     425             : /* *INDENT-OFF* */
     426      186217 : VLIB_CLI_COMMAND (vxlan_gpe_show_ioam_trace_cmd, static) = {
     427             :   .path = "show ioam vxlan-gpe trace",
     428             :   .short_help = "iOAM trace statistics",
     429             :   .function = vxlan_gpe_show_ioam_trace_cmd_fn,
     430             : };
     431             : /* *INDENT-ON* */
     432             : 
     433             : 
     434             : static clib_error_t *
     435         575 : vxlan_gpe_ioam_trace_init (vlib_main_t * vm)
     436             : {
     437         575 :   vxlan_gpe_ioam_trace_main_t *hm = &vxlan_gpe_ioam_trace_main;
     438             : 
     439         575 :   hm->vlib_main = vm;
     440         575 :   hm->vnet_main = vnet_get_main ();
     441         575 :   clib_memset (hm->counters, 0, sizeof (hm->counters));
     442             : 
     443         575 :   if (vxlan_gpe_ioam_register_option
     444             :       (VXLAN_GPE_OPTION_TYPE_IOAM_TRACE,
     445             :        vxlan_gpe_ioam_trace_data_list_handler,
     446             :        vxlan_gpe_ioam_trace_data_list_trace_handler) < 0)
     447           0 :     return (clib_error_create
     448             :             ("registration of VXLAN_GPE_OPTION_TYPE_IOAM_TRACE failed"));
     449             : 
     450             : 
     451         575 :   if (vxlan_gpe_ioam_add_register_option
     452             :       (VXLAN_GPE_OPTION_TYPE_IOAM_TRACE,
     453             :        sizeof (vxlan_gpe_ioam_trace_option_t),
     454             :        vxlan_gpe_ioam_trace_rewrite_handler) < 0)
     455           0 :     return (clib_error_create
     456             :             ("registration of VXLAN_GPE_OPTION_TYPE_IOAM_TRACE for rewrite failed"));
     457             : 
     458             : 
     459         575 :   return (0);
     460             : }
     461             : 
     462             : /* *INDENT-OFF* */
     463        4031 : VLIB_INIT_FUNCTION (vxlan_gpe_ioam_trace_init) =
     464             : {
     465             :   .runs_after = VLIB_INITS("ip_main_init", "ip6_lookup_init",
     466             :                            "vxlan_gpe_init"),
     467             : };
     468             : /* *INDENT-ON* */
     469             : 
     470             : 
     471             : int
     472           0 : vxlan_gpe_trace_profile_cleanup (void)
     473             : {
     474           0 :   vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
     475             : 
     476           0 :   hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] = 0;
     477             : 
     478           0 :   return 0;
     479             : 
     480             : }
     481             : 
     482             : static int
     483           0 : vxlan_gpe_ioam_trace_get_sizeof_handler (u32 * result)
     484             : {
     485           0 :   u16 size = 0;
     486           0 :   u8 trace_data_size = 0;
     487           0 :   trace_profile *profile = NULL;
     488             : 
     489           0 :   *result = 0;
     490             : 
     491           0 :   profile = trace_profile_find ();
     492             : 
     493           0 :   if (PREDICT_FALSE (!profile))
     494             :     {
     495           0 :       return (-1);
     496             :     }
     497             : 
     498           0 :   trace_data_size = fetch_trace_data_size (profile->trace_type);
     499           0 :   if (PREDICT_FALSE (trace_data_size == 0))
     500           0 :     return VNET_API_ERROR_INVALID_VALUE;
     501             : 
     502           0 :   if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254))
     503           0 :     return VNET_API_ERROR_INVALID_VALUE;
     504             : 
     505           0 :   size +=
     506             :     sizeof (vxlan_gpe_ioam_trace_option_t) +
     507           0 :     profile->num_elts * trace_data_size;
     508           0 :   *result = size;
     509             : 
     510           0 :   return 0;
     511             : }
     512             : 
     513             : 
     514             : int
     515           0 : vxlan_gpe_trace_profile_setup (void)
     516             : {
     517           0 :   u32 trace_size = 0;
     518           0 :   vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
     519             : 
     520           0 :   trace_profile *profile = NULL;
     521             : 
     522             : 
     523           0 :   profile = trace_profile_find ();
     524             : 
     525           0 :   if (PREDICT_FALSE (!profile))
     526             :     {
     527           0 :       return (-1);
     528             :     }
     529             : 
     530             : 
     531           0 :   if (vxlan_gpe_ioam_trace_get_sizeof_handler (&trace_size) < 0)
     532           0 :     return (-1);
     533             : 
     534           0 :   hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] = trace_size;
     535             : 
     536           0 :   return (0);
     537             : }
     538             : 
     539             : 
     540             : 
     541             : /*
     542             :  * fd.io coding-style-patch-verification: ON
     543             :  *
     544             :  * Local Variables:
     545             :  * eval: (c-set-style "gnu")
     546             :  * End:
     547             :  */

Generated by: LCOV version 1.14