LCOV - code coverage report
Current view: top level - plugins/ioam/encap - ip6_ioam_trace.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 14 191 7.3 %
Date: 2023-07-05 22:20:52 Functions: 6 15 40.0 %

          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             : #include <vpp/app/version.h>
      19             : 
      20             : #include <vnet/ip/ip6.h>
      21             : #include <vnet/ip/ip6_hop_by_hop.h>
      22             : #include <vnet/ip/ip6_hop_by_hop_packet.h>
      23             : 
      24             : #include <vppinfra/hash.h>
      25             : #include <vppinfra/error.h>
      26             : #include <vppinfra/elog.h>
      27             : #include <vnet/plugin/plugin.h>
      28             : 
      29             : #include <ioam/lib-trace/trace_util.h>
      30             : #include <ioam/lib-trace/trace_config.h>
      31             : #include <ioam/encap/ip6_ioam_trace.h>
      32             : #include <ioam/udp-ping/udp_ping.h>
      33             : #include <ioam/udp-ping/udp_ping_packet.h>
      34             : #include <ioam/udp-ping/udp_ping_util.h>
      35             : 
      36             : /* Timestamp precision multipliers for seconds, milliseconds, microseconds
      37             :  * and nanoseconds respectively.
      38             :  */
      39             : static f64 trace_tsp_mul[4] = { 1, 1e3, 1e6, 1e9 };
      40             : 
      41             : typedef union
      42             : {
      43             :   u64 as_u64;
      44             :   u32 as_u32[2];
      45             : } time_u64_t;
      46             : 
      47             : extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main;
      48             : extern ip6_main_t ip6_main;
      49             : 
      50             : #define foreach_ip6_hop_by_hop_ioam_trace_stats                                \
      51             :   _(PROCESSED, "Pkts with ip6 hop-by-hop trace options")                        \
      52             :   _(PROFILE_MISS, "Pkts with ip6 hop-by-hop trace options but no profile set") \
      53             :   _(UPDATED, "Pkts with trace updated")                                        \
      54             :   _(FULL, "Pkts with trace options but no space")                              \
      55             :   _(LOOPBACK, "Pkts with trace options Loopback")                              \
      56             :   _(LOOPBACK_REPLY, "Pkts with trace options Loopback Reply")
      57             : 
      58             : static char *ip6_hop_by_hop_ioam_trace_stats_strings[] = {
      59             : #define _(sym,string) string,
      60             :   foreach_ip6_hop_by_hop_ioam_trace_stats
      61             : #undef _
      62             : };
      63             : 
      64             : typedef enum
      65             : {
      66             : #define _(sym,str) IP6_IOAM_TRACE_##sym,
      67             :   foreach_ip6_hop_by_hop_ioam_trace_stats
      68             : #undef _
      69             :     IP6_IOAM_TRACE_N_STATS,
      70             : } ip6_ioam_trace_stats_t;
      71             : 
      72             : 
      73             : typedef struct
      74             : {
      75             :   /* stats */
      76             :   u64 counters[ARRAY_LEN (ip6_hop_by_hop_ioam_trace_stats_strings)];
      77             : 
      78             :   /* convenience */
      79             :   vlib_main_t *vlib_main;
      80             :   vnet_main_t *vnet_main;
      81             : } ip6_hop_by_hop_ioam_trace_main_t;
      82             : 
      83             : ip6_hop_by_hop_ioam_trace_main_t ip6_hop_by_hop_ioam_trace_main;
      84             : 
      85             : always_inline void
      86           0 : ip6_ioam_trace_stats_increment_counter (u32 counter_index, u64 increment)
      87             : {
      88           0 :   ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main;
      89             : 
      90           0 :   hm->counters[counter_index] += increment;
      91           0 : }
      92             : 
      93             : 
      94             : static u8 *
      95           0 : format_ioam_data_list_element (u8 * s, va_list * args)
      96             : {
      97           0 :   u32 *elt = va_arg (*args, u32 *);
      98           0 :   u8 *trace_type_p = va_arg (*args, u8 *);
      99           0 :   u8 trace_type = *trace_type_p;
     100             : 
     101             : 
     102           0 :   if (trace_type & BIT_TTL_NODEID)
     103             :     {
     104           0 :       u32 ttl_node_id_host_byte_order = clib_net_to_host_u32 (*elt);
     105           0 :       s = format (s, "ttl 0x%x node id 0x%x ",
     106             :                   ttl_node_id_host_byte_order >> 24,
     107             :                   ttl_node_id_host_byte_order & 0x00FFFFFF);
     108             : 
     109           0 :       elt++;
     110             :     }
     111             : 
     112           0 :   if (trace_type & BIT_ING_INTERFACE && trace_type & BIT_ING_INTERFACE)
     113             :     {
     114           0 :       u32 ingress_host_byte_order = clib_net_to_host_u32 (*elt);
     115           0 :       s = format (s, "ingress 0x%x egress 0x%x ",
     116             :                   ingress_host_byte_order >> 16,
     117             :                   ingress_host_byte_order & 0xFFFF);
     118           0 :       elt++;
     119             :     }
     120             : 
     121           0 :   if (trace_type & BIT_TIMESTAMP)
     122             :     {
     123           0 :       u32 ts_in_host_byte_order = clib_net_to_host_u32 (*elt);
     124           0 :       s = format (s, "ts 0x%x \n", ts_in_host_byte_order);
     125           0 :       elt++;
     126             :     }
     127             : 
     128           0 :   if (trace_type & BIT_APPDATA)
     129             :     {
     130           0 :       u32 appdata_in_host_byte_order = clib_net_to_host_u32 (*elt);
     131           0 :       s = format (s, "app 0x%x ", appdata_in_host_byte_order);
     132           0 :       elt++;
     133             :     }
     134             : 
     135           0 :   return s;
     136             : }
     137             : 
     138             : 
     139             : int
     140           0 : ip6_ioam_trace_get_sizeof_handler (u32 * result)
     141             : {
     142           0 :   u16 size = 0;
     143           0 :   u8 trace_data_size = 0;
     144           0 :   trace_profile *profile = NULL;
     145             : 
     146           0 :   *result = 0;
     147             : 
     148           0 :   profile = trace_profile_find ();
     149             : 
     150           0 :   if (PREDICT_FALSE (!profile))
     151             :     {
     152           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1);
     153           0 :       return (-1);
     154             :     }
     155             : 
     156           0 :   trace_data_size = fetch_trace_data_size (profile->trace_type);
     157           0 :   if (PREDICT_FALSE (trace_data_size == 0))
     158           0 :     return VNET_API_ERROR_INVALID_VALUE;
     159             : 
     160           0 :   if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254))
     161           0 :     return VNET_API_ERROR_INVALID_VALUE;
     162             : 
     163           0 :   size +=
     164           0 :     sizeof (ioam_trace_option_t) + (profile->num_elts * trace_data_size);
     165           0 :   *result = size;
     166             : 
     167           0 :   return 0;
     168             : }
     169             : 
     170             : 
     171             : 
     172             : int
     173           0 : ip6_hop_by_hop_ioam_trace_rewrite_handler (u8 * rewrite_string,
     174             :                                            u8 * rewrite_size)
     175             : {
     176           0 :   ioam_trace_option_t *trace_option = NULL;
     177           0 :   u8 trace_data_size = 0;
     178           0 :   u8 trace_option_elts = 0;
     179           0 :   trace_profile *profile = NULL;
     180             : 
     181             : 
     182           0 :   profile = trace_profile_find ();
     183             : 
     184           0 :   if (PREDICT_FALSE (!profile))
     185             :     {
     186           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1);
     187           0 :       return (-1);
     188             :     }
     189             : 
     190           0 :   if (PREDICT_FALSE (!rewrite_string))
     191           0 :     return -1;
     192             : 
     193           0 :   trace_option_elts = profile->num_elts;
     194           0 :   trace_data_size = fetch_trace_data_size (profile->trace_type);
     195           0 :   trace_option = (ioam_trace_option_t *) rewrite_string;
     196           0 :   trace_option->hdr.type = HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST |
     197             :     HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
     198           0 :   trace_option->hdr.length = 2 /*ioam_trace_type,data_list_elts_left */  +
     199           0 :     trace_option_elts * trace_data_size;
     200           0 :   trace_option->trace_hdr.ioam_trace_type =
     201           0 :     profile->trace_type & TRACE_TYPE_MASK;
     202           0 :   trace_option->trace_hdr.data_list_elts_left = trace_option_elts;
     203           0 :   *rewrite_size =
     204           0 :     sizeof (ioam_trace_option_t) + (trace_option_elts * trace_data_size);
     205             : 
     206           0 :   return 0;
     207             : }
     208             : 
     209             : always_inline void
     210           0 : ip6_hbh_ioam_loopback_handler (vlib_buffer_t * b, ip6_header_t * ip,
     211             :                                ioam_trace_option_t * trace)
     212             : {
     213             :   u32 buf_index;
     214           0 :   ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main;
     215             :   vlib_buffer_t *b0;
     216           0 :   vlib_frame_t *nf = 0;
     217             :   u32 *to_next;
     218             :   vlib_node_t *next_node;
     219             :   ip6_header_t *ip6;
     220             :   ip6_hop_by_hop_header_t *hbh;
     221             :   ioam_trace_option_t *opt;
     222             :   udp_ping_t *udp;
     223             : 
     224           0 :   b0 = vlib_buffer_copy (hm->vlib_main, b);
     225           0 :   if (b0 == NULL)
     226           0 :     return;
     227             : 
     228           0 :   buf_index = vlib_get_buffer_index (hm->vlib_main, b0);
     229           0 :   next_node = vlib_get_node_by_name (hm->vlib_main, (u8 *) "ip6-lookup");
     230           0 :   nf = vlib_get_frame_to_node (hm->vlib_main, next_node->index);
     231           0 :   nf->n_vectors = 0;
     232           0 :   to_next = vlib_frame_vector_args (nf);
     233             : 
     234           0 :   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
     235           0 :   vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
     236             : 
     237           0 :   ip6 = vlib_buffer_get_current (b0);
     238           0 :   hbh = (ip6_hop_by_hop_header_t *) (ip6 + 1);
     239             :   opt = (ioam_trace_option_t *)
     240           0 :     ip6_hbh_get_option (hbh, HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST);
     241             : 
     242           0 :   udp = (udp_ping_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
     243           0 :   udp_ping_create_reply_from_probe_ip6 (ip6, hbh, udp);
     244           0 :   ip6_hbh_ioam_trace_set_bit (opt, BIT_LOOPBACK_REPLY);
     245             : 
     246           0 :   *to_next = buf_index;
     247           0 :   nf->n_vectors++;
     248           0 :   to_next++;
     249             : 
     250           0 :   vlib_put_frame_to_node (hm->vlib_main, next_node->index, nf);
     251           0 :   ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_LOOPBACK, 1);
     252             : }
     253             : 
     254             : int
     255           0 : ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip,
     256             :                                       ip6_hop_by_hop_option_t * opt)
     257             : {
     258           0 :   ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main;
     259           0 :   u8 elt_index = 0;
     260           0 :   ioam_trace_option_t *trace = (ioam_trace_option_t *) opt;
     261           0 :   u32 adj_index = vnet_buffer (b)->ip.adj_index[VLIB_TX];
     262           0 :   ip_adjacency_t *adj = adj_get (adj_index);
     263             :   time_u64_t time_u64;
     264             :   u32 *elt;
     265           0 :   int rv = 0;
     266           0 :   trace_profile *profile = NULL;
     267             : 
     268             : 
     269           0 :   profile = trace_profile_find ();
     270             : 
     271           0 :   if (PREDICT_FALSE (!profile))
     272             :     {
     273           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1);
     274           0 :       return (-1);
     275             :     }
     276             : 
     277             :   /* Don't trace loopback reply packets */
     278           0 :   if (trace->trace_hdr.ioam_trace_type & BIT_LOOPBACK_REPLY)
     279             :     {
     280           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_LOOPBACK_REPLY,
     281             :                                               1);
     282           0 :       return rv;
     283             :     }
     284             : 
     285           0 :   time_u64.as_u64 = 0;
     286             : 
     287           0 :   if (PREDICT_TRUE (trace->trace_hdr.data_list_elts_left))
     288             :     {
     289           0 :       trace->trace_hdr.data_list_elts_left--;
     290             :       /* fetch_trace_data_size returns in bytes. Convert it to 4-bytes
     291             :        * to skip to this node's location.
     292             :        */
     293           0 :       elt_index =
     294           0 :         trace->trace_hdr.data_list_elts_left *
     295           0 :         fetch_trace_data_size (trace->trace_hdr.ioam_trace_type) / 4;
     296           0 :       elt = &trace->trace_hdr.elts[elt_index];
     297           0 :       if (trace->trace_hdr.ioam_trace_type & BIT_TTL_NODEID)
     298             :         {
     299           0 :           *elt =
     300           0 :             clib_host_to_net_u32 ((ip->hop_limit << 24) | profile->node_id);
     301           0 :           elt++;
     302             :         }
     303             : 
     304           0 :       if (trace->trace_hdr.ioam_trace_type & BIT_ING_INTERFACE)
     305             :         {
     306           0 :           *elt =
     307           0 :             (vnet_buffer (b)->sw_if_index[VLIB_RX] & 0xFFFF) << 16 |
     308           0 :             (adj->rewrite_header.sw_if_index & 0xFFFF);
     309           0 :           *elt = clib_host_to_net_u32 (*elt);
     310           0 :           elt++;
     311             :         }
     312             : 
     313           0 :       if (trace->trace_hdr.ioam_trace_type & BIT_TIMESTAMP)
     314             :         {
     315             :           /* Send least significant 32 bits */
     316           0 :           f64 time_f64 =
     317           0 :             (f64) (((f64) hm->unix_time_0) +
     318           0 :                    (vlib_time_now (hm->vlib_main) - hm->vlib_time_0));
     319             : 
     320           0 :           time_u64.as_u64 = time_f64 * trace_tsp_mul[profile->trace_tsp];
     321           0 :           *elt = clib_host_to_net_u32 (time_u64.as_u32[0]);
     322           0 :           elt++;
     323             :         }
     324             : 
     325           0 :       if (trace->trace_hdr.ioam_trace_type & BIT_APPDATA)
     326             :         {
     327             :           /* $$$ set elt0->app_data */
     328           0 :           *elt = clib_host_to_net_u32 (profile->app_data);
     329           0 :           elt++;
     330             :         }
     331             : 
     332             : 
     333           0 :       if (PREDICT_FALSE (trace->trace_hdr.ioam_trace_type & BIT_LOOPBACK))
     334             :         {
     335             :           /* if loopback flag set then copy the packet
     336             :            * and send it back to source */
     337           0 :           ip6_hbh_ioam_loopback_handler (b, ip, trace);
     338             :         }
     339             : 
     340           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_UPDATED, 1);
     341             :     }
     342             :   else
     343             :     {
     344           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_FULL, 1);
     345             :     }
     346           0 :   return (rv);
     347             : }
     348             : 
     349             : u8 *
     350           0 : ip6_hbh_ioam_trace_data_list_trace_handler (u8 * s,
     351             :                                             ip6_hop_by_hop_option_t * opt)
     352             : {
     353             :   ioam_trace_option_t *trace;
     354           0 :   u8 trace_data_size_in_words = 0;
     355             :   u32 *elt;
     356           0 :   int elt_index = 0;
     357             : 
     358           0 :   trace = (ioam_trace_option_t *) opt;
     359             :   s =
     360           0 :     format (s, "  Trace Type 0x%x , %d elts left\n",
     361           0 :             trace->trace_hdr.ioam_trace_type,
     362           0 :             trace->trace_hdr.data_list_elts_left);
     363           0 :   trace_data_size_in_words =
     364           0 :     fetch_trace_data_size (trace->trace_hdr.ioam_trace_type) / 4;
     365           0 :   elt = &trace->trace_hdr.elts[0];
     366           0 :   while ((u8 *) elt <
     367           0 :          ((u8 *) (&trace->trace_hdr.elts[0]) + trace->hdr.length - 2
     368             :           /* -2 accounts for ioam_trace_type,elts_left */ ))
     369             :     {
     370           0 :       s = format (s, "    [%d] %U\n", elt_index,
     371             :                   format_ioam_data_list_element,
     372             :                   elt, &trace->trace_hdr.ioam_trace_type);
     373           0 :       elt_index++;
     374           0 :       elt += trace_data_size_in_words;
     375             :     }
     376           0 :   return (s);
     377             : }
     378             : 
     379             : 
     380             : static clib_error_t *
     381           0 : ip6_show_ioam_trace_cmd_fn (vlib_main_t * vm,
     382             :                             unformat_input_t * input,
     383             :                             vlib_cli_command_t * cmd)
     384             : {
     385           0 :   ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main;
     386           0 :   u8 *s = 0;
     387           0 :   int i = 0;
     388             : 
     389           0 :   for (i = 0; i < IP6_IOAM_TRACE_N_STATS; i++)
     390             :     {
     391           0 :       s =
     392           0 :         format (s, " %s - %lu\n", ip6_hop_by_hop_ioam_trace_stats_strings[i],
     393             :                 hm->counters[i]);
     394             :     }
     395             : 
     396           0 :   vlib_cli_output (vm, "%v", s);
     397           0 :   vec_free (s);
     398           0 :   return 0;
     399             : }
     400             : 
     401             : 
     402             : /* *INDENT-OFF* */
     403      176567 : VLIB_CLI_COMMAND (ip6_show_ioam_trace_cmd, static) = {
     404             :   .path = "show ioam trace",
     405             :   .short_help = "iOAM trace statistics",
     406             :   .function = ip6_show_ioam_trace_cmd_fn,
     407             : };
     408             : /* *INDENT-ON* */
     409             : 
     410             : /* *INDENT-OFF* */
     411             : VLIB_PLUGIN_REGISTER () = {
     412             :     .version = VPP_BUILD_VER,
     413             :     .description = "Inbound Operations, Administration, and Maintenance (OAM)",
     414             : };
     415             : /* *INDENT-ON* */
     416             : 
     417             : static clib_error_t *
     418         559 : ip6_hop_by_hop_ioam_trace_init (vlib_main_t * vm)
     419             : {
     420         559 :   ip6_hop_by_hop_ioam_trace_main_t *hm = &ip6_hop_by_hop_ioam_trace_main;
     421             : 
     422         559 :   hm->vlib_main = vm;
     423         559 :   hm->vnet_main = vnet_get_main ();
     424         559 :   clib_memset (hm->counters, 0, sizeof (hm->counters));
     425             : 
     426             : 
     427         559 :   if (ip6_hbh_register_option
     428             :       (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST,
     429             :        ip6_hbh_ioam_trace_data_list_handler,
     430             :        ip6_hbh_ioam_trace_data_list_trace_handler) < 0)
     431           0 :     return (clib_error_create
     432             :             ("registration of HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST failed"));
     433             : 
     434             : 
     435         559 :   if (ip6_hbh_add_register_option (HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST,
     436             :                                    sizeof (ioam_trace_option_t),
     437             :                                    ip6_hop_by_hop_ioam_trace_rewrite_handler)
     438             :       < 0)
     439           0 :     return (clib_error_create
     440             :             ("registration of HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST for rewrite failed"));
     441             : 
     442             : 
     443         559 :   return (0);
     444             : }
     445             : 
     446             : /* *INDENT-OFF* */
     447        2239 : VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_trace_init) =
     448             : {
     449             :   .runs_after = VLIB_INITS ("ip_main_init", "ip6_lookup_init",
     450             :                             "ip6_hop_by_hop_ioam_init"),
     451             : };
     452             : /* *INDENT-ON* */
     453             : 
     454             : int
     455         559 : ip6_trace_profile_cleanup (void)
     456             : {
     457         559 :   ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main;
     458             : 
     459         559 :   hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] = 0;
     460             : 
     461         559 :   return 0;
     462             : 
     463             : }
     464             : 
     465             : 
     466             : int
     467           0 : ip6_trace_profile_setup (void)
     468             : {
     469           0 :   u32 trace_size = 0;
     470           0 :   ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main;
     471             : 
     472           0 :   trace_profile *profile = NULL;
     473             : 
     474             : 
     475           0 :   profile = trace_profile_find ();
     476             : 
     477           0 :   if (PREDICT_FALSE (!profile))
     478             :     {
     479           0 :       ip6_ioam_trace_stats_increment_counter (IP6_IOAM_TRACE_PROFILE_MISS, 1);
     480           0 :       return (-1);
     481             :     }
     482             : 
     483             : 
     484           0 :   if (ip6_ioam_trace_get_sizeof_handler (&trace_size) < 0)
     485           0 :     return (-1);
     486             : 
     487           0 :   hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] = trace_size;
     488             : 
     489           0 :   return (0);
     490             : }
     491             : 
     492             : /*
     493             :  * fd.io coding-style-patch-verification: ON
     494             :  *
     495             :  * Local Variables:
     496             :  * eval: (c-set-style "gnu")
     497             :  * End:
     498             :  */

Generated by: LCOV version 1.14