LCOV - code coverage report
Current view: top level - vlibmemory - vlib_api_cli.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 175 668 26.2 %
Date: 2023-10-26 01:39:38 Functions: 30 49 61.2 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #include <fcntl.h>
      19             : #include <unistd.h>
      20             : #include <sys/types.h>
      21             : #include <sys/stat.h>
      22             : 
      23             : #include <vlibapi/api.h>
      24             : #include <vlibmemory/api.h>
      25             : 
      26             : static clib_error_t *
      27           0 : vl_api_show_histogram_command (vlib_main_t * vm,
      28             :                                unformat_input_t * input,
      29             :                                vlib_cli_command_t * cli_cmd)
      30             : {
      31           0 :   u64 total_counts = 0;
      32             :   int i;
      33             : 
      34           0 :   for (i = 0; i < SLEEP_N_BUCKETS; i++)
      35             :     {
      36           0 :       total_counts += vector_rate_histogram[i];
      37             :     }
      38             : 
      39           0 :   if (total_counts == 0)
      40             :     {
      41           0 :       vlib_cli_output (vm, "No control-plane activity.");
      42           0 :       return 0;
      43             :     }
      44             : 
      45             : #define _(n)                                                    \
      46             :     do {                                                        \
      47             :         f64 percent;                                            \
      48             :         percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
      49             :             / (f64) total_counts;                               \
      50             :         percent *= 100.0;                                       \
      51             :         vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n,    \
      52             :                          vector_rate_histogram[SLEEP_##n##_US], \
      53             :                          percent);                              \
      54             :     } while (0);
      55           0 :   foreach_histogram_bucket;
      56             : #undef _
      57             : 
      58           0 :   return 0;
      59             : }
      60             : 
      61             : /*?
      62             :  * Display the binary api sleep-time histogram
      63             : ?*/
      64             : /* *INDENT-OFF* */
      65      285289 : VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
      66             : {
      67             :   .path = "show api histogram",
      68             :   .short_help = "show api histogram",
      69             :   .function = vl_api_show_histogram_command,
      70             : };
      71             : /* *INDENT-ON* */
      72             : 
      73             : static clib_error_t *
      74           0 : vl_api_clear_histogram_command (vlib_main_t * vm,
      75             :                                 unformat_input_t * input,
      76             :                                 vlib_cli_command_t * cli_cmd)
      77             : {
      78             :   int i;
      79             : 
      80           0 :   for (i = 0; i < SLEEP_N_BUCKETS; i++)
      81           0 :     vector_rate_histogram[i] = 0;
      82           0 :   return 0;
      83             : }
      84             : 
      85             : /*?
      86             :  * Clear the binary api sleep-time histogram
      87             : ?*/
      88             : /* *INDENT-OFF* */
      89      285289 : VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
      90             : {
      91             :   .path = "clear api histogram",
      92             :   .short_help = "clear api histogram",
      93             :   .function = vl_api_clear_histogram_command,
      94             : };
      95             : /* *INDENT-ON* */
      96             : 
      97             : static clib_error_t *
      98           0 : vl_api_client_command (vlib_main_t * vm,
      99             :                        unformat_input_t * input, vlib_cli_command_t * cli_cmd)
     100             : {
     101             :   vl_api_registration_t **regpp, *regp;
     102             :   svm_queue_t *q;
     103             :   char *health;
     104           0 :   api_main_t *am = vlibapi_get_main ();
     105           0 :   u32 *confused_indices = 0;
     106             : 
     107           0 :   if (!pool_elts (am->vl_clients))
     108           0 :     goto socket_clients;
     109           0 :   vlib_cli_output (vm, "Shared memory clients");
     110           0 :   vlib_cli_output (vm, "%20s %8s %14s %18s %s",
     111             :                    "Name", "PID", "Queue Length", "Queue VA", "Health");
     112             : 
     113             :   /* *INDENT-OFF* */
     114           0 :   pool_foreach (regpp, am->vl_clients)
     115             :    {
     116           0 :     regp = *regpp;
     117             : 
     118           0 :     if (regp)
     119             :       {
     120           0 :         if (regp->unanswered_pings > 0)
     121           0 :           health = "questionable";
     122             :         else
     123           0 :           health = "OK";
     124             : 
     125           0 :         q = regp->vl_input_queue;
     126             : 
     127           0 :         vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
     128             :                          regp->name, q->consumer_pid, q->cursize,
     129             :                          q, health);
     130             :       }
     131             :     else
     132             :       {
     133           0 :         clib_warning ("NULL client registration index %d",
     134             :                       regpp - am->vl_clients);
     135           0 :         vec_add1 (confused_indices, regpp - am->vl_clients);
     136             :       }
     137             :   }
     138             :   /* *INDENT-ON* */
     139             : 
     140             :   /* This should "never happen," but if it does, fix it... */
     141           0 :   if (PREDICT_FALSE (vec_len (confused_indices) > 0))
     142             :     {
     143             :       int i;
     144           0 :       for (i = 0; i < vec_len (confused_indices); i++)
     145             :         {
     146           0 :           pool_put_index (am->vl_clients, confused_indices[i]);
     147             :         }
     148             :     }
     149           0 :   vec_free (confused_indices);
     150             : 
     151           0 :   if (am->missing_clients)
     152           0 :     vlib_cli_output (vm, "%u messages with missing clients",
     153             :                      am->missing_clients);
     154           0 : socket_clients:
     155           0 :   vl_sock_api_dump_clients (vm, am);
     156             : 
     157           0 :   return 0;
     158             : }
     159             : 
     160             : static clib_error_t *
     161           0 : vl_api_status_command (vlib_main_t * vm,
     162             :                        unformat_input_t * input, vlib_cli_command_t * cli_cmd)
     163             : {
     164           0 :   api_main_t *am = vlibapi_get_main ();
     165             : 
     166             :   /* check if rx_trace and tx_trace are not null pointers */
     167           0 :   if (am->rx_trace == 0)
     168             :     {
     169           0 :       vlib_cli_output (vm, "RX Trace disabled\n");
     170             :     }
     171             :   else
     172             :     {
     173           0 :       if (am->rx_trace->enabled == 0)
     174           0 :         vlib_cli_output (vm, "RX Trace disabled\n");
     175             :       else
     176           0 :         vlib_cli_output (vm, "RX Trace enabled\n");
     177             :     }
     178             : 
     179           0 :   if (am->tx_trace == 0)
     180             :     {
     181           0 :       vlib_cli_output (vm, "TX Trace disabled\n");
     182             :     }
     183             :   else
     184             :     {
     185           0 :       if (am->tx_trace->enabled == 0)
     186           0 :         vlib_cli_output (vm, "TX Trace disabled\n");
     187             :       else
     188           0 :         vlib_cli_output (vm, "TX Trace enabled\n");
     189             :     }
     190             : 
     191           0 :   return 0;
     192             : }
     193             : 
     194             : /* *INDENT-OFF* */
     195      285289 : VLIB_CLI_COMMAND (cli_show_api_command, static) =
     196             : {
     197             :   .path = "show api",
     198             :   .short_help = "Show API information",
     199             : };
     200             : /* *INDENT-ON* */
     201             : 
     202             : /*?
     203             :  * Display current api client connections
     204             : ?*/
     205             : /* *INDENT-OFF* */
     206      285289 : VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
     207             : {
     208             :   .path = "show api clients",
     209             :   .short_help = "Client information",
     210             :   .function = vl_api_client_command,
     211             : };
     212             : /* *INDENT-ON* */
     213             : 
     214             : /*?
     215             :  * Display the current api message tracing status
     216             : ?*/
     217             : /* *INDENT-OFF* */
     218      285289 : VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
     219             : {
     220             :   .path = "show api trace-status",
     221             :   .short_help = "Display API trace status",
     222             :   .function = vl_api_status_command,
     223             : };
     224             : /* *INDENT-ON* */
     225             : 
     226             : static clib_error_t *
     227           0 : vl_api_message_table_command (vlib_main_t * vm,
     228             :                               unformat_input_t * input,
     229             :                               vlib_cli_command_t * cli_cmd)
     230             : {
     231           0 :   api_main_t *am = vlibapi_get_main ();
     232             :   int i;
     233           0 :   int verbose = 0;
     234             : 
     235           0 :   if (unformat (input, "verbose"))
     236           0 :     verbose = 1;
     237             : 
     238             : 
     239           0 :   if (verbose == 0)
     240           0 :     vlib_cli_output (vm, "%-4s %s", "ID", "Name");
     241             :   else
     242           0 :     vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
     243             :                      "MP-safe");
     244             : 
     245           0 :   for (i = 1; i < vec_len (am->msg_data); i++)
     246             :     {
     247           0 :       vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
     248           0 :       if (verbose == 0)
     249             :         {
     250           0 :           vlib_cli_output (vm, "%-4d %s", i,
     251           0 :                            m->name ? m->name : "  [no handler]");
     252             :         }
     253             :       else
     254             :         {
     255           0 :           vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
     256           0 :                            m->name ? m->name : "  [no handler]", m->bounce,
     257           0 :                            m->is_mp_safe);
     258             :         }
     259             :     }
     260             : 
     261           0 :   return 0;
     262             : }
     263             : 
     264             : /*?
     265             :  * Display the current api message decode tables
     266             : ?*/
     267             : /* *INDENT-OFF* */
     268      285289 : VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
     269             : {
     270             :   .path = "show api message-table",
     271             :   .short_help = "Message Table",
     272             :   .function = vl_api_message_table_command,
     273             : };
     274             : /* *INDENT-ON* */
     275             : 
     276             : static int
     277           0 : range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
     278             : {
     279             :   int len0, len1, clen;
     280             : 
     281           0 :   len0 = vec_len (a0->name);
     282           0 :   len1 = vec_len (a1->name);
     283           0 :   clen = len0 < len1 ? len0 : len1;
     284           0 :   return (strncmp ((char *) a0->name, (char *) a1->name, clen));
     285             : }
     286             : 
     287             : static u8 *
     288           0 : format_api_msg_range (u8 * s, va_list * args)
     289             : {
     290           0 :   vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
     291             : 
     292           0 :   if (rp == 0)
     293           0 :     s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
     294             :   else
     295           0 :     s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
     296           0 :                 rp->last_msg_id);
     297             : 
     298           0 :   return s;
     299             : }
     300             : 
     301             : static clib_error_t *
     302           0 : vl_api_show_plugin_command (vlib_main_t * vm,
     303             :                             unformat_input_t * input,
     304             :                             vlib_cli_command_t * cli_cmd)
     305             : {
     306           0 :   api_main_t *am = vlibapi_get_main ();
     307           0 :   vl_api_msg_range_t *rp = 0;
     308             :   int i;
     309             : 
     310           0 :   if (vec_len (am->msg_ranges) == 0)
     311             :     {
     312           0 :       vlib_cli_output (vm, "No plugin API message ranges configured...");
     313           0 :       return 0;
     314             :     }
     315             : 
     316           0 :   rp = vec_dup (am->msg_ranges);
     317             : 
     318           0 :   vec_sort_with_function (rp, range_compare);
     319             : 
     320           0 :   vlib_cli_output (vm, "Plugin API message ID ranges...\n");
     321           0 :   vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
     322             : 
     323           0 :   for (i = 0; i < vec_len (rp); i++)
     324           0 :     vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
     325             : 
     326           0 :   vec_free (rp);
     327             : 
     328           0 :   return 0;
     329             : }
     330             : 
     331             : /*?
     332             :  * Display the plugin binary API message range table
     333             : ?*/
     334             : /* *INDENT-OFF* */
     335      285289 : VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
     336             : {
     337             :   .path = "show api plugin",
     338             :   .short_help = "show api plugin",
     339             :   .function = vl_api_show_plugin_command,
     340             : };
     341             : /* *INDENT-ON* */
     342             : 
     343             : typedef enum
     344             : {
     345             :   DUMP,
     346             :   DUMP_JSON,
     347             :   REPLAY,
     348             :   INITIALIZERS,
     349             : } vl_api_replay_t;
     350             : 
     351             : u8 *
     352           0 : format_vl_msg_api_trace_status (u8 * s, va_list * args)
     353             : {
     354           0 :   api_main_t *am = va_arg (*args, api_main_t *);
     355           0 :   vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
     356             :   vl_api_trace_t *tp;
     357             :   char *trace_name;
     358             : 
     359           0 :   switch (which)
     360             :     {
     361           0 :     case VL_API_TRACE_TX:
     362           0 :       tp = am->tx_trace;
     363           0 :       trace_name = "TX trace";
     364           0 :       break;
     365             : 
     366           0 :     case VL_API_TRACE_RX:
     367           0 :       tp = am->rx_trace;
     368           0 :       trace_name = "RX trace";
     369           0 :       break;
     370             : 
     371           0 :     default:
     372           0 :       abort ();
     373             :     }
     374             : 
     375           0 :   if (tp == 0)
     376             :     {
     377           0 :       s = format (s, "%s: not yet configured.\n", trace_name);
     378           0 :       return s;
     379             :     }
     380             : 
     381           0 :   s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
     382           0 :               trace_name, vec_len (tp->traces), tp->nitems,
     383           0 :               tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
     384           0 :   return s;
     385             : }
     386             : 
     387             : static void
     388           0 : vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
     389             :                          u32 first_index, u32 last_index,
     390             :                          vl_api_replay_t which)
     391             : {
     392             :   vl_api_trace_file_header_t *hp;
     393             :   int i, fd;
     394           0 :   u16 *msgid_vec = 0;
     395             :   struct stat statb;
     396             :   size_t file_size;
     397             :   u8 *msg;
     398           0 :   api_main_t *am = vlibapi_get_main ();
     399           0 :   u8 *tmpbuf = 0;
     400             :   u32 nitems, nitems_msgtbl;
     401             : 
     402           0 :   fd = open ((char *) filename, O_RDONLY);
     403             : 
     404           0 :   if (fd < 0)
     405             :     {
     406           0 :       vlib_cli_output (vm, "Couldn't open %s\n", filename);
     407           0 :       return;
     408             :     }
     409             : 
     410           0 :   if (fstat (fd, &statb) < 0)
     411             :     {
     412           0 :       vlib_cli_output (vm, "Couldn't stat %s\n", filename);
     413           0 :       close (fd);
     414           0 :       return;
     415             :     }
     416             : 
     417           0 :   if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
     418             :     {
     419           0 :       vlib_cli_output (vm, "File not plausible: %s\n", filename);
     420           0 :       close (fd);
     421           0 :       return;
     422             :     }
     423             : 
     424           0 :   file_size = statb.st_size;
     425           0 :   file_size = (file_size + 4095) & ~(4095);
     426             : 
     427           0 :   hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
     428             : 
     429           0 :   if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
     430             :     {
     431           0 :       vlib_cli_output (vm, "mmap failed: %s\n", filename);
     432           0 :       close (fd);
     433           0 :       return;
     434             :     }
     435           0 :   close (fd);
     436             : 
     437           0 :   clib_mem_unpoison (hp, file_size);
     438             : 
     439           0 :   nitems = ntohl (hp->nitems);
     440             : 
     441           0 :   if (last_index == (u32) ~ 0)
     442             :     {
     443           0 :       last_index = nitems - 1;
     444             :     }
     445             : 
     446           0 :   if (first_index >= nitems || last_index >= nitems)
     447             :     {
     448           0 :       vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
     449             :                        first_index, last_index, nitems - 1);
     450           0 :       munmap (hp, file_size);
     451           0 :       return;
     452             :     }
     453           0 :   if (hp->wrapped)
     454           0 :     vlib_cli_output (vm,
     455             :                      "Note: wrapped/incomplete trace, results may vary\n");
     456             : 
     457           0 :   size_t file_size_left = file_size;
     458             : 
     459             : #define assert_size(size_left, s)                                             \
     460             :   do                                                                          \
     461             :     {                                                                         \
     462             :       if ((s) >= size_left)                                                   \
     463             :         {                                                                     \
     464             :           vlib_cli_output (vm, "corrupted file");                             \
     465             :           munmap (hp, file_size);                                             \
     466             :           vec_free (msgid_vec);                                               \
     467             :           return;                                                             \
     468             :         }                                                                     \
     469             :       size_left -= s;                                                         \
     470             :     }                                                                         \
     471             :   while (0);
     472             : 
     473           0 :   assert_size (file_size_left, sizeof (hp[0]));
     474           0 :   msg = (u8 *) (hp + 1);
     475             : 
     476           0 :   serialize_main_t _sm, *sm = &_sm;
     477           0 :   u32 msgtbl_size = ntohl (hp->msgtbl_size);
     478             :   u8 *name_and_crc;
     479             : 
     480           0 :   assert_size (file_size_left, msgtbl_size);
     481             : 
     482           0 :   unserialize_open_data (sm, msg, msgtbl_size);
     483           0 :   unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
     484             : 
     485           0 :   for (i = 0; i < nitems_msgtbl; i++)
     486             :     {
     487           0 :       u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
     488           0 :       unserialize_cstring (sm, (char **) &name_and_crc);
     489           0 :       u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
     490           0 :       ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
     491           0 :       if (~0 == msg_index2)
     492           0 :         vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
     493             :                          msg_index);
     494           0 :       vec_validate (msgid_vec, msg_index);
     495           0 :       msgid_vec[msg_index] = msg_index2;
     496             :     }
     497             : 
     498           0 :   msg += msgtbl_size;
     499             : 
     500           0 :   for (i = 0; i < first_index; i++)
     501             :     {
     502             :       int size;
     503             :       u16 msg_id;
     504             : 
     505           0 :       assert_size (file_size_left, sizeof (u32));
     506           0 :       size = clib_host_to_net_u32 (*(u32 *) msg);
     507           0 :       msg += sizeof (u32);
     508             : 
     509           0 :       assert_size (file_size_left, clib_max (size, sizeof (u16)));
     510           0 :       msg_id = ntohs (*((u16 *) msg));
     511           0 :       if (msg_id >= vec_len (msgid_vec) ||
     512           0 :           msgid_vec[msg_id] >= vec_len (am->msg_data))
     513           0 :         vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
     514             :                          msg_id, i);
     515             : 
     516           0 :       msg += size;
     517             :     }
     518             : 
     519           0 :   if (which == REPLAY)
     520           0 :     am->replay_in_progress = 1;
     521             : 
     522           0 :   for (; i <= last_index; i++)
     523             :     {
     524             :       vl_api_msg_data_t *m;
     525             :       u16 msg_id;
     526             :       int size;
     527             : 
     528           0 :       if (which == DUMP)
     529           0 :         vlib_cli_output (vm, "---------- trace %d -----------\n", i);
     530             : 
     531           0 :       assert_size (file_size_left, sizeof (u32));
     532           0 :       size = clib_host_to_net_u32 (*(u32 *) msg);
     533           0 :       msg += sizeof (u32);
     534             : 
     535           0 :       assert_size (file_size_left, clib_max (size, sizeof (u16)));
     536           0 :       msg_id = ntohs (*((u16 *) msg));
     537             : 
     538           0 :       if (msg_id >= vec_len (msgid_vec) ||
     539           0 :           msgid_vec[msg_id] >= vec_len (am->msg_data))
     540             :         {
     541           0 :           vlib_cli_output (
     542             :             vm, "warning: unknown msg id %d for msg number %d, skipping\n",
     543             :             msg_id, i);
     544           0 :           msg += size;
     545           0 :           continue;
     546             :         }
     547             : 
     548           0 :       msg_id = msgid_vec[msg_id];
     549           0 :       m = vl_api_get_msg_data (am, msg_id);
     550             : 
     551             :       /* Copy the buffer (from the read-only mmap'ed file) */
     552           0 :       vec_validate (tmpbuf, size - 1 + sizeof (uword));
     553           0 :       clib_memcpy (tmpbuf + sizeof (uword), msg, size);
     554           0 :       clib_memset (tmpbuf, 0xf, sizeof (uword));
     555             : 
     556             :       /*
     557             :        * Endian swap if needed. All msg data is supposed to be in
     558             :        * network byte order.
     559             :        */
     560           0 :       if (((which == DUMP || which == DUMP_JSON) &&
     561             :            clib_arch_is_little_endian))
     562             :         {
     563           0 :           if (m && m->endian_handler == 0)
     564             :             {
     565           0 :               vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
     566           0 :               munmap (hp, file_size);
     567           0 :               vec_free (tmpbuf);
     568           0 :               am->replay_in_progress = 0;
     569           0 :               return;
     570             :             }
     571           0 :           if (m)
     572             :             {
     573           0 :               m->endian_handler (tmpbuf + sizeof (uword));
     574             :             }
     575             :         }
     576             : 
     577             :       /* msg_id always in network byte order */
     578             :       if (clib_arch_is_little_endian)
     579             :         {
     580           0 :           u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
     581           0 :           *msg_idp = msg_id;
     582             :         }
     583             : 
     584           0 :       switch (which)
     585             :         {
     586           0 :         case DUMP_JSON:
     587           0 :           vlib_cli_output (vm, "%U", format_vl_api_msg_json, am, msg_id,
     588             :                            tmpbuf + sizeof (uword));
     589           0 :           break;
     590             : 
     591           0 :         case DUMP:
     592           0 :           vlib_cli_output (vm, "%U", format_vl_api_msg_text, am, msg_id,
     593             :                            tmpbuf + sizeof (uword));
     594           0 :           break;
     595             : 
     596           0 :         case INITIALIZERS:
     597           0 :           if (m)
     598             :             {
     599             :               u8 *s;
     600             :               int j;
     601             : 
     602           0 :               vlib_cli_output (vm, "/*%U*/", format_vl_api_msg_text, am,
     603             :                                msg_id, tmpbuf + sizeof (uword));
     604             : 
     605           0 :               vlib_cli_output (vm, "*/\n");
     606             : 
     607           0 :               s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
     608             :                           m->trace_size);
     609             : 
     610           0 :               for (j = 0; j < m->trace_size; j++)
     611             :                 {
     612           0 :                   if ((j & 7) == 0)
     613           0 :                     s = format (s, "\n    ");
     614           0 :                   s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
     615             :                 }
     616           0 :               s = format (s, "\n};\n%c", 0);
     617           0 :               vlib_cli_output (vm, (char *) s);
     618           0 :               vec_free (s);
     619             :             }
     620           0 :           break;
     621             : 
     622           0 :         case REPLAY:
     623           0 :           if (m && m->handler && m->replay_allowed)
     624             :             {
     625           0 :               if (!m->is_mp_safe)
     626           0 :                 vl_msg_api_barrier_sync ();
     627           0 :               m->handler (tmpbuf + sizeof (uword));
     628           0 :               if (!m->is_mp_safe)
     629           0 :                 vl_msg_api_barrier_release ();
     630             :             }
     631             :           else
     632             :             {
     633           0 :               if (m && m->replay_allowed)
     634           0 :                 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
     635             :                                  msg_id);
     636           0 :               break;
     637             :             }
     638           0 :           break;
     639             :         }
     640             : 
     641           0 :       vec_set_len (tmpbuf, 0);
     642           0 :       msg += size;
     643             :     }
     644             : 
     645           0 :   munmap (hp, file_size);
     646           0 :   vec_free (tmpbuf);
     647           0 :   vec_free (msgid_vec);
     648           0 :   am->replay_in_progress = 0;
     649             : }
     650             : 
     651             : static int
     652        1578 : file_exists (u8 *fname)
     653             : {
     654        1578 :   FILE *fp = 0;
     655        1578 :   fp = fopen ((char *) fname, "r");
     656        1578 :   if (fp)
     657             :     {
     658           0 :       fclose (fp);
     659           0 :       return 1;
     660             :     }
     661        1578 :   return 0;
     662             : }
     663             : 
     664             : typedef struct
     665             : {
     666             :   vlib_main_t *vm;
     667             :   u8 is_json;
     668             : } vl_msg_print_args;
     669             : 
     670             : static int
     671           0 : vl_msg_print_trace (u8 *msg, void *ctx)
     672             : {
     673           0 :   vl_msg_print_args *a = ctx;
     674           0 :   api_main_t *am = vlibapi_get_main ();
     675           0 :   u16 msg_id = ntohs (*((u16 *) msg));
     676           0 :   vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
     677           0 :   u8 is_json = a->is_json;
     678           0 :   u8 *tmpbuf = 0;
     679             : 
     680           0 :   if (!m)
     681             :     {
     682           0 :       vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
     683           0 :       return 0;
     684             :     }
     685             : 
     686           0 :   if (clib_arch_is_little_endian && (m->endian_handler != NULL))
     687             :     {
     688           0 :       u32 msg_length = vec_len (msg);
     689           0 :       vec_validate (tmpbuf, msg_length - 1);
     690           0 :       clib_memcpy_fast (tmpbuf, msg, msg_length);
     691           0 :       msg = tmpbuf;
     692             : 
     693           0 :       m->endian_handler (tmpbuf);
     694             :     }
     695             : 
     696           0 :   vlib_cli_output (a->vm, "%U\n",
     697             :                    is_json ? format_vl_api_msg_json : format_vl_api_msg_text,
     698             :                    am, msg_id, msg);
     699             : 
     700           0 :   vec_free (tmpbuf);
     701           0 :   return 0;
     702             : }
     703             : 
     704             : static int
     705           0 : vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
     706             : {
     707           0 :   api_main_t *am = vlibapi_get_main ();
     708             :   vl_api_trace_t *tp;
     709             : 
     710           0 :   switch (which)
     711             :     {
     712           0 :     case VL_API_TRACE_TX:
     713           0 :       tp = am->tx_trace;
     714           0 :       break;
     715           0 :     case VL_API_TRACE_RX:
     716           0 :       tp = am->rx_trace;
     717           0 :       break;
     718           0 :     default:
     719           0 :       return -1;
     720             :     }
     721             : 
     722           0 :   if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
     723           0 :     return -1;
     724             : 
     725             :   vl_msg_print_args args;
     726           0 :   clib_memset (&args, 0, sizeof (args));
     727           0 :   args.is_json = is_json;
     728           0 :   args.vm = vm;
     729           0 :   vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
     730             : 
     731           0 :   return 0;
     732             : }
     733             : 
     734             : static char *
     735           1 : vl_msg_read_file (FILE *f)
     736           1 : {
     737           1 :   const size_t bufsize = 1024;
     738           1 :   char *buf[bufsize], *v = 0;
     739             :   size_t n;
     740             : 
     741           2 :   while ((n = fread (buf, 1, bufsize, f)))
     742           1 :     vec_add (v, buf, n);
     743             : 
     744             :   /* most callers expect a NULL-terminated C-string */
     745           1 :   if (v)
     746           1 :     vec_add1 (v, 0);
     747             : 
     748           1 :   return v;
     749             : }
     750             : 
     751             : static u16
     752           1 : vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
     753             : {
     754             :   uword *p;
     755           1 :   p = hash_get_mem (am->msg_index_by_name_and_crc, name);
     756           1 :   if (!p)
     757           0 :     return (u16) ~0;
     758             : 
     759           1 :   return p[0];
     760             : }
     761             : 
     762             : static u16
     763           0 : vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
     764             : {
     765             :   uword *p;
     766             : 
     767           0 :   if (!am->msg_id_by_name)
     768             :     {
     769           0 :       vlib_cli_output (vm, "message id table not yet initialized!\n");
     770           0 :       return (u16) ~0;
     771             :     }
     772             : 
     773           0 :   p = hash_get_mem (am->msg_id_by_name, name);
     774           0 :   if (!p)
     775           0 :     return (u16) ~0;
     776             : 
     777           0 :   return p[0];
     778             : }
     779             : 
     780             : static int
     781           1 : vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
     782             : {
     783           1 :   api_main_t *am = vlibapi_get_main ();
     784             :   u16 msg_id;
     785           1 :   int len = 0, rv = -1;
     786             :   vl_api_msg_data_t *m;
     787           1 :   u8 *msg = 0;
     788             : 
     789           1 :   cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
     790           1 :   if (!msg_id_obj)
     791             :     {
     792           0 :       vlib_cli_output (vm, "Missing '_msgname' element!\n");
     793           0 :       return rv;
     794             :     }
     795           1 :   char *name = cJSON_GetStringValue (msg_id_obj);
     796             : 
     797           1 :   cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
     798           1 :   if (!crc_obj)
     799             :     {
     800           0 :       vlib_cli_output (vm, "Missing '_crc' element!\n");
     801           0 :       return rv;
     802             :     }
     803           1 :   char *crc = cJSON_GetStringValue (crc_obj);
     804           1 :   u8 proc_warning = 0;
     805             : 
     806           1 :   u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
     807           1 :   msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
     808           1 :   m = vl_api_get_msg_data (am, msg_id);
     809           1 :   if (msg_id == (u16) ~0)
     810             :     {
     811           0 :       msg_id = vl_msg_find_id_by_name (vm, am, name);
     812           0 :       if (msg_id == (u16) ~0)
     813             :         {
     814           0 :           vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
     815           0 :           vec_free (name_crc);
     816           0 :           return rv;
     817             :         }
     818           0 :       proc_warning = 1;
     819             :     }
     820           1 :   vec_free (name_crc);
     821             : 
     822           1 :   if (m->replay_allowed)
     823             :     {
     824           1 :       if (proc_warning)
     825           0 :         vlib_cli_output (vm, "warning: msg %d has different signature\n");
     826             : 
     827           1 :       if (!m->fromjson_handler)
     828             :         {
     829           0 :           vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
     830             :                            msg_id);
     831           0 :           return rv;
     832             :         }
     833             : 
     834           1 :       msg = (u8 *) m->fromjson_handler (o, &len);
     835           1 :       if (!msg)
     836             :         {
     837           0 :           vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
     838             :                            msg_id);
     839           0 :           return rv;
     840             :         }
     841             : 
     842             :       if (clib_arch_is_little_endian)
     843           1 :         m->endian_handler (msg);
     844             : 
     845           1 :       if (!m->handler)
     846             :         {
     847           0 :           vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
     848           0 :           goto end;
     849             :         }
     850             : 
     851           1 :       if (m->handler)
     852             :         {
     853           1 :           if (!m->is_mp_safe)
     854           1 :             vl_msg_api_barrier_sync ();
     855           1 :           m->handler (msg);
     856           1 :           if (!m->is_mp_safe)
     857           1 :             vl_msg_api_barrier_release ();
     858             :         }
     859             :     }
     860             : 
     861           1 :   rv = 0;
     862           1 : end:
     863           1 :   if (msg)
     864           1 :     cJSON_free (msg);
     865           1 :   return rv;
     866             : }
     867             : 
     868             : static void
     869           1 : vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
     870             : {
     871           1 :   api_main_t *am = vlibapi_get_main ();
     872           1 :   cJSON *o = 0;
     873           1 :   int rv = 0;
     874           1 :   FILE *f = fopen ((char *) filename, "r");
     875             : 
     876           1 :   if (!f)
     877             :     {
     878           0 :       vlib_cli_output (vm, "failed to open %s!\n", filename);
     879           0 :       return;
     880             :     }
     881             : 
     882           1 :   char *buf = vl_msg_read_file (f);
     883           1 :   fclose (f);
     884             : 
     885           1 :   o = cJSON_Parse (buf);
     886           1 :   vec_free (buf);
     887           1 :   if (!o)
     888             :     {
     889           0 :       vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
     890             :                        cJSON_GetErrorPtr ());
     891           0 :       return;
     892             :     }
     893             : 
     894           1 :   if (cJSON_IsArray (o))
     895             :     {
     896           1 :       am->replay_in_progress = 1;
     897           1 :       size_t size = cJSON_GetArraySize (o);
     898           2 :       for (int i = 0; i < size; i++)
     899             :         {
     900           1 :           rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
     901           1 :           if (rv < 0)
     902             :             {
     903           0 :               am->replay_in_progress = 0;
     904           0 :               break;
     905             :             }
     906             :         }
     907             :     }
     908             :   else
     909             :     {
     910           0 :       rv = vl_msg_exec_json_command (vm, o);
     911             :     }
     912             : 
     913           1 :   if (rv < 0)
     914           0 :     vlib_cli_output (vm, "error during replaying API trace");
     915             : 
     916           1 :   cJSON_Delete (o);
     917             : }
     918             : 
     919             : static void
     920           0 : vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
     921             : {
     922           0 :   FILE *f = fopen ((char *) filename, "r");
     923             :   char *buf;
     924             : 
     925           0 :   if (!f)
     926             :     {
     927           0 :       vlib_cli_output (vm, "failed to open %s!\n", filename);
     928           0 :       return;
     929             :     }
     930             : 
     931           0 :   buf = vl_msg_read_file (f);
     932           0 :   fclose (f);
     933             : 
     934           0 :   if (!buf)
     935             :     {
     936           0 :       vlib_cli_output (vm, "no content in %s!\n", filename);
     937           0 :       return;
     938             :     }
     939             : 
     940           0 :   vlib_cli_output (vm, buf);
     941           0 :   vec_free (buf);
     942             : }
     943             : 
     944             : /** api_trace_command_fn - control the binary API trace / replay feature
     945             : 
     946             :     Note: this command MUST be marked thread-safe. Replay with
     947             :     multiple worker threads depends in many cases on worker thread
     948             :     graph replica maintenance. If we (implicitly) assert a worker
     949             :     thread barrier at the debug CLI level, all graph replica changes
     950             :     are deferred until the replay operation completes. If an interface
     951             :     is deleted, the wheels fall off.
     952             :  */
     953             : 
     954             : static clib_error_t *
     955        1585 : api_trace_command_fn (vlib_main_t * vm,
     956             :                       unformat_input_t * input, vlib_cli_command_t * cmd)
     957             : {
     958        1585 :   unformat_input_t _line_input, *line_input = &_line_input;
     959        1585 :   u32 nitems = 256 << 10;
     960        1585 :   api_main_t *am = vlibapi_get_main ();
     961        1585 :   vl_api_trace_which_t which = VL_API_TRACE_RX;
     962        1585 :   u8 *filename = 0;
     963        1585 :   u8 *chroot_filename = 0;
     964        1585 :   u32 first = 0;
     965        1585 :   u32 last = (u32) ~ 0;
     966             :   FILE *fp;
     967             :   int rv;
     968             : 
     969             :   /* Get a line of input. */
     970        1585 :   if (!unformat_user (input, unformat_line_input, line_input))
     971           0 :     return 0;
     972             : 
     973        1595 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     974             :     {
     975        1587 :       if (unformat (line_input, "on") || unformat (line_input, "enable"))
     976             :         {
     977           4 :           if (unformat (line_input, "nitems %d", &nitems))
     978             :             ;
     979           4 :           vlib_worker_thread_barrier_sync (vm);
     980           4 :           vl_msg_api_trace_configure (am, which, nitems);
     981           4 :           vl_msg_api_trace_onoff (am, which, 1 /* on */ );
     982           4 :           vlib_worker_thread_barrier_release (vm);
     983             :         }
     984        1583 :       else if (unformat (line_input, "off"))
     985             :         {
     986           0 :           vlib_worker_thread_barrier_sync (vm);
     987           0 :           vl_msg_api_trace_onoff (am, which, 0);
     988           0 :           vlib_worker_thread_barrier_release (vm);
     989             :         }
     990        1583 :       else if (unformat (line_input, "save-json %s", &filename))
     991             :         {
     992           1 :           if (strstr ((char *) filename, "..") ||
     993           1 :               index ((char *) filename, '/'))
     994             :             {
     995           0 :               vlib_cli_output (vm, "illegal characters in filename '%s'",
     996             :                                filename);
     997           0 :               goto out;
     998             :             }
     999             : 
    1000           1 :           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
    1001             : 
    1002           1 :           vec_free (filename);
    1003             : 
    1004           1 :           if (file_exists (chroot_filename))
    1005             :             {
    1006           0 :               vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
    1007           0 :               goto out;
    1008             :             }
    1009             : 
    1010           1 :           fp = fopen ((char *) chroot_filename, "w");
    1011           1 :           if (fp == NULL)
    1012             :             {
    1013           0 :               vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
    1014           0 :               goto out;
    1015             :             }
    1016           1 :           vlib_worker_thread_barrier_sync (vm);
    1017           1 :           rv = vl_msg_api_trace_save (am, which, fp, 1);
    1018           1 :           if (rv == -1)
    1019           0 :             vlib_cli_output (vm, "API Trace data not present\n");
    1020           1 :           else if (rv < 0)
    1021           0 :             vlib_cli_output (vm, "failed to save api trace\n");
    1022             :           else
    1023           1 :             vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
    1024           1 :           vlib_worker_thread_barrier_release (vm);
    1025           1 :           fclose (fp);
    1026             :         }
    1027        1582 :       else if (unformat (line_input, "save %s", &filename))
    1028             :         {
    1029        1577 :           if (strstr ((char *) filename, "..")
    1030        1577 :               || index ((char *) filename, '/'))
    1031             :             {
    1032           0 :               vlib_cli_output (vm, "illegal characters in filename '%s'",
    1033             :                                filename);
    1034           0 :               goto out;
    1035             :             }
    1036             : 
    1037        1577 :           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
    1038             : 
    1039        1577 :           vec_free (filename);
    1040             : 
    1041        1577 :           if (file_exists (chroot_filename))
    1042             :             {
    1043           0 :               vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
    1044           0 :               goto out;
    1045             :             }
    1046             : 
    1047        1577 :           fp = fopen ((char *) chroot_filename, "w");
    1048        1577 :           if (fp == NULL)
    1049             :             {
    1050           0 :               vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
    1051           0 :               goto out;
    1052             :             }
    1053        1577 :           vlib_worker_thread_barrier_sync (vm);
    1054        1577 :           rv = vl_msg_api_trace_save (am, which, fp, 0);
    1055        1577 :           vlib_worker_thread_barrier_release (vm);
    1056        1577 :           fclose (fp);
    1057        1577 :           if (rv == -1)
    1058           0 :             vlib_cli_output (vm, "API Trace data not present\n");
    1059        1577 :           else if (rv == -2)
    1060           0 :             vlib_cli_output (vm, "File for writing is closed\n");
    1061        1577 :           else if (rv == -10)
    1062           0 :             vlib_cli_output (vm, "Error while writing header to file\n");
    1063        1577 :           else if (rv == -11)
    1064           0 :             vlib_cli_output (vm, "Error while writing trace to file\n");
    1065        1577 :           else if (rv == -12)
    1066           0 :             vlib_cli_output (vm,
    1067             :                              "Error while writing end of buffer trace to file\n");
    1068        1577 :           else if (rv == -13)
    1069           0 :             vlib_cli_output (vm,
    1070             :                              "Error while writing start of buffer trace to file\n");
    1071        1577 :           else if (rv < 0)
    1072           0 :             vlib_cli_output (vm, "Unknown error while saving: %d", rv);
    1073             :           else
    1074        1577 :             vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
    1075        1577 :           goto out;
    1076             :         }
    1077           5 :       else if (unformat (line_input, "tojson %s", &filename))
    1078             :         {
    1079           0 :           vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
    1080             :         }
    1081           5 :       else if (unformat (line_input, "dump-file-json %s", &filename))
    1082             :         {
    1083           0 :           vl_msg_dump_file_json (vm, filename);
    1084             :         }
    1085           5 :       else if (unformat (line_input, "dump-file %s", &filename))
    1086             :         {
    1087           0 :           vl_msg_api_process_file (vm, filename, first, last, DUMP);
    1088             :         }
    1089           5 :       else if (unformat (line_input, "dump-json"))
    1090             :         {
    1091           0 :           vl_msg_api_dump_trace (vm, which, 1);
    1092             :         }
    1093           5 :       else if (unformat (line_input, "dump"))
    1094             :         {
    1095           0 :           vl_msg_api_dump_trace (vm, which, 0);
    1096             :         }
    1097           5 :       else if (unformat (line_input, "replay-json %s", &filename))
    1098             :         {
    1099           1 :           vl_msg_replay_json (vm, filename);
    1100             :         }
    1101           4 :       else if (unformat (line_input, "replay %s", &filename))
    1102             :         {
    1103           0 :           vl_msg_api_process_file (vm, filename, first, last, REPLAY);
    1104             :         }
    1105           4 :       else if (unformat (line_input, "initializers %s", &filename))
    1106             :         {
    1107           0 :           vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
    1108             :         }
    1109           4 :       else if (unformat (line_input, "tx"))
    1110             :         {
    1111           2 :           which = VL_API_TRACE_TX;
    1112             :         }
    1113           2 :       else if (unformat (line_input, "first %d", &first))
    1114             :         {
    1115             :           ;
    1116             :         }
    1117           2 :       else if (unformat (line_input, "last %d", &last))
    1118             :         {
    1119             :           ;
    1120             :         }
    1121           2 :       else if (unformat (line_input, "status"))
    1122             :         {
    1123           0 :           vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
    1124             :                            am, which);
    1125             :         }
    1126           2 :       else if (unformat (line_input, "free"))
    1127             :         {
    1128           2 :           vlib_worker_thread_barrier_sync (vm);
    1129           2 :           vl_msg_api_trace_onoff (am, which, 0);
    1130           2 :           vl_msg_api_trace_free (am, which);
    1131           2 :           vlib_worker_thread_barrier_release (vm);
    1132             :         }
    1133           0 :       else if (unformat (line_input, "post-mortem-on"))
    1134           0 :         vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
    1135           0 :       else if (unformat (line_input, "post-mortem-off"))
    1136           0 :         vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
    1137             :       else
    1138           0 :         return clib_error_return (0, "unknown input `%U'",
    1139             :                                   format_unformat_error, input);
    1140             :     }
    1141           8 : out:
    1142        1585 :   vec_free (filename);
    1143        1585 :   vec_free (chroot_filename);
    1144        1585 :   unformat_free (line_input);
    1145        1585 :   return 0;
    1146             : }
    1147             : 
    1148             : /*?
    1149             :  * Display, replay, or save a binary API trace
    1150             : ?*/
    1151             : 
    1152             : /* *INDENT-OFF* */
    1153      285289 : VLIB_CLI_COMMAND (api_trace_command, static) = {
    1154             :   .path = "api trace",
    1155             :   .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
    1156             :                 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
    1157             :                 "json|replay <file>|replay-json <file>][nitems <n>]"
    1158             :                 "[initializers <file>]",
    1159             :   .function = api_trace_command_fn,
    1160             :   .is_mp_safe = 1,
    1161             : };
    1162             : /* *INDENT-ON* */
    1163             : 
    1164             : static clib_error_t *
    1165         575 : api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
    1166             : {
    1167         575 :   u32 nitems = 256 << 10;
    1168         575 :   vl_api_trace_which_t which = VL_API_TRACE_RX;
    1169         575 :   api_main_t *am = vlibapi_get_main ();
    1170             : 
    1171        1150 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1172             :     {
    1173         575 :       if (unformat (input, "on") || unformat (input, "enable"))
    1174             :         {
    1175         575 :           if (unformat (input, "nitems %d", &nitems))
    1176             :             ;
    1177         575 :           vl_msg_api_trace_configure (am, which, nitems);
    1178         575 :           vl_msg_api_trace_onoff (am, which, 1 /* on */ );
    1179         575 :           vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
    1180             :         }
    1181           0 :       else if (unformat (input, "save-api-table %s",
    1182             :                          &am->save_msg_table_filename))
    1183             :         ;
    1184             :       else
    1185           0 :         return clib_error_return (0, "unknown input `%U'",
    1186             :                                   format_unformat_error, input);
    1187             :     }
    1188         575 :   return 0;
    1189             : }
    1190             : 
    1191             : /*?
    1192             :  * This module has three configuration parameters:
    1193             :  * "on" or "enable" - enables binary api tracing
    1194             :  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
    1195             :  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
    1196             : ?*/
    1197        7514 : VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
    1198             : 
    1199             : static clib_error_t *
    1200         575 : api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
    1201             : {
    1202         575 :   api_main_t *am = vlibapi_get_main ();
    1203             :   u32 nitems;
    1204             : 
    1205         575 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1206             :     {
    1207           0 :       if (unformat (input, "length %d", &nitems) ||
    1208           0 :           (unformat (input, "len %d", &nitems)))
    1209             :         {
    1210           0 :           if (nitems >= 1024)
    1211           0 :             am->vlib_input_queue_length = nitems;
    1212             :           else
    1213           0 :             clib_warning ("vlib input queue length %d too small, ignored",
    1214             :                           nitems);
    1215             :         }
    1216             :       else
    1217           0 :         return clib_error_return (0, "unknown input `%U'",
    1218             :                                   format_unformat_error, input);
    1219             :     }
    1220         575 :   return 0;
    1221             : }
    1222             : 
    1223        7514 : VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
    1224             : 
    1225             : static u8 *
    1226           0 : extract_name (u8 * s)
    1227             : {
    1228             :   u8 *rv;
    1229             : 
    1230           0 :   rv = vec_dup (s);
    1231             : 
    1232           0 :   while (vec_len (rv) && rv[vec_len (rv)] != '_')
    1233           0 :     vec_dec_len (rv, 1);
    1234             : 
    1235           0 :   rv[vec_len (rv)] = 0;
    1236             : 
    1237           0 :   return rv;
    1238             : }
    1239             : 
    1240             : static u8 *
    1241           0 : extract_crc (u8 * s)
    1242             : {
    1243             :   int i;
    1244             :   u8 *rv;
    1245             : 
    1246           0 :   rv = vec_dup (s);
    1247             : 
    1248           0 :   for (i = vec_len (rv) - 1; i >= 0; i--)
    1249             :     {
    1250           0 :       if (rv[i] == '_')
    1251             :         {
    1252           0 :           vec_delete (rv, i + 1, 0);
    1253           0 :           break;
    1254             :         }
    1255             :     }
    1256           0 :   return rv;
    1257             : }
    1258             : 
    1259             : typedef struct
    1260             : {
    1261             :   u8 *name_and_crc;
    1262             :   u8 *name;
    1263             :   u8 *crc;
    1264             :   u32 msg_index;
    1265             :   int which;
    1266             : } msg_table_unserialize_t;
    1267             : 
    1268             : static int
    1269           0 : table_id_cmp (void *a1, void *a2)
    1270             : {
    1271           0 :   msg_table_unserialize_t *n1 = a1;
    1272           0 :   msg_table_unserialize_t *n2 = a2;
    1273             : 
    1274           0 :   return (n1->msg_index - n2->msg_index);
    1275             : }
    1276             : 
    1277             : static int
    1278           0 : table_name_and_crc_cmp (void *a1, void *a2)
    1279             : {
    1280           0 :   msg_table_unserialize_t *n1 = a1;
    1281           0 :   msg_table_unserialize_t *n2 = a2;
    1282             : 
    1283           0 :   return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
    1284             : }
    1285             : 
    1286             : static clib_error_t *
    1287           0 : dump_api_table_file_command_fn (vlib_main_t * vm,
    1288             :                                 unformat_input_t * input,
    1289             :                                 vlib_cli_command_t * cmd)
    1290             : {
    1291           0 :   u8 *filename = 0;
    1292           0 :   api_main_t *am = vlibapi_get_main ();
    1293           0 :   serialize_main_t _sm, *sm = &_sm;
    1294             :   clib_error_t *error;
    1295             :   u32 nmsgs;
    1296             :   u32 msg_index;
    1297             :   u8 *name_and_crc;
    1298           0 :   int compare_current = 0;
    1299           0 :   int numeric_sort = 0;
    1300           0 :   msg_table_unserialize_t *table = 0, *item;
    1301             :   u32 i;
    1302           0 :   u32 ndifferences = 0;
    1303             : 
    1304           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1305             :     {
    1306           0 :       if (unformat (input, "file %s", &filename))
    1307             :         ;
    1308           0 :       else if (unformat (input, "compare-current")
    1309           0 :                || unformat (input, "compare"))
    1310           0 :         compare_current = 1;
    1311           0 :       else if (unformat (input, "numeric"))
    1312           0 :         numeric_sort = 1;
    1313             :       else
    1314           0 :         return clib_error_return (0, "unknown input `%U'",
    1315             :                                   format_unformat_error, input);
    1316             :     }
    1317             : 
    1318           0 :   if (numeric_sort && compare_current)
    1319           0 :     return clib_error_return
    1320             :       (0, "Comparison and numeric sorting are incompatible");
    1321             : 
    1322           0 :   if (filename == 0)
    1323           0 :     return clib_error_return (0, "File not specified");
    1324             : 
    1325             :   /* Load the serialized message table from the table dump */
    1326             : 
    1327           0 :   error = unserialize_open_clib_file (sm, (char *) filename);
    1328             : 
    1329           0 :   if (error)
    1330           0 :     return error;
    1331             : 
    1332           0 :   unserialize_integer (sm, &nmsgs, sizeof (u32));
    1333             : 
    1334           0 :   for (i = 0; i < nmsgs; i++)
    1335             :     {
    1336           0 :       msg_index = unserialize_likely_small_unsigned_integer (sm);
    1337           0 :       unserialize_cstring (sm, (char **) &name_and_crc);
    1338           0 :       vec_add2 (table, item, 1);
    1339           0 :       item->msg_index = msg_index;
    1340           0 :       item->name_and_crc = name_and_crc;
    1341           0 :       item->name = extract_name (name_and_crc);
    1342           0 :       item->crc = extract_crc (name_and_crc);
    1343           0 :       item->which = 0;               /* file */
    1344             :     }
    1345           0 :   unserialize_close (sm);
    1346             : 
    1347             :   /* Compare with the current image? */
    1348           0 :   if (compare_current)
    1349             :     {
    1350             :       /* Append the current message table */
    1351           0 :       u8 *tblv = vl_api_serialize_message_table (am, 0);
    1352             : 
    1353           0 :       serialize_open_vector (sm, tblv);
    1354           0 :       unserialize_integer (sm, &nmsgs, sizeof (u32));
    1355             : 
    1356           0 :       for (i = 0; i < nmsgs; i++)
    1357             :         {
    1358           0 :           msg_index = unserialize_likely_small_unsigned_integer (sm);
    1359           0 :           unserialize_cstring (sm, (char **) &name_and_crc);
    1360             : 
    1361           0 :           vec_add2 (table, item, 1);
    1362           0 :           item->msg_index = msg_index;
    1363           0 :           item->name_and_crc = name_and_crc;
    1364           0 :           item->name = extract_name (name_and_crc);
    1365           0 :           item->crc = extract_crc (name_and_crc);
    1366           0 :           item->which = 1;   /* current_image */
    1367             :         }
    1368           0 :       vec_free (tblv);
    1369             :     }
    1370             : 
    1371             :   /* Sort the table. */
    1372           0 :   if (numeric_sort)
    1373           0 :     vec_sort_with_function (table, table_id_cmp);
    1374             :   else
    1375           0 :     vec_sort_with_function (table, table_name_and_crc_cmp);
    1376             : 
    1377           0 :   if (compare_current)
    1378             :     {
    1379           0 :       u8 *dashes = 0;
    1380           0 :       ndifferences = 0;
    1381             : 
    1382             :       /*
    1383             :        * In this case, the recovered table will have two entries per
    1384             :        * API message. So, if entries i and i+1 match, the message definitions
    1385             :        * are identical. Otherwise, the crc is different, or a message is
    1386             :        * present in only one of the tables.
    1387             :        */
    1388           0 :       vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
    1389           0 :       vec_validate_init_empty (dashes, 60, '-');
    1390           0 :       vec_terminate_c_string (dashes);
    1391           0 :       vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
    1392           0 :       vec_free (dashes);
    1393           0 :       for (i = 0; i < vec_len (table);)
    1394             :         {
    1395             :           /* Last message lonely? */
    1396           0 :           if (i == vec_len (table) - 1)
    1397             :             {
    1398           0 :               ndifferences++;
    1399           0 :               goto last_unique;
    1400             :             }
    1401             : 
    1402             :           /* Identical pair? */
    1403           0 :           if (!strncmp
    1404           0 :               ((char *) table[i].name_and_crc,
    1405           0 :                (char *) table[i + 1].name_and_crc,
    1406           0 :                vec_len (table[i].name_and_crc)))
    1407             :             {
    1408           0 :               i += 2;
    1409           0 :               continue;
    1410             :             }
    1411             : 
    1412           0 :           ndifferences++;
    1413             : 
    1414             :           /* Only in one of two tables? */
    1415           0 :           if (i + 1 == vec_len (table)
    1416           0 :               || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
    1417             :             {
    1418           0 :             last_unique:
    1419           0 :               vlib_cli_output (vm, "%-60s | only in %s",
    1420           0 :                                table[i].name, table[i].which ?
    1421             :                                "image" : "file");
    1422           0 :               i++;
    1423           0 :               continue;
    1424             :             }
    1425             :           /* In both tables, but with different signatures */
    1426           0 :           vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
    1427           0 :           i += 2;
    1428             :         }
    1429           0 :       if (ndifferences == 0)
    1430           0 :         vlib_cli_output (vm, "No api message signature differences found.");
    1431             :       else
    1432           0 :         vlib_cli_output (vm, "\nFound %u api message signature differences",
    1433             :                          ndifferences);
    1434           0 :       goto cleanup;
    1435             :     }
    1436             : 
    1437             :   /* Dump the table, sorted as shown above */
    1438           0 :   vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
    1439             : 
    1440           0 :   for (i = 0; i < vec_len (table); i++)
    1441             :     {
    1442           0 :       item = table + i;
    1443           0 :       vlib_cli_output (vm, "%-60s %8u %10s", item->name,
    1444           0 :                        item->msg_index, item->crc);
    1445             :     }
    1446             : 
    1447           0 : cleanup:
    1448           0 :   for (i = 0; i < vec_len (table); i++)
    1449             :     {
    1450           0 :       vec_free (table[i].name_and_crc);
    1451           0 :       vec_free (table[i].name);
    1452           0 :       vec_free (table[i].crc);
    1453             :     }
    1454             : 
    1455           0 :   vec_free (table);
    1456             : 
    1457           0 :   return 0;
    1458             : }
    1459             : 
    1460             : /*?
    1461             :  * Displays a serialized API message decode table, sorted by message name
    1462             :  *
    1463             :  * @cliexpar
    1464             :  * @cliexstart{show api dump file <filename>}
    1465             :  *                                                Message name    MsgID        CRC
    1466             :  * accept_session                                                    407   8e2a127e
    1467             :  * accept_session_reply                                              408   67d8c22a
    1468             :  * add_node_next                                                     549   e4202993
    1469             :  * add_node_next_reply                                               550   e89d6eed
    1470             :  * etc.
    1471             :  * @cliexend
    1472             : ?*/
    1473             : 
    1474             : /*?
    1475             :  * Compares a serialized API message decode table with the current image
    1476             :  *
    1477             :  * @cliexpar
    1478             :  * @cliexstart{show api dump file <filename> compare}
    1479             :  * ip_add_del_route                                             definition changed
    1480             :  * ip_table_add_del                                             definition changed
    1481             :  * l2_macs_event                                                only in image
    1482             :  * vnet_ip4_fib_counters                                        only in file
    1483             :  * vnet_ip4_nbr_counters                                        only in file
    1484             :  * @cliexend
    1485             : ?*/
    1486             : 
    1487             : /*?
    1488             :  * Display a serialized API message decode table, compare a saved
    1489             :  * decode table with the current image, to establish API differences.
    1490             :  *
    1491             : ?*/
    1492             : /* *INDENT-OFF* */
    1493      285289 : VLIB_CLI_COMMAND (dump_api_table_file, static) =
    1494             : {
    1495             :   .path = "show api dump",
    1496             :   .short_help = "show api dump file <filename> [numeric | compare-current]",
    1497             :   .function = dump_api_table_file_command_fn,
    1498             : };
    1499             : 
    1500             : /* *INDENT-ON* */
    1501             : /*
    1502             :  * fd.io coding-style-patch-verification: ON
    1503             :  *
    1504             :  * Local Variables:
    1505             :  * eval: (c-set-style "gnu")
    1506             :  * End:
    1507             :  */

Generated by: LCOV version 1.14