LCOV - code coverage report
Current view: top level - plugins/mdata - mdata.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 123 136 90.4 %
Date: 2023-10-26 01:39:38 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /*
       2             :  * mdata.c - Buffer metadata change tracker
       3             :  *
       4             :  * Copyright (c) 2019 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vnet/vnet.h>
      19             : #include <vnet/plugin/plugin.h>
      20             : #include <mdata/mdata.h>
      21             : 
      22             : #include <vlibapi/api.h>
      23             : #include <vlibmemory/api.h>
      24             : #include <vppinfra/callback_data.h>
      25             : #include <vpp/app/version.h>
      26             : #include <stdbool.h>
      27             : 
      28             : #include <mdata/mdata.api_enum.h>
      29             : #include <mdata/mdata.api_types.h>
      30             : 
      31             : #define REPLY_MSG_ID_BASE mmp->msg_id_base
      32             : #include <vlibapi/api_helper_macros.h>
      33             : 
      34             : mdata_main_t mdata_main;
      35             : 
      36             : /** @file mdata.c
      37             :  * buffer metadata change tracker
      38             :  */
      39             : 
      40             : static mdata_t mdata_none;
      41             : 
      42             : /** Metadata tracking callback
      43             :     before_or_after: 0 => before, 1=> after
      44             : */
      45             : static void
      46        7549 : mdata_trace_callback (vlib_node_runtime_perf_callback_data_t * data,
      47             :                       vlib_node_runtime_perf_callback_args_t * args)
      48             : {
      49             :   int i;
      50        7549 :   mdata_main_t *mm = &mdata_main;
      51             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
      52             :   u32 *from;
      53             :   u32 n_left_from;
      54             :   mdata_t *before, *modifies;
      55             :   u8 *after;
      56        7549 :   vlib_main_t *vm = args->vm;
      57        7549 :   vlib_frame_t *frame = args->frame;
      58        7549 :   vlib_node_runtime_t *node = args->node;
      59             : 
      60        7549 :   if (PREDICT_FALSE (args->call_type == VLIB_NODE_RUNTIME_PERF_RESET))
      61        7543 :     return;
      62             : 
      63             :   /* Input nodes don't have frames, etc. */
      64        7548 :   if (frame == 0)
      65        7536 :     return;
      66             : 
      67          12 :   n_left_from = frame->n_vectors;
      68             : 
      69          12 :   if (n_left_from == 0)
      70           0 :     return;
      71             : 
      72          12 :   from = vlib_frame_vector_args (frame);
      73             : 
      74          12 :   vlib_get_buffers (vm, from, bufs, n_left_from);
      75          12 :   b = bufs;
      76             : 
      77          12 :   if (args->call_type == VLIB_NODE_RUNTIME_PERF_AFTER)
      78           6 :     goto after_pass;
      79             : 
      80             :   /* Resize the per-thread "before" vector to cover the current frame */
      81           6 :   vec_reset_length (mm->before_per_thread[vm->thread_index]);
      82           6 :   vec_validate (mm->before_per_thread[vm->thread_index], n_left_from - 1);
      83           6 :   before = mm->before_per_thread[vm->thread_index];
      84           6 :   before->node_index = ~0;
      85             : 
      86             :   /* Before we call the dispatch fn, copy metadata. */
      87          36 :   while (n_left_from > 0)
      88             :     {
      89          30 :       clib_memcpy_fast (before->mdata, b[0], sizeof (before->mdata));
      90          30 :       b++;
      91          30 :       before++;
      92          30 :       n_left_from--;
      93             :     }
      94           6 :   return;
      95             : 
      96           6 : after_pass:
      97             : 
      98             :   /* Recover the metadata copy we saved a moment ago */
      99           6 :   before = mm->before_per_thread[vm->thread_index];
     100             : 
     101             :   /* We'd better have the same number of buffers... */
     102           6 :   ASSERT (n_left_from == vec_len (before));
     103           6 :   ASSERT (node->node_index);
     104             : 
     105           6 :   clib_spinlock_lock_if_init (&mm->modify_lock);
     106             : 
     107             :   /*
     108             :    * Resize the per-node accumulator vector as needed
     109             :    * Paint the "no data" patter across any nodes we haven't seen yet
     110             :    */
     111         725 :   vec_validate_init_empty (mm->modifies, node->node_index, mdata_none);
     112           6 :   modifies = vec_elt_at_index (mm->modifies, node->node_index);
     113           6 :   modifies->node_index = node->node_index;
     114           6 :   before = mm->before_per_thread[vm->thread_index];
     115             : 
     116             :   /* Walk the frame */
     117          36 :   while (n_left_from > 0)
     118             :     {
     119          30 :       after = (u8 *) b[0];
     120             : 
     121             :       /* Compare metadata before and after node dispatch fn */
     122        3870 :       for (i = 0; i < ARRAY_LEN (before->mdata); i++)
     123             :         {
     124             :           /* Mark mdata octet changed */
     125        3840 :           if (before->mdata[i] != after[i])
     126         140 :             modifies->mdata[i] = 0xff;
     127             :         }
     128             : 
     129          30 :       b++;
     130          30 :       before++;
     131          30 :       n_left_from--;
     132             :     }
     133             : 
     134           6 :   clib_spinlock_unlock_if_init (&mm->modify_lock);
     135             : }
     136             : 
     137             : int
     138           2 : mdata_enable_disable (mdata_main_t * mmp, int enable_disable)
     139             : {
     140           2 :   int rv = 0;
     141           2 :   vlib_thread_main_t *thread_main = vlib_get_thread_main ();
     142             :   int i;
     143             : 
     144           2 :   if (mmp->modify_lock == 0 && thread_main->n_vlib_mains > 1)
     145           0 :     clib_spinlock_init (&mmp->modify_lock);
     146             : 
     147           2 :   if (vec_len (mmp->before_per_thread) == 0)
     148             :     {
     149           1 :       mdata_none.node_index = ~0;
     150           1 :       vec_validate (mmp->before_per_thread, vlib_get_n_threads () - 1);
     151             :     }
     152             : 
     153             :   /* Reset the per-node accumulator, see vec_validate_init_empty above */
     154           2 :   vec_reset_length (mmp->modifies);
     155             : 
     156           4 :   for (i = 0; i < vlib_get_n_threads (); i++)
     157             :     {
     158           2 :       vlib_main_t *ovm = vlib_get_main_by_index (i);
     159           2 :       if (ovm == 0)
     160           0 :         continue;
     161             : 
     162           2 :       clib_callback_data_enable_disable (
     163             :         &ovm->vlib_node_runtime_perf_callbacks, mdata_trace_callback,
     164             :         enable_disable);
     165             :     }
     166             : 
     167           2 :   return rv;
     168             : }
     169             : 
     170             : static clib_error_t *
     171           2 : mdata_enable_disable_command_fn (vlib_main_t * vm,
     172             :                                  unformat_input_t * input,
     173             :                                  vlib_cli_command_t * cmd)
     174             : {
     175           2 :   mdata_main_t *mmp = &mdata_main;
     176           2 :   int enable_disable = 1;
     177             : 
     178             :   int rv;
     179             : 
     180           3 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     181             :     {
     182           2 :       if (unformat (input, "disable") || unformat (input, "off"))
     183           1 :         enable_disable = 0;
     184           2 :       if (unformat (input, "enable") || unformat (input, "on"))
     185           1 :         enable_disable = 1;
     186             :       else
     187             :         break;
     188             :     }
     189             : 
     190           2 :   rv = mdata_enable_disable (mmp, enable_disable);
     191             : 
     192           2 :   switch (rv)
     193             :     {
     194           2 :     case 0:
     195           2 :       break;
     196             : 
     197           0 :     default:
     198           0 :       return clib_error_return (0, "mdata_enable_disable returned %d", rv);
     199             :     }
     200           2 :   return 0;
     201             : }
     202             : 
     203             : /*?
     204             :  * This command enables or disables buffer metadata change tracking
     205             :  *
     206             :  * @cliexpar
     207             :  * To enable buffer metadata change tracking:
     208             :  * @cliexstart{buffer metadata tracking on}
     209             :  * Tracking enabled
     210             :  * @cliexend
     211             :  *
     212             :  * @cliexstart{buffer metadata tracking off}
     213             :  * Tracking disabled
     214             :  * @cliexend
     215             : ?*/
     216             : 
     217             : /* *INDENT-OFF* */
     218      111319 : VLIB_CLI_COMMAND (mdata_enable_disable_command, static) =
     219             : {
     220             :   .path = "buffer metadata tracking",
     221             :   .short_help = "buffer metadata tracking [on][off]",
     222             :   .function = mdata_enable_disable_command_fn,
     223             : };
     224             : /* *INDENT-ON* */
     225             : 
     226             : /* API message handler */
     227           0 : static void vl_api_mdata_enable_disable_t_handler
     228             :   (vl_api_mdata_enable_disable_t * mp)
     229             : {
     230             :   vl_api_mdata_enable_disable_reply_t *rmp;
     231           0 :   mdata_main_t *mmp = &mdata_main;
     232             :   int rv;
     233             : 
     234           0 :   rv = mdata_enable_disable (mmp, (int) (mp->enable_disable));
     235             : 
     236           0 :   REPLY_MACRO (VL_API_MDATA_ENABLE_DISABLE_REPLY);
     237             : }
     238             : 
     239             : /* API definitions */
     240             : #include <mdata/mdata.api.c>
     241             : 
     242             : static clib_error_t *
     243         575 : mdata_init (vlib_main_t * vm)
     244             : {
     245         575 :   mdata_main_t *mmp = &mdata_main;
     246         575 :   clib_error_t *error = 0;
     247             : 
     248         575 :   mmp->vlib_main = vm;
     249         575 :   mmp->vnet_main = vnet_get_main ();
     250             : 
     251             :   /* Add our API messages to the global name_crc hash table */
     252         575 :   mmp->msg_id_base = setup_message_id_table ();
     253             : 
     254         575 :   return error;
     255             : }
     256             : 
     257        1151 : VLIB_INIT_FUNCTION (mdata_init);
     258             : 
     259             : /* *INDENT-OFF* */
     260             : VLIB_PLUGIN_REGISTER () =
     261             : {
     262             :   .version = VPP_BUILD_VER,
     263             :   .description = "Buffer metadata change tracker."
     264             : };
     265             : /* *INDENT-ON* */
     266             : 
     267             : 
     268             : #define foreach_primary_metadata_field          \
     269             : _(current_data)                                 \
     270             : _(current_length)                               \
     271             : _(flags)                                        \
     272             : _(flow_id)                                      \
     273             : _(ref_count)                                    \
     274             : _(buffer_pool_index)                            \
     275             : _(error)                                        \
     276             : _(next_buffer)                                  \
     277             : _(current_config_index)                         \
     278             : _(punt_reason)
     279             : 
     280             : #define foreach_opaque_metadata_field           \
     281             : _(sw_if_index[0])                               \
     282             : _(sw_if_index[1])                               \
     283             : _(l2_hdr_offset)                                \
     284             : _(l3_hdr_offset)                                \
     285             : _(l4_hdr_offset)                                \
     286             : _(feature_arc_index)                            \
     287             : _(ip.adj_index[0])                              \
     288             : _(ip.adj_index[1])                              \
     289             : _(ip.flow_hash)                                 \
     290             : _(ip.save_protocol)                             \
     291             : _(ip.fib_index)                                 \
     292             : _(ip.icmp.type)                                 \
     293             : _(ip.icmp.code)                                 \
     294             : _(ip.icmp.data)                                 \
     295             : _(ip.reass.next_index)                          \
     296             : _(ip.reass.error_next_index)                    \
     297             : _(ip.reass.owner_thread_index)                  \
     298             : _(ip.reass.ip_proto)                            \
     299             : _(ip.reass.l4_src_port)                         \
     300             : _(ip.reass.l4_dst_port)                         \
     301             : _(ip.reass.estimated_mtu)                       \
     302             : _(ip.reass.fragment_first)                      \
     303             : _(ip.reass.fragment_last)                       \
     304             : _(ip.reass.range_first)                         \
     305             : _(ip.reass.range_last)                          \
     306             : _(ip.reass.next_range_bi)                       \
     307             : _(ip.reass.ip6_frag_hdr_offset)                 \
     308             : _(mpls.ttl)                                     \
     309             : _(mpls.exp)                                     \
     310             : _(mpls.first)                                   \
     311             : _(mpls.save_rewrite_length)                     \
     312             : _(mpls.mpls_hdr_length)                         \
     313             : _(mpls.bier.n_bytes)                            \
     314             : _(l2.feature_bitmap)                            \
     315             : _(l2.bd_index)                                  \
     316             : _(l2.l2fib_sn)                                  \
     317             : _(l2.l2_len)                                    \
     318             : _(l2.shg)                                       \
     319             : _(l2.bd_age)                                    \
     320             : _(l2t.next_index)                               \
     321             : _(l2t.session_index)                            \
     322             : _(l2_classify.table_index)                      \
     323             : _(l2_classify.opaque_index)                     \
     324             : _(l2_classify.hash)                             \
     325             : _(policer.index)                                \
     326             : _(ipsec.sad_index)                              \
     327             : _(ipsec.protect_index)                          \
     328             : _(map.mtu)                                      \
     329             : _(map_t.map_domain_index)                       \
     330             : _(map_t.v6.saddr)                               \
     331             : _(map_t.v6.daddr)                               \
     332             : _(map_t.v6.frag_offset)                         \
     333             : _(map_t.v6.l4_offset)                           \
     334             : _(map_t.v6.l4_protocol)                         \
     335             : _(map_t.checksum_offset)                        \
     336             : _(map_t.mtu)                                    \
     337             : _(ip_frag.mtu)                                  \
     338             : _(ip_frag.next_index)                           \
     339             : _(ip_frag.flags)                                \
     340             : _(cop.current_config_index)                     \
     341             : _(lisp.overlay_afi)                             \
     342             : _(tcp.connection_index)                         \
     343             : _(tcp.seq_number)                               \
     344             : _(tcp.next_node_opaque)                         \
     345             : _(tcp.seq_end)                                  \
     346             : _(tcp.ack_number)                               \
     347             : _(tcp.hdr_offset)                               \
     348             : _(tcp.data_offset)                              \
     349             : _(tcp.data_len)                                 \
     350             : _(tcp.flags)                                    \
     351             : _(snat.flags)
     352             : 
     353             : #define foreach_opaque2_metadata_field                                        \
     354             :   _ (qos.bits)                                                                \
     355             :   _ (qos.source)                                                              \
     356             :   _ (loop_counter)                                                            \
     357             :   _ (gso_size)                                                                \
     358             :   _ (gso_l4_hdr_sz)
     359             : 
     360             : static u8 *
     361           1 : format_buffer_metadata_changes (u8 * s, va_list * args)
     362             : {
     363           1 :   mdata_main_t *mm = va_arg (*args, mdata_main_t *);
     364           1 :   int verbose = va_arg (*args, int);
     365             :   mdata_t *modifies;
     366             :   vlib_buffer_t *b;
     367             :   vnet_buffer_opaque_t *o;
     368             :   vnet_buffer_opaque2_t *o2;
     369             :   vlib_node_t *node;
     370             :   int i, j;
     371             :   int printed;
     372             : 
     373           1 :   clib_spinlock_lock_if_init (&mm->modify_lock);
     374             : 
     375         720 :   for (i = 0; i < vec_len (mm->modifies); i++)
     376             :     {
     377         719 :       modifies = vec_elt_at_index (mm->modifies, i);
     378         719 :       node = vlib_get_node (mm->vlib_main, i);
     379             : 
     380             :       /* No data for this node? */
     381         719 :       if (modifies->node_index == ~0)
     382             :         {
     383         713 :           if (verbose)
     384           0 :             s = format (s, "\n%v: no data\n", node->name);
     385         713 :           continue;
     386             :         }
     387             : 
     388             :       /* We visited the node, but it may not have changed any metadata... */
     389         220 :       for (j = 0; j < ARRAY_LEN (modifies->mdata); j++)
     390             :         {
     391         219 :           if (modifies->mdata[j])
     392           5 :             goto found;
     393             :         }
     394           1 :       s = format (s, "\n%v: no metadata changes\n", node->name);
     395           1 :       continue;
     396             : 
     397           5 :     found:
     398             :       /* Fields which the node modifies will be non-zero */
     399           5 :       b = (vlib_buffer_t *) (modifies->mdata);
     400             : 
     401             :       /* Dump primary metadata changes */
     402           5 :       s = format (s, "\n%v: ", node->name);
     403             : 
     404           5 :       printed = 0;
     405             : #define _(n) if (b->n) {s = format (s, "%s ", #n); printed = 1;}
     406           5 :       foreach_primary_metadata_field;
     407             : #undef _
     408             : 
     409           5 :       if (printed == 0)
     410           2 :         s = format (s, "no vlib_buffer_t metadata changes");
     411             : 
     412           5 :       vec_add1 (s, '\n');
     413             : 
     414             :       /*
     415             :        * Dump opaque union changes.
     416             :        * Hopefully this will give folks a clue about opaque
     417             :        * union data conflicts. That's the point of the exercise...
     418             :        */
     419           5 :       o = vnet_buffer (b);
     420           5 :       printed = 0;
     421           5 :       s = format (s, "  vnet_buffer_t: ");
     422             : 
     423             : #define _(n) if (o->n) {s = format (s, "%s ", #n); printed = 1;}
     424           5 :       foreach_opaque_metadata_field;
     425             : #undef _
     426             : 
     427           5 :       if (printed == 0)
     428           0 :         s = format (s, "no changes");
     429             : 
     430           5 :       vec_add1 (s, '\n');
     431             : 
     432           5 :       o2 = vnet_buffer2 (b);
     433           5 :       printed = 0;
     434           5 :       s = format (s, "  vnet_buffer2_t: ");
     435             : 
     436             : #define _(n) if (o2->n) {s = format (s, "%s ", #n); printed = 1;}
     437           5 :       foreach_opaque2_metadata_field;
     438             : #undef _
     439           5 :       if (printed == 0)
     440           5 :         s = format (s, "no changes");
     441             : 
     442           5 :       vec_add1 (s, '\n');
     443             : 
     444             :     }
     445             : 
     446           1 :   clib_spinlock_unlock_if_init (&mm->modify_lock);
     447             : 
     448           1 :   return s;
     449             : }
     450             : 
     451             : static clib_error_t *
     452           1 : show_metadata_command_fn (vlib_main_t * vm,
     453             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
     454             : {
     455           1 :   int verbose = 0;
     456             : 
     457           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     458             :     {
     459           0 :       if (unformat (input, "verbose %=", &verbose, 1))
     460             :         ;
     461             :       else
     462           0 :         break;
     463             :     }
     464             : 
     465           1 :   vlib_cli_output (vm, "%U", format_buffer_metadata_changes, &mdata_main,
     466             :                    verbose);
     467           1 :   return 0;
     468             : }
     469             : 
     470             : /*?
     471             :  * This command displays buffer metadata change information
     472             :  * @cliexpar
     473             :  * How to display buffer metadata change information
     474             :  * @cliexstart{show buffer metadata}
     475             :  * ethernet-input: current_data current_length flags error
     476             :  * vnet_buffer_t: l2_hdr_offset l3_hdr_offset
     477             :  * vnet_buffer2_t: no changes
     478             :  * @cliexend
     479             : ?*/
     480             : 
     481             : /* *INDENT-OFF* */
     482      111319 : VLIB_CLI_COMMAND (show_metadata_command, static) =
     483             : {
     484             :   .path = "show buffer metadata",
     485             :   .short_help = "show buffer metadata",
     486             :   .function = show_metadata_command_fn,
     487             : };
     488             : /* *INDENT-OFF* */
     489             : 
     490             : /*
     491             :  * fd.io coding-style-patch-verification: ON
     492             :  *
     493             :  * Local Variables:
     494             :  * eval: (c-set-style "gnu")
     495             :  * End:
     496             :  */

Generated by: LCOV version 1.14