LCOV - code coverage report
Current view: top level - vlib - cli.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 569 793 71.8 %
Date: 2023-10-26 01:39:38 Functions: 49 59 83.1 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /*
      16             :  * cli.c: command line interface
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vlib/vlib.h>
      41             : #include <vlib/stats/stats.h>
      42             : #include <vlib/unix/unix.h>
      43             : #include <vppinfra/callback.h>
      44             : #include <vppinfra/cpu.h>
      45             : #include <vppinfra/elog.h>
      46             : #include <unistd.h>
      47             : #include <ctype.h>
      48             : 
      49             : /** \file src/vlib/cli.c Debug CLI Implementation
      50             :  */
      51             : 
      52             : int vl_api_set_elog_trace_api_messages (int enable);
      53             : int vl_api_get_elog_trace_api_messages (void);
      54             : 
      55             : static void *current_traced_heap;
      56             : 
      57             : /* Root of all show commands. */
      58             : /* *INDENT-OFF* */
      59      285289 : VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
      60             :   .path = "show",
      61             :   .short_help = "Show commands",
      62             : };
      63             : /* *INDENT-ON* */
      64             : 
      65             : /* Root of all clear commands. */
      66             : /* *INDENT-OFF* */
      67      285289 : VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
      68             :   .path = "clear",
      69             :   .short_help = "Clear commands",
      70             : };
      71             : /* *INDENT-ON* */
      72             : 
      73             : /* Root of all set commands. */
      74             : /* *INDENT-OFF* */
      75      285289 : VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
      76             :   .path = "set",
      77             :   .short_help = "Set commands",
      78             : };
      79             : /* *INDENT-ON* */
      80             : 
      81             : /* Root of all test commands. */
      82             : /* *INDENT-OFF* */
      83      285289 : VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
      84             :   .path = "test",
      85             :   .short_help = "Test commands",
      86             : };
      87             : /* *INDENT-ON* */
      88             : 
      89             : /* Returns bitmap of commands which match key. */
      90             : static uword *
      91      555273 : vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
      92             : {
      93             :   int i, n;
      94      555273 :   uword *match = 0;
      95             :   vlib_cli_parse_position_t *p;
      96             : 
      97      555273 :   unformat_skip_white_space (input);
      98             : 
      99      555273 :   for (i = 0;; i++)
     100     4682690 :     {
     101             :       uword k;
     102             : 
     103     5237960 :       k = unformat_get_input (input);
     104     5237960 :       switch (k)
     105             :         {
     106     4685310 :         case 'a' ... 'z':
     107             :         case 'A' ... 'Z':
     108             :         case '0' ... '9':
     109             :         case '-':
     110             :         case '_':
     111     4685310 :           break;
     112             : 
     113      552647 :         case ' ':
     114             :         case '\t':
     115             :         case '\r':
     116             :         case '\n':
     117             :         case UNFORMAT_END_OF_INPUT:
     118             :           /* White space or end of input removes any non-white
     119             :              matches that were before possible. */
     120      552647 :           if (i < vec_len (c->sub_command_positions)
     121      418259 :               && clib_bitmap_count_set_bits (match) > 1)
     122             :             {
     123       16170 :               p = vec_elt_at_index (c->sub_command_positions, i);
     124     1254790 :               for (n = 0; n < vec_len (p->bitmaps); n++)
     125     1238620 :                 match = clib_bitmap_andnot (match, p->bitmaps[n]);
     126             :             }
     127      552647 :           goto done;
     128             : 
     129           5 :         default:
     130           5 :           unformat_put_input (input);
     131           5 :           goto done;
     132             :         }
     133             : 
     134     4685310 :       if (i >= vec_len (c->sub_command_positions))
     135             :         {
     136           0 :         no_match:
     137        2621 :           clib_bitmap_free (match);
     138        2621 :           return 0;
     139             :         }
     140             : 
     141     4685310 :       p = vec_elt_at_index (c->sub_command_positions, i);
     142     4685310 :       if (vec_len (p->bitmaps) == 0)
     143           0 :         goto no_match;
     144             : 
     145     4685310 :       n = k - p->min_char;
     146     4685310 :       if (n < 0 || n >= vec_len (p->bitmaps))
     147        2603 :         goto no_match;
     148             : 
     149     4682710 :       if (i == 0)
     150      535983 :         match = clib_bitmap_dup (p->bitmaps[n]);
     151             :       else
     152     4146720 :         match = clib_bitmap_and (match, p->bitmaps[n]);
     153             : 
     154     4682710 :       if (clib_bitmap_is_zero (match))
     155          18 :         goto no_match;
     156             :     }
     157             : 
     158      552652 : done:
     159      552652 :   return match;
     160             : }
     161             : 
     162             : uword
     163           0 : unformat_vlib_cli_line (unformat_input_t *i, va_list *va)
     164             : {
     165           0 :   unformat_input_t *result = va_arg (*va, unformat_input_t *);
     166           0 :   u8 *line = 0;
     167             :   uword c;
     168             :   int skip;
     169             : 
     170           0 : next_line:
     171           0 :   skip = 0;
     172             : 
     173             :   /* skip leading whitespace if any */
     174           0 :   unformat_skip_white_space (i);
     175             : 
     176           0 :   if (unformat_is_eof (i))
     177           0 :     return 0;
     178             : 
     179           0 :   while ((c = unformat_get_input (i)) != UNFORMAT_END_OF_INPUT)
     180             :     {
     181           0 :       if (c == '\\')
     182             :         {
     183           0 :           c = unformat_get_input (i);
     184             : 
     185           0 :           if (c == '\n')
     186             :             {
     187           0 :               if (!skip)
     188           0 :                 vec_add1 (line, '\n');
     189           0 :               skip = 0;
     190           0 :               continue;
     191             :             }
     192             : 
     193           0 :           if (!skip)
     194           0 :             vec_add1 (line, '\\');
     195             : 
     196           0 :           if (c == UNFORMAT_END_OF_INPUT)
     197           0 :             break;
     198             : 
     199           0 :           if (!skip)
     200           0 :             vec_add1 (line, c);
     201           0 :           continue;
     202             :         }
     203             : 
     204           0 :       if (c == '#')
     205           0 :         skip = 1;
     206           0 :       else if (c == '\n')
     207           0 :         break;
     208             : 
     209           0 :       if (!skip)
     210           0 :         vec_add1 (line, c);
     211             :     }
     212             : 
     213           0 :   if (line == 0)
     214           0 :     goto next_line;
     215             : 
     216           0 :   unformat_init_vector (result, line);
     217           0 :   return 1;
     218             : }
     219             : 
     220             : /* Looks for string based sub-input formatted { SUB-INPUT }. */
     221             : uword
     222      538303 : unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
     223             : {
     224      538303 :   unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
     225             :   u8 *s;
     226             :   uword c;
     227             : 
     228             :   while (1)
     229             :     {
     230      538308 :       c = unformat_get_input (i);
     231      538308 :       switch (c)
     232             :         {
     233           5 :         case ' ':
     234             :         case '\t':
     235             :         case '\n':
     236             :         case '\r':
     237             :         case '\f':
     238           5 :           break;
     239             : 
     240      538303 :         case '{':
     241             :         default:
     242             :           /* Put back paren. */
     243      538303 :           if (c != UNFORMAT_END_OF_INPUT)
     244      415484 :             unformat_put_input (i);
     245             : 
     246      538303 :           if (c == '{' && unformat (i, "%v", &s))
     247             :             {
     248        2354 :               unformat_init_vector (sub_input, s);
     249        2354 :               return 1;
     250             :             }
     251      535949 :           return 0;
     252             :         }
     253             :     }
     254             :   return 0;
     255             : }
     256             : 
     257             : static vlib_cli_command_t *
     258      535965 : get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
     259             : {
     260      535965 :   vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
     261      535965 :   return vec_elt_at_index (cm->commands, s->index);
     262             : }
     263             : 
     264             : static uword
     265      555269 : unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
     266             : {
     267      555269 :   vlib_main_t __clib_unused *vm = va_arg (*args, vlib_main_t *);
     268      555269 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     269      555269 :   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
     270      555269 :   vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
     271      555269 :   vlib_cli_main_t *cm = &vgm->cli_main;
     272             :   uword *match_bitmap, is_unique, index;
     273             : 
     274      555269 :   match_bitmap = vlib_cli_sub_command_match (c, i);
     275      555269 :   is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
     276      555269 :   index = ~0;
     277      555269 :   if (is_unique)
     278             :     {
     279      535963 :       index = clib_bitmap_first_set (match_bitmap);
     280      535963 :       *result = get_sub_command (cm, c, index);
     281             :     }
     282      555269 :   clib_bitmap_free (match_bitmap);
     283             : 
     284      555269 :   return is_unique;
     285             : }
     286             : 
     287             : static int
     288         768 : vlib_cli_cmp_strings (void *a1, void *a2)
     289             : {
     290         768 :   u8 *c1 = *(u8 **) a1;
     291         768 :   u8 *c2 = *(u8 **) a2;
     292             : 
     293        1175 :   return vec_cmp (c1, c2);
     294             : }
     295             : 
     296             : u8 **
     297           3 : vlib_cli_get_possible_completions (u8 * str)
     298             : {
     299             :   vlib_cli_command_t *c;
     300             :   vlib_cli_sub_command_t *sc;
     301           3 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     302           3 :   vlib_cli_main_t *vcm = &vgm->cli_main;
     303           3 :   uword *match_bitmap = 0;
     304             :   uword index, is_unique, help_next_level;
     305           3 :   u8 **result = 0;
     306             :   unformat_input_t input;
     307           3 :   unformat_init_vector (&input, vec_dup (str));
     308           3 :   c = vec_elt_at_index (vcm->commands, 0);
     309             : 
     310             :   /* remove trailing whitespace, except for one of them */
     311           9 :   while (vec_len (input.buffer) >= 2 &&
     312           8 :          isspace (input.buffer[vec_len (input.buffer) - 1]) &&
     313           7 :          isspace (input.buffer[vec_len (input.buffer) - 2]))
     314             :     {
     315           6 :       vec_del1 (input.buffer, vec_len (input.buffer) - 1);
     316             :     }
     317             : 
     318             :   /* if input is empty, directly return list of root commands */
     319           3 :   if (vec_len (input.buffer) == 0 ||
     320           3 :       (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
     321             :     {
     322           0 :       vec_foreach (sc, c->sub_commands)
     323             :       {
     324           0 :         vec_add1 (result, (u8 *) sc->name);
     325             :       }
     326           0 :       goto done;
     327             :     }
     328             : 
     329             :   /* add a trailing '?' so that vlib_cli_sub_command_match can find
     330             :    * all commands starting with the input string */
     331           3 :   vec_add1 (input.buffer, '?');
     332             : 
     333             :   while (1)
     334             :     {
     335           4 :       match_bitmap = vlib_cli_sub_command_match (c, &input);
     336             :       /* no match: return no result */
     337           4 :       if (match_bitmap == 0)
     338             :         {
     339           2 :           goto done;
     340             :         }
     341           2 :       is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
     342             :       /* unique match: try to step one subcommand level further */
     343           2 :       if (is_unique)
     344             :         {
     345             :           /* stop if no more input */
     346           2 :           if (input.index >= vec_len (input.buffer) - 1)
     347             :             {
     348           1 :               break;
     349             :             }
     350             : 
     351           1 :           index = clib_bitmap_first_set (match_bitmap);
     352           1 :           c = get_sub_command (vcm, c, index);
     353           1 :           clib_bitmap_free (match_bitmap);
     354           1 :           continue;
     355             :         }
     356             :       /* multiple matches: stop here, return all matches */
     357           0 :       break;
     358             :     }
     359             : 
     360             :   /* remove trailing '?' */
     361           1 :   vec_del1 (input.buffer, vec_len (input.buffer) - 1);
     362             : 
     363             :   /* if we have a space at the end of input, and a unique match,
     364             :    * autocomplete the next level of subcommands */
     365           1 :   help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
     366             :   /* *INDENT-OFF* */
     367           1 :   clib_bitmap_foreach (index, match_bitmap) {
     368           1 :     if (help_next_level && is_unique) {
     369           1 :         c = get_sub_command (vcm, c, index);
     370         137 :         vec_foreach (sc, c->sub_commands) {
     371         136 :           vec_add1 (result, (u8*) sc->name);
     372             :         }
     373           1 :         goto done; /* break doesn't work in this macro-loop */
     374             :     }
     375           0 :     sc = &c->sub_commands[index];
     376           0 :     vec_add1(result, (u8*) sc->name);
     377             :   }
     378             :   /* *INDENT-ON* */
     379             : 
     380           0 : done:
     381           3 :   clib_bitmap_free (match_bitmap);
     382           3 :   unformat_free (&input);
     383             : 
     384           3 :   if (result)
     385           1 :     vec_sort_with_function (result, vlib_cli_cmp_strings);
     386           3 :   return result;
     387             : }
     388             : 
     389             : static u8 *
     390        1085 : format_vlib_cli_command_help (u8 * s, va_list * args)
     391             : {
     392        1085 :   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
     393        1085 :   int is_long = va_arg (*args, int);
     394        1085 :   if (is_long && c->long_help)
     395           0 :     s = format (s, "%s", c->long_help);
     396        1085 :   else if (c->short_help)
     397        1011 :     s = format (s, "%s", c->short_help);
     398             :   else
     399          74 :     s = format (s, "%v commands", c->path);
     400        1085 :   return s;
     401             : }
     402             : 
     403             : static u8 *
     404         949 : format_vlib_cli_path (u8 * s, va_list * args)
     405             : {
     406         949 :   u8 *path = va_arg (*args, u8 *);
     407             : 
     408         949 :   s = format (s, "%v", path);
     409             : 
     410         949 :   return s;
     411             : }
     412             : 
     413             : static vlib_cli_command_t *
     414        1346 : all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
     415             : {
     416        1346 :   vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
     417             :   vlib_cli_sub_command_t *sc;
     418             : 
     419        1346 :   if (c->function)
     420         948 :     vec_add1 (subs, c[0]);
     421             : 
     422        2691 :   vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
     423             : 
     424        1346 :   return subs;
     425             : }
     426             : 
     427             : static int
     428         768 : vlib_cli_cmp_rule (void *a1, void *a2)
     429             : {
     430         768 :   vlib_cli_sub_rule_t *r1 = a1;
     431         768 :   vlib_cli_sub_rule_t *r2 = a2;
     432             : 
     433        1175 :   return vec_cmp (r1->name, r2->name);
     434             : }
     435             : 
     436             : static int
     437        7486 : vlib_cli_cmp_command (void *a1, void *a2)
     438             : {
     439        7486 :   vlib_cli_command_t *c1 = a1;
     440        7486 :   vlib_cli_command_t *c2 = a2;
     441             : 
     442       40862 :   return vec_cmp (c1->path, c2->path);
     443             : }
     444             : 
     445             : static clib_error_t *
     446      555274 : vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
     447             :                                 vlib_cli_main_t * cm,
     448             :                                 unformat_input_t * input,
     449             :                                 uword parent_command_index)
     450             : {
     451      555274 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     452             :   vlib_cli_command_t *parent, *c;
     453      555274 :   clib_error_t *error = 0;
     454             :   unformat_input_t sub_input;
     455             :   u8 *string;
     456      555274 :   uword is_main_dispatch = cm == &vgm->cli_main;
     457             : 
     458      555274 :   parent = vec_elt_at_index (cm->commands, parent_command_index);
     459      555274 :   if (is_main_dispatch && unformat (input, "help"))
     460           1 :     {
     461             :       uword help_at_end_of_line, i;
     462             : 
     463           1 :       help_at_end_of_line =
     464           1 :         unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
     465             :       while (1)
     466             :         {
     467           1 :           c = parent;
     468           1 :           if (unformat_user
     469             :               (input, unformat_vlib_cli_sub_command, vm, c, &parent))
     470             :             ;
     471             : 
     472           1 :           else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
     473           0 :             goto unknown;
     474             : 
     475             :           else
     476           1 :             break;
     477             :         }
     478             : 
     479             :       /* help SUB-COMMAND => long format help.
     480             :          "help" at end of line: show all commands. */
     481           1 :       if (!help_at_end_of_line)
     482           0 :         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
     483             :                          /* is_long */ 1);
     484             : 
     485           1 :       else if (vec_len (c->sub_commands) == 0)
     486           0 :         vlib_cli_output (vm, "%v: no sub-commands", c->path);
     487             : 
     488             :       else
     489             :         {
     490           1 :           vlib_cli_sub_rule_t *sr, *subs = 0;
     491             :           vlib_cli_sub_command_t *sc;
     492             : 
     493         137 :           vec_foreach (sc, c->sub_commands)
     494             :           {
     495         136 :             vec_add2 (subs, sr, 1);
     496         136 :             sr->name = sc->name;
     497         136 :             sr->command_index = sc->index;
     498         136 :             sr->rule_index = ~0;
     499             :           }
     500             : 
     501           1 :           vec_sort_with_function (subs, vlib_cli_cmp_rule);
     502             : 
     503         137 :           for (i = 0; i < vec_len (subs); i++)
     504             :             {
     505             :               vlib_cli_command_t *d;
     506             : 
     507         136 :               d = vec_elt_at_index (cm->commands, subs[i].command_index);
     508         136 :               vlib_cli_output
     509         136 :                 (vm, "  %-30v %U", subs[i].name,
     510             :                  format_vlib_cli_command_help, d, /* is_long */ 0);
     511             :             }
     512             : 
     513           1 :           vec_free (subs);
     514             :         }
     515             :     }
     516             : 
     517      555273 :   else if (is_main_dispatch
     518      555273 :            && (unformat (input, "choices") || unformat (input, "?")))
     519           1 :     {
     520             :       vlib_cli_command_t *sub, *subs;
     521             : 
     522           1 :       subs = all_subs (cm, 0, parent_command_index);
     523           1 :       vec_sort_with_function (subs, vlib_cli_cmp_command);
     524         949 :       vec_foreach (sub, subs)
     525         948 :         vlib_cli_output (vm, "  %-40U %U",
     526             :                          format_vlib_cli_path, sub->path,
     527             :                          format_vlib_cli_command_help, sub, /* is_long */ 0);
     528           1 :       vec_free (subs);
     529             :     }
     530             : 
     531      555272 :   else if (unformat (input, "comment %v", &string))
     532             :     {
     533           1 :       vec_free (string);
     534             :     }
     535             : 
     536      555271 :   else if (unformat (input, "vpplog %v", &string))
     537             :     {
     538             :       int i;
     539             :       /*
     540             :        * Delete leading whitespace, so "vpplog { this and that }"
     541             :        * and "vpplog this" line up nicely.
     542             :        */
     543           0 :       for (i = 0; i < vec_len (string); i++)
     544           0 :         if (string[i] != ' ')
     545           0 :           break;
     546           0 :       if (i > 0)
     547           0 :         vec_delete (string, i, 0);
     548             : 
     549           0 :       vlib_log_notice (cm->log, "CLI: %v", string);
     550           0 :       vec_free (string);
     551             :     }
     552             : 
     553      555271 :   else if (unformat (input, "uncomment %U",
     554             :                      unformat_vlib_cli_sub_input, &sub_input))
     555             :     {
     556             :       error =
     557           1 :         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
     558             :                                         parent_command_index);
     559           1 :       unformat_free (&sub_input);
     560             :     }
     561      555270 :   else if (unformat (input, "leak-check %U",
     562             :                      unformat_vlib_cli_sub_input, &sub_input))
     563             :     {
     564             :       u8 *leak_report;
     565           2 :       if (current_traced_heap)
     566             :         {
     567             :           void *oldheap;
     568           1 :           oldheap = clib_mem_set_heap (current_traced_heap);
     569           1 :           clib_mem_trace (0);
     570           1 :           clib_mem_set_heap (oldheap);
     571           1 :           current_traced_heap = 0;
     572             :         }
     573           2 :       clib_mem_trace (1);
     574             :       error =
     575           2 :         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
     576             :                                         parent_command_index);
     577           2 :       unformat_free (&sub_input);
     578             : 
     579             :       /* Otherwise, the clib_error_t shows up as a leak... */
     580           2 :       if (error)
     581             :         {
     582           1 :           vlib_cli_output (vm, "%v", error->what);
     583           1 :           clib_error_free (error);
     584           1 :           error = 0;
     585             :         }
     586             : 
     587           2 :       (void) clib_mem_trace_enable_disable (0);
     588           2 :       leak_report = format (0, "%U", format_clib_mem_heap, 0,
     589             :                             1 /* verbose, i.e. print leaks */ );
     590           2 :       clib_mem_trace (0);
     591           2 :       vlib_cli_output (vm, "%v", leak_report);
     592           2 :       vec_free (leak_report);
     593             :     }
     594             : 
     595             :   else
     596      555268 :     if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
     597             :     {
     598             :       unformat_input_t *si;
     599      535963 :       uword has_sub_commands =
     600      535963 :         vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
     601             : 
     602      535963 :       si = input;
     603      535963 :       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
     604          14 :         si = &sub_input;
     605             : 
     606      535963 :       if (has_sub_commands)
     607      293678 :         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
     608             : 
     609      535963 :       if (has_sub_commands && !error)
     610             :         /* Found valid sub-command. */ ;
     611             : 
     612      261632 :       else if (c->function)
     613             :         {
     614             :           clib_error_t *c_error;
     615             : 
     616             :           /* Skip white space for benefit of called function. */
     617      261583 :           unformat_skip_white_space (si);
     618             : 
     619      261583 :           if (unformat (si, "?"))
     620             :             {
     621           1 :               vlib_cli_output (vm, "  %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c,   /* is_long */
     622             :                                0);
     623             :             }
     624             :           else
     625             :             {
     626      261582 :               if (PREDICT_FALSE (vm->elog_trace_cli_commands))
     627             :                 {
     628             :                   /* *INDENT-OFF* */
     629             :                   ELOG_TYPE_DECLARE (e) =
     630             :                     {
     631             :                       .format = "cli-cmd: %s",
     632             :                       .format_args = "T4",
     633             :                     };
     634             :                   /* *INDENT-ON* */
     635             :                   struct
     636             :                   {
     637             :                     u32 c;
     638             :                   } *ed;
     639           3 :                   ed = ELOG_DATA (vlib_get_elog_main (), e);
     640           3 :                   ed->c = elog_string (vlib_get_elog_main (), "%v", c->path);
     641             :                 }
     642             : 
     643      261582 :               if (!c->is_mp_safe)
     644      255742 :                 vlib_worker_thread_barrier_sync (vm);
     645      261582 :               if (PREDICT_FALSE (vec_len (cm->perf_counter_cbs) != 0))
     646           0 :                 clib_call_callbacks (cm->perf_counter_cbs, cm,
     647             :                                      c - cm->commands, 0 /* before */ );
     648             : 
     649      261582 :               c->hit_counter++;
     650      261582 :               c_error = c->function (vm, si, c);
     651             : 
     652      261582 :               if (PREDICT_FALSE (vec_len (cm->perf_counter_cbs) != 0))
     653           0 :                 clib_call_callbacks (cm->perf_counter_cbs, cm,
     654             :                                      c - cm->commands, 1 /* after */ );
     655      261582 :               if (!c->is_mp_safe)
     656      255742 :                 vlib_worker_thread_barrier_release (vm);
     657             : 
     658      261582 :               if (PREDICT_FALSE (vm->elog_trace_cli_commands))
     659             :                 {
     660             :                   /* *INDENT-OFF* */
     661             :                   ELOG_TYPE_DECLARE (e) =
     662             :                     {
     663             :                       .format = "cli-cmd: %s %s",
     664             :                       .format_args = "T4T4",
     665             :                     };
     666             :                   /* *INDENT-ON* */
     667             :                   struct
     668             :                   {
     669             :                     u32 c, err;
     670             :                   } *ed;
     671           3 :                   ed = ELOG_DATA (vlib_get_elog_main (), e);
     672           3 :                   ed->c = elog_string (vlib_get_elog_main (), "%v", c->path);
     673           3 :                   if (c_error)
     674             :                     {
     675           1 :                       vec_add1 (c_error->what, 0);
     676           1 :                       ed->err = elog_string (vlib_get_elog_main (),
     677           1 :                                              (char *) c_error->what);
     678           1 :                       vec_dec_len (c_error->what, 1);
     679             :                     }
     680             :                   else
     681           2 :                     ed->err = elog_string (vlib_get_elog_main (), "OK");
     682             :                 }
     683             : 
     684      261582 :               if (c_error)
     685             :                 {
     686             :                   error =
     687          38 :                     clib_error_return (0, "%v: %v", c->path, c_error->what);
     688          38 :                   clib_error_free (c_error);
     689             :                   /* Free sub input. */
     690          38 :                   if (si != input)
     691           0 :                     unformat_free (si);
     692             : 
     693          38 :                   return error;
     694             :                 }
     695             :             }
     696             : 
     697             :           /* Free any previous error. */
     698      261545 :           clib_error_free (error);
     699             :         }
     700             : 
     701          49 :       else if (!error)
     702           0 :         error = clib_error_return (0, "%v: no sub-commands", c->path);
     703             : 
     704             :       /* Free sub input. */
     705      535925 :       if (si != input)
     706          14 :         unformat_free (si);
     707             :     }
     708             : 
     709             :   else
     710       19305 :     goto unknown;
     711             : 
     712      535931 :   return error;
     713             : 
     714       19305 : unknown:
     715       19305 :   if (parent->path)
     716       19301 :     return clib_error_return (0, "%v: unknown input `%U'", parent->path,
     717             :                               format_unformat_error, input);
     718             :   else
     719           4 :     return clib_error_return (0, "unknown input `%U'", format_unformat_error,
     720             :                               input);
     721             : }
     722             : 
     723             : 
     724             : void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
     725             :   __attribute__ ((weak));
     726             : 
     727             : void
     728           0 : vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
     729             : {
     730           0 : }
     731             : 
     732             : /* Process CLI input. */
     733             : int
     734      261590 : vlib_cli_input (vlib_main_t * vm,
     735             :                 unformat_input_t * input,
     736             :                 vlib_cli_output_function_t * function, uword function_arg)
     737             : {
     738      261590 :   vlib_global_main_t *vgm = vlib_get_global_main ();
     739      261590 :   vlib_process_t *cp = vlib_get_current_process (vm);
     740             :   clib_error_t *error;
     741             :   vlib_cli_output_function_t *save_function;
     742             :   uword save_function_arg;
     743      261590 :   int rv = 0;
     744             : 
     745      261590 :   save_function = cp->output_function;
     746      261590 :   save_function_arg = cp->output_function_arg;
     747             : 
     748      261590 :   cp->output_function = function;
     749      261590 :   cp->output_function_arg = function_arg;
     750             : 
     751             :   do
     752             :     {
     753      261593 :       error = vlib_cli_dispatch_sub_commands (vm, &vgm->cli_main, input,
     754             :                                               /* parent */ 0);
     755             :     }
     756      261593 :   while (!error && !unformat (input, "%U", unformat_eof));
     757             : 
     758      261590 :   if (error)
     759             :     {
     760          44 :       vlib_cli_output (vm, "%v", error->what);
     761          44 :       vlib_unix_error_report (vm, error);
     762             :       /* clib_error_return is unfortunately often called with a '0'
     763             :          return code */
     764          44 :       rv = error->code != 0 ? error->code : -1;
     765          44 :       clib_error_free (error);
     766             :     }
     767             : 
     768      261590 :   cp->output_function = save_function;
     769      261590 :   cp->output_function_arg = save_function_arg;
     770      261590 :   return rv;
     771             : }
     772             : 
     773             : /* Output to current CLI connection. */
     774             : void
     775      801967 : vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
     776             : {
     777      801967 :   vlib_process_t *cp = vlib_get_current_process (vm);
     778             :   va_list va;
     779             :   u8 *s;
     780             : 
     781      801967 :   va_start (va, fmt);
     782      801967 :   s = va_format (0, fmt, &va);
     783      801967 :   va_end (va);
     784             : 
     785             :   /* some format functions might return 0
     786             :    * e.g. show int addr */
     787      801967 :   if (NULL == s)
     788        3801 :     return;
     789             : 
     790             :   /* Terminate with \n if not present. */
     791      798166 :   if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
     792      680012 :     vec_add1 (s, '\n');
     793             : 
     794      798166 :   if ((!cp) || (!cp->output_function))
     795           3 :     fformat (stdout, "%v", s);
     796             :   else
     797      798163 :     cp->output_function (cp->output_function_arg, s, vec_len (s));
     798             : 
     799      798166 :   vec_free (s);
     800             : }
     801             : 
     802             : void *vl_msg_push_heap (void) __attribute__ ((weak));
     803             : void *
     804           0 : vl_msg_push_heap (void)
     805             : {
     806           0 :   return 0;
     807             : }
     808             : 
     809             : void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
     810             : void
     811           0 : vl_msg_pop_heap (void *oldheap)
     812             : {
     813           0 : }
     814             : 
     815             : static clib_error_t *
     816           4 : show_memory_usage (vlib_main_t * vm,
     817             :                    unformat_input_t * input, vlib_cli_command_t * cmd)
     818             : {
     819           4 :   clib_mem_main_t *mm = &clib_mem_main;
     820           4 :   int verbose __attribute__ ((unused)) = 0;
     821           4 :   int api_segment = 0, stats_segment = 0, main_heap = 0, numa_heaps = 0;
     822           4 :   int map = 0;
     823             :   clib_error_t *error;
     824           4 :   u32 index = 0;
     825             :   int i;
     826             :   uword clib_mem_trace_enable_disable (uword enable);
     827             :   uword was_enabled;
     828             : 
     829             : 
     830           9 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     831             :     {
     832           6 :       if (unformat (input, "verbose"))
     833           1 :         verbose = 1;
     834           5 :       else if (unformat (input, "api-segment"))
     835           1 :         api_segment = 1;
     836           4 :       else if (unformat (input, "stats-segment"))
     837           1 :         stats_segment = 1;
     838           3 :       else if (unformat (input, "main-heap"))
     839           2 :         main_heap = 1;
     840           1 :       else if (unformat (input, "numa-heaps"))
     841           0 :         numa_heaps = 1;
     842           1 :       else if (unformat (input, "map"))
     843           0 :         map = 1;
     844             :       else
     845             :         {
     846           1 :           error = clib_error_return (0, "unknown input `%U'",
     847             :                                      format_unformat_error, input);
     848           1 :           return error;
     849             :         }
     850             :     }
     851             : 
     852           3 :   if ((api_segment + stats_segment + main_heap + numa_heaps + map) == 0)
     853           1 :     return clib_error_return
     854             :       (0, "Need one of api-segment, stats-segment, main-heap, numa-heaps "
     855             :        "or map");
     856             : 
     857           2 :   if (api_segment)
     858             :     {
     859           1 :       void *oldheap = vl_msg_push_heap ();
     860           1 :       was_enabled = clib_mem_trace_enable_disable (0);
     861           1 :       u8 *s_in_svm = format (0, "%U\n", format_clib_mem_heap, 0, 1);
     862           1 :       vl_msg_pop_heap (oldheap);
     863           1 :       u8 *s = vec_dup (s_in_svm);
     864             : 
     865           1 :       oldheap = vl_msg_push_heap ();
     866           1 :       vec_free (s_in_svm);
     867           1 :       clib_mem_trace_enable_disable (was_enabled);
     868           1 :       vl_msg_pop_heap (oldheap);
     869           1 :       vlib_cli_output (vm, "API segment");
     870           1 :       vlib_cli_output (vm, "%v", s);
     871           1 :       vec_free (s);
     872             :     }
     873           2 :   if (stats_segment)
     874             :     {
     875           1 :       void *oldheap = vlib_stats_set_heap ();
     876           1 :       was_enabled = clib_mem_trace_enable_disable (0);
     877           1 :       u8 *s_in_svm = format (0, "%U\n", format_clib_mem_heap, 0, 1);
     878           1 :       if (oldheap)
     879           1 :         clib_mem_set_heap (oldheap);
     880           1 :       u8 *s = vec_dup (s_in_svm);
     881             : 
     882           1 :       oldheap = vlib_stats_set_heap ();
     883           1 :       vec_free (s_in_svm);
     884           1 :       if (oldheap)
     885             :         {
     886           1 :           clib_mem_trace_enable_disable (was_enabled);
     887           1 :           clib_mem_set_heap (oldheap);
     888             :         }
     889           1 :       vlib_cli_output (vm, "Stats segment");
     890           1 :       vlib_cli_output (vm, "%v", s);
     891           1 :       vec_free (s);
     892             :     }
     893             : 
     894             : 
     895             :   {
     896           2 :     if (main_heap)
     897             :       {
     898             :         /*
     899             :          * Note: the foreach_vlib_main causes allocator traffic,
     900             :          * so shut off tracing before we go there...
     901             :          */
     902           2 :         was_enabled = clib_mem_trace_enable_disable (0);
     903             : 
     904           6 :         foreach_vlib_main ()
     905             :           {
     906           4 :             vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n" : "", index,
     907           4 :                              vlib_worker_threads[index].name);
     908           4 :             vlib_cli_output (vm, "  %U\n", format_clib_mem_heap,
     909             :                              mm->per_cpu_mheaps[index], verbose);
     910           4 :             index++;
     911             :           }
     912             : 
     913             :         /* Restore the trace flag */
     914           2 :         clib_mem_trace_enable_disable (was_enabled);
     915             :       }
     916           2 :     if (numa_heaps)
     917             :       {
     918           0 :         for (i = 0; i < ARRAY_LEN (mm->per_numa_mheaps); i++)
     919             :           {
     920           0 :             if (mm->per_numa_mheaps[i] == 0)
     921           0 :               continue;
     922           0 :             if (mm->per_numa_mheaps[i] == mm->per_cpu_mheaps[i])
     923             :               {
     924           0 :                 vlib_cli_output (vm, "Numa %d uses the main heap...", i);
     925           0 :                 continue;
     926             :               }
     927           0 :             was_enabled = clib_mem_trace_enable_disable (0);
     928             : 
     929           0 :             vlib_cli_output (vm, "Numa %d:", i);
     930           0 :             vlib_cli_output (vm, "  %U\n", format_clib_mem_heap,
     931             :                              mm->per_numa_mheaps[index], verbose);
     932             :           }
     933             :       }
     934           2 :     if (map)
     935             :       {
     936           0 :         clib_mem_page_stats_t stats = { };
     937           0 :         clib_mem_vm_map_hdr_t *hdr = 0;
     938           0 :         u8 *s = 0;
     939           0 :         int numa = -1;
     940             : 
     941           0 :         s = format (s, "\n%-16s%7s%5s%7s%7s",
     942             :                     "StartAddr", "size", "FD", "PageSz", "Pages");
     943           0 :         while ((numa = vlib_mem_get_next_numa_node (numa)) != -1)
     944           0 :           s = format (s, " Numa%u", numa);
     945           0 :         s = format (s, " NotMap");
     946           0 :         s = format (s, " Name");
     947           0 :         vlib_cli_output (vm, "%v", s);
     948           0 :         vec_reset_length (s);
     949             : 
     950           0 :         while ((hdr = clib_mem_vm_get_next_map_hdr (hdr)))
     951             :           {
     952           0 :             clib_mem_get_page_stats ((void *) hdr->base_addr,
     953             :                                      hdr->log2_page_sz, hdr->num_pages,
     954             :                                      &stats);
     955           0 :             s = format (s, "%016lx%7U",
     956             :                         hdr->base_addr, format_memory_size,
     957           0 :                         hdr->num_pages << hdr->log2_page_sz);
     958             : 
     959           0 :             if (hdr->fd != -1)
     960           0 :               s = format (s, "%5d", hdr->fd);
     961             :             else
     962           0 :               s = format (s, "%5s", " ");
     963             : 
     964           0 :             s = format (s, "%7U%7lu",
     965           0 :                         format_log2_page_size, hdr->log2_page_sz,
     966             :                         hdr->num_pages);
     967           0 :             while ((numa = vlib_mem_get_next_numa_node (numa)) != -1)
     968           0 :               s = format (s, "%6lu", stats.per_numa[numa]);
     969           0 :             s = format (s, "%7lu", stats.not_mapped);
     970           0 :             s = format (s, " %s", hdr->name);
     971           0 :             vlib_cli_output (vm, "%v", s);
     972           0 :             vec_reset_length (s);
     973             :           }
     974           0 :         vec_free (s);
     975             :       }
     976             :   }
     977           2 :   return 0;
     978             : }
     979             : 
     980             : /* *INDENT-OFF* */
     981      285289 : VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
     982             :   .path = "show memory",
     983             :   .short_help = "show memory [api-segment][stats-segment][verbose]\n"
     984             :                 "            [numa-heaps][map][main-heap]",
     985             :   .function = show_memory_usage,
     986             : };
     987             : /* *INDENT-ON* */
     988             : 
     989             : static clib_error_t *
     990           1 : show_cpu (vlib_main_t * vm, unformat_input_t * input,
     991             :           vlib_cli_command_t * cmd)
     992             : {
     993             : #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
     994           1 :   _("Model name", "%U", format_cpu_model_name);
     995           1 :   _("Microarch model (family)", "%U", format_cpu_uarch);
     996           1 :   _("Flags", "%U", format_cpu_flags);
     997           1 :   _("Base frequency", "%.2f GHz",
     998             :     ((f64) vm->clib_time.clocks_per_second) * 1e-9);
     999             : #undef _
    1000           1 :   return 0;
    1001             : }
    1002             : 
    1003             : /*?
    1004             :  * Displays various information about the CPU.
    1005             :  *
    1006             :  * @cliexpar
    1007             :  * @cliexstart{show cpu}
    1008             :  * Model name:               Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
    1009             :  * Microarchitecture:        Broadwell (Broadwell-EP/EX)
    1010             :  * Flags:                    sse3 ssse3 sse41 sse42 avx avx2 aes
    1011             :  * Base Frequency:           3.20 GHz
    1012             :  * @cliexend
    1013             : ?*/
    1014             : /* *INDENT-OFF* */
    1015      285289 : VLIB_CLI_COMMAND (show_cpu_command, static) = {
    1016             :   .path = "show cpu",
    1017             :   .short_help = "Show cpu information",
    1018             :   .function = show_cpu,
    1019             : };
    1020             : /* *INDENT-ON* */
    1021             : 
    1022             : static clib_error_t *
    1023           3 : enable_disable_memory_trace (vlib_main_t * vm,
    1024             :                              unformat_input_t * input,
    1025             :                              vlib_cli_command_t * cmd)
    1026             : {
    1027           3 :   clib_mem_main_t *mm = &clib_mem_main;
    1028           3 :   unformat_input_t _line_input, *line_input = &_line_input;
    1029           3 :   int enable = 1;
    1030           3 :   int api_segment = 0;
    1031           3 :   int stats_segment = 0;
    1032           3 :   int main_heap = 0;
    1033           3 :   u32 numa_id = ~0;
    1034             :   void *oldheap;
    1035             : 
    1036           3 :   if (!unformat_user (input, unformat_line_input, line_input))
    1037           0 :     return 0;
    1038             : 
    1039           9 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1040             :     {
    1041           6 :       if (unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
    1042             :         ;
    1043           5 :       else if (unformat (line_input, "api-segment"))
    1044           1 :         api_segment = 1;
    1045           4 :       else if (unformat (line_input, "stats-segment"))
    1046           1 :         stats_segment = 1;
    1047           3 :       else if (unformat (line_input, "main-heap"))
    1048           3 :         main_heap = 1;
    1049           0 :       else if (unformat (line_input, "numa-heap %d", &numa_id))
    1050             :         ;
    1051             :       else
    1052             :         {
    1053           0 :           unformat_free (line_input);
    1054           0 :           return clib_error_return (0, "invalid input");
    1055             :         }
    1056             :     }
    1057           3 :   unformat_free (line_input);
    1058             : 
    1059           3 :   if ((api_segment + stats_segment + main_heap + (enable == 0)
    1060           3 :        + (numa_id != ~0)) == 0)
    1061             :     {
    1062           0 :       return clib_error_return
    1063             :         (0, "Need one of main-heap, stats-segment, api-segment,\n"
    1064             :          "numa-heap <nn> or disable");
    1065             :     }
    1066             : 
    1067             :   /* Turn off current trace, if any */
    1068           3 :   if (current_traced_heap)
    1069             :     {
    1070             :       void *oldheap;
    1071           1 :       oldheap = clib_mem_set_heap (current_traced_heap);
    1072           1 :       clib_mem_trace (0);
    1073           1 :       clib_mem_set_heap (oldheap);
    1074           1 :       current_traced_heap = 0;
    1075             :     }
    1076             : 
    1077           3 :   if (enable == 0)
    1078           1 :     return 0;
    1079             : 
    1080             :   /* API segment */
    1081           2 :   if (api_segment)
    1082             :     {
    1083           1 :       oldheap = vl_msg_push_heap ();
    1084           1 :       current_traced_heap = clib_mem_get_heap ();
    1085           1 :       clib_mem_trace (1);
    1086           1 :       vl_msg_pop_heap (oldheap);
    1087             : 
    1088             :     }
    1089             : 
    1090             :   /* Stats segment */
    1091           2 :   if (stats_segment)
    1092             :     {
    1093           1 :       oldheap = vlib_stats_set_heap ();
    1094           1 :       current_traced_heap = clib_mem_get_heap ();
    1095           1 :       clib_mem_trace (stats_segment);
    1096             :       /* We don't want to call vlib_stats_pop_heap... */
    1097           1 :       if (oldheap)
    1098           1 :         clib_mem_set_heap (oldheap);
    1099             :     }
    1100             : 
    1101             :   /* main_heap */
    1102           2 :   if (main_heap)
    1103             :     {
    1104           2 :       current_traced_heap = clib_mem_get_heap ();
    1105           2 :       clib_mem_trace (main_heap);
    1106             :     }
    1107             : 
    1108           2 :   if (numa_id != ~0)
    1109             :     {
    1110           0 :       if (numa_id >= ARRAY_LEN (mm->per_numa_mheaps))
    1111           0 :         return clib_error_return (0, "Numa %d out of range", numa_id);
    1112           0 :       if (mm->per_numa_mheaps[numa_id] == 0)
    1113           0 :         return clib_error_return (0, "Numa %d heap not active", numa_id);
    1114             : 
    1115           0 :       if (mm->per_numa_mheaps[numa_id] == clib_mem_get_heap ())
    1116           0 :         return clib_error_return (0, "Numa %d uses the main heap...",
    1117             :                                   numa_id);
    1118           0 :       current_traced_heap = mm->per_numa_mheaps[numa_id];
    1119           0 :       oldheap = clib_mem_set_heap (current_traced_heap);
    1120           0 :       clib_mem_trace (1);
    1121           0 :       clib_mem_set_heap (oldheap);
    1122             :     }
    1123             : 
    1124             : 
    1125           2 :   return 0;
    1126             : }
    1127             : 
    1128             : /* *INDENT-OFF* */
    1129      285289 : VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
    1130             :   .path = "memory-trace",
    1131             :   .short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n"
    1132             :   "                   [numa-heap <numa-id>]\n",
    1133             :   .function = enable_disable_memory_trace,
    1134             : };
    1135             : /* *INDENT-ON* */
    1136             : 
    1137             : static clib_error_t *
    1138           0 : restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
    1139             :                 vlib_cli_command_t * cmd)
    1140             : {
    1141           0 :   vlib_global_main_t *vgm = vlib_get_global_main ();
    1142           0 :   clib_file_main_t *fm = &file_main;
    1143             :   clib_file_t *f;
    1144             : 
    1145             :   /* environ(7) does not indicate a header for this */
    1146             :   extern char **environ;
    1147             : 
    1148             :   /* Close all known open files */
    1149             :   /* *INDENT-OFF* */
    1150           0 :   pool_foreach (f, fm->file_pool)
    1151             :      {
    1152           0 :       if (f->file_descriptor > 2)
    1153           0 :         close(f->file_descriptor);
    1154             :     }
    1155             :   /* *INDENT-ON* */
    1156             : 
    1157             :   /* Exec ourself */
    1158           0 :   execve (vgm->name, (char **) vgm->argv, environ);
    1159             : 
    1160           0 :   return 0;
    1161             : }
    1162             : 
    1163             : /* *INDENT-OFF* */
    1164      285289 : VLIB_CLI_COMMAND (restart_cmd,static) = {
    1165             :     .path = "restart",
    1166             :     .short_help = "restart process",
    1167             :     .function = restart_cmd_fn,
    1168             : };
    1169             : /* *INDENT-ON* */
    1170             : 
    1171             : #ifdef TEST_CODE
    1172             : /*
    1173             :  * A trivial test harness to verify the per-process output_function
    1174             :  * is working correcty.
    1175             :  */
    1176             : 
    1177             : static clib_error_t *
    1178             : sleep_ten_seconds (vlib_main_t * vm,
    1179             :                    unformat_input_t * input, vlib_cli_command_t * cmd)
    1180             : {
    1181             :   u16 i;
    1182             :   u16 my_id = rand ();
    1183             : 
    1184             :   vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
    1185             : 
    1186             :   for (i = 0; i < 10; i++)
    1187             :     {
    1188             :       vlib_process_wait_for_event_or_clock (vm, 1.0);
    1189             :       vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
    1190             :     }
    1191             :   vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
    1192             :   return 0;
    1193             : }
    1194             : 
    1195             : /* *INDENT-OFF* */
    1196             : VLIB_CLI_COMMAND (ping_command, static) = {
    1197             :   .path = "test sleep",
    1198             :   .function = sleep_ten_seconds,
    1199             :   .short_help = "Sleep for 10 seconds",
    1200             : };
    1201             : /* *INDENT-ON* */
    1202             : #endif /* ifdef TEST_CODE */
    1203             : 
    1204             : static uword
    1205      553320 : vlib_cli_normalize_path (char *input, char **result)
    1206             : {
    1207      553320 :   char *i = input;
    1208      553320 :   char *s = 0;
    1209      553320 :   uword l = 0;
    1210      553320 :   uword index_of_last_space = ~0;
    1211             : 
    1212    10313500 :   while (*i != 0)
    1213             :     {
    1214     9760130 :       u8 c = *i++;
    1215             :       /* Multiple white space -> single space. */
    1216     9760130 :       switch (c)
    1217             :         {
    1218     1012350 :         case ' ':
    1219             :         case '\t':
    1220             :         case '\n':
    1221             :         case '\r':
    1222     1012350 :           if (l > 0 && s[l - 1] != ' ')
    1223             :             {
    1224     1012350 :               vec_add1 (s, ' ');
    1225     1012350 :               l++;
    1226             :             }
    1227     1012350 :           break;
    1228             : 
    1229     8747780 :         default:
    1230     8747780 :           if (l > 0 && s[l - 1] == ' ')
    1231     1010620 :             index_of_last_space = vec_len (s);
    1232     8747780 :           vec_add1 (s, c);
    1233     8747780 :           l++;
    1234     8747780 :           break;
    1235             :         }
    1236             :     }
    1237             : 
    1238             :   /* Remove any extra space at end. */
    1239      553320 :   if (l > 0 && s[l - 1] == ' ')
    1240        1725 :     vec_dec_len (s, 1);
    1241             : 
    1242      553320 :   *result = s;
    1243      553320 :   return index_of_last_space;
    1244             : }
    1245             : 
    1246             : always_inline uword
    1247     1593400 : parent_path_len (char *path)
    1248             : {
    1249             :   word i;
    1250    12203700 :   for (i = vec_len (path) - 1; i >= 0; i--)
    1251             :     {
    1252    12087500 :       if (path[i] == ' ')
    1253     1477190 :         return i;
    1254             :     }
    1255      116204 :   return ~0;
    1256             : }
    1257             : 
    1258             : static void
    1259      796699 : add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
    1260             : {
    1261             :   vlib_cli_command_t *p, *c;
    1262             :   vlib_cli_sub_command_t *sub_c;
    1263             :   u8 *sub_name;
    1264             :   word i, l;
    1265             : 
    1266      796699 :   p = vec_elt_at_index (cm->commands, parent_index);
    1267      796699 :   c = vec_elt_at_index (cm->commands, child_index);
    1268             : 
    1269      796699 :   l = parent_path_len (c->path);
    1270      796699 :   if (l == ~0)
    1271       58102 :     sub_name = vec_dup ((u8 *) c->path);
    1272             :   else
    1273             :     {
    1274      738597 :       ASSERT (l + 1 < vec_len (c->path));
    1275      738597 :       sub_name = 0;
    1276      738597 :       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
    1277             :     }
    1278             : 
    1279             :   /* "Can't happen," check mainly to shut up coverity */
    1280      796699 :   ALWAYS_ASSERT (sub_name != 0);
    1281             : 
    1282      796699 :   if (sub_name[0] == '%')
    1283             :     {
    1284             :       uword *q;
    1285             :       vlib_cli_sub_rule_t *sr;
    1286             : 
    1287             :       /* Remove %. */
    1288           0 :       vec_delete (sub_name, 1, 0);
    1289             : 
    1290           0 :       if (!p->sub_rule_index_by_name)
    1291           0 :         p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
    1292             :                                                      sizeof (sub_name[0]),
    1293             :                                                      sizeof (uword));
    1294           0 :       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
    1295           0 :       if (q)
    1296             :         {
    1297           0 :           sr = vec_elt_at_index (p->sub_rules, q[0]);
    1298           0 :           ASSERT (sr->command_index == child_index);
    1299           0 :           return;
    1300             :         }
    1301             : 
    1302           0 :       hash_set_mem (p->sub_rule_index_by_name, sub_name,
    1303             :                     vec_len (p->sub_rules));
    1304           0 :       vec_add2 (p->sub_rules, sr, 1);
    1305           0 :       sr->name = sub_name;
    1306           0 :       sr->rule_index = sr - p->sub_rules;
    1307           0 :       sr->command_index = child_index;
    1308           0 :       return;
    1309             :     }
    1310             : 
    1311      796699 :   if (!p->sub_command_index_by_name)
    1312      249706 :     p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
    1313             :                                                     sizeof (c->path[0]),
    1314             :                                                     sizeof (uword));
    1315             : 
    1316             :   /* Check if sub-command has already been created. */
    1317     1593400 :   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
    1318             :     {
    1319       23025 :       vec_free (sub_name);
    1320       23025 :       return;
    1321             :     }
    1322             : 
    1323      773674 :   vec_add2 (p->sub_commands, sub_c, 1);
    1324      773674 :   sub_c->index = child_index;
    1325      773674 :   sub_c->name = sub_name;
    1326     1547350 :   hash_set_mem (p->sub_command_index_by_name, sub_c->name,
    1327             :                 sub_c - p->sub_commands);
    1328             : 
    1329      773674 :   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
    1330     5925190 :   for (i = 0; i < vec_len (sub_c->name); i++)
    1331             :     {
    1332             :       int n;
    1333             :       vlib_cli_parse_position_t *pos;
    1334             : 
    1335     5151520 :       pos = vec_elt_at_index (p->sub_command_positions, i);
    1336             : 
    1337     5151520 :       if (!pos->bitmaps)
    1338     2010850 :         pos->min_char = sub_c->name[i];
    1339             : 
    1340     5151520 :       n = sub_c->name[i] - pos->min_char;
    1341     5151520 :       if (n < 0)
    1342             :         {
    1343      649897 :           pos->min_char = sub_c->name[i];
    1344      649897 :           vec_insert (pos->bitmaps, -n, 0);
    1345      649897 :           n = 0;
    1346             :         }
    1347             : 
    1348     5151520 :       vec_validate (pos->bitmaps, n);
    1349     5151520 :       pos->bitmaps[n] =
    1350     5151520 :         clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
    1351             :     }
    1352             : }
    1353             : 
    1354             : static void
    1355      796699 : vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
    1356             : {
    1357             :   uword p_len, pi, *p;
    1358             :   char *p_path;
    1359             :   vlib_cli_command_t *c, *parent;
    1360             : 
    1361             :   /* Root command (index 0) should have already been added. */
    1362      796699 :   ASSERT (vec_len (cm->commands) > 0);
    1363             : 
    1364      796699 :   c = vec_elt_at_index (cm->commands, ci);
    1365      796699 :   p_len = parent_path_len (c->path);
    1366             : 
    1367             :   /* No space?  Parent is root command. */
    1368      796699 :   if (p_len == ~0)
    1369             :     {
    1370       58102 :       add_sub_command (cm, 0, ci);
    1371       58102 :       return;
    1372             :     }
    1373             : 
    1374      738597 :   p_path = 0;
    1375      738597 :   vec_add (p_path, c->path, p_len);
    1376             : 
    1377     1477190 :   p = hash_get_mem (cm->command_index_by_path, p_path);
    1378             : 
    1379             :   /* Parent exists? */
    1380      738597 :   if (!p)
    1381             :     {
    1382             :       /* Parent does not exist; create it. */
    1383      243379 :       vec_add2 (cm->commands, parent, 1);
    1384      243379 :       parent->path = p_path;
    1385      486758 :       hash_set_mem (cm->command_index_by_path, parent->path,
    1386             :                     parent - cm->commands);
    1387      243379 :       pi = parent - cm->commands;
    1388             :     }
    1389             :   else
    1390             :     {
    1391      495218 :       pi = p[0];
    1392      495218 :       vec_free (p_path);
    1393             :     }
    1394             : 
    1395      738597 :   add_sub_command (cm, pi, ci);
    1396             : 
    1397             :   /* Create parent's parent. */
    1398      738597 :   if (!p)
    1399      243379 :     vlib_cli_make_parent (cm, pi);
    1400             : }
    1401             : 
    1402             : always_inline uword
    1403       46050 : vlib_cli_command_is_empty (vlib_cli_command_t * c)
    1404             : {
    1405       46050 :   return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
    1406             : }
    1407             : 
    1408             : clib_error_t *
    1409      553320 : vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
    1410             : {
    1411      553320 :   vlib_global_main_t *vgm = vlib_get_global_main ();
    1412      553320 :   vlib_cli_main_t *cm = &vgm->cli_main;
    1413      553320 :   clib_error_t *error = 0;
    1414             :   uword ci, *p;
    1415             :   char *normalized_path;
    1416             : 
    1417      553320 :   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
    1418           0 :     return error;
    1419             : 
    1420      553320 :   (void) vlib_cli_normalize_path (c->path, &normalized_path);
    1421             : 
    1422      553320 :   if (!cm->command_index_by_path)
    1423         575 :     cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
    1424             :                                                  sizeof (c->path[0]),
    1425             :                                                  sizeof (uword));
    1426             : 
    1427             :   /* See if command already exists with given path. */
    1428     1106640 :   p = hash_get_mem (cm->command_index_by_path, normalized_path);
    1429      553320 :   if (p)
    1430             :     {
    1431             :       vlib_cli_command_t *d;
    1432             : 
    1433       23025 :       ci = p[0];
    1434       23025 :       d = vec_elt_at_index (cm->commands, ci);
    1435             : 
    1436             :       /* If existing command was created via vlib_cli_make_parent
    1437             :          replaced it with callers data. */
    1438       23025 :       if (vlib_cli_command_is_empty (d))
    1439             :         {
    1440       23025 :           vlib_cli_command_t save = d[0];
    1441             : 
    1442       23025 :           ASSERT (!vlib_cli_command_is_empty (c));
    1443             : 
    1444             :           /* Copy callers fields. */
    1445       23025 :           d[0] = c[0];
    1446             : 
    1447             :           /* Save internal fields. */
    1448       23025 :           d->path = save.path;
    1449       23025 :           d->sub_commands = save.sub_commands;
    1450       23025 :           d->sub_command_index_by_name = save.sub_command_index_by_name;
    1451       23025 :           d->sub_command_positions = save.sub_command_positions;
    1452       23025 :           d->sub_rules = save.sub_rules;
    1453             :         }
    1454             :       else
    1455             :         error =
    1456           0 :           clib_error_return (0, "duplicate command name with path %v",
    1457             :                              normalized_path);
    1458             : 
    1459       23025 :       vec_free (normalized_path);
    1460       23025 :       if (error)
    1461           0 :         return error;
    1462             :     }
    1463             :   else
    1464             :     {
    1465             :       /* Command does not exist: create it. */
    1466             : 
    1467             :       /* Add root command (index 0). */
    1468      530295 :       if (vec_len (cm->commands) == 0)
    1469             :         {
    1470             :           /* Create command with index 0; path is empty string. */
    1471         575 :           vec_resize (cm->commands, 1);
    1472             :         }
    1473             : 
    1474      530295 :       ci = vec_len (cm->commands);
    1475     1060590 :       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
    1476      530295 :       vec_add1 (cm->commands, c[0]);
    1477             : 
    1478      530295 :       c = vec_elt_at_index (cm->commands, ci);
    1479      530295 :       c->path = normalized_path;
    1480             : 
    1481             :       /* Don't inherit from registration. */
    1482      530295 :       c->sub_commands = 0;
    1483      530295 :       c->sub_command_index_by_name = 0;
    1484      530295 :       c->sub_command_positions = 0;
    1485             :     }
    1486             : 
    1487      553320 :   vlib_cli_make_parent (cm, ci);
    1488      553320 :   return 0;
    1489             : }
    1490             : 
    1491             : #if 0
    1492             : /* $$$ turn back on again someday, maybe */
    1493             : clib_error_t *
    1494             : vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
    1495             : {
    1496             :   vlib_cli_main_t *cm = &vm->cli_main;
    1497             :   vlib_cli_parse_rule_t *r;
    1498             :   clib_error_t *error = 0;
    1499             :   u8 *r_name;
    1500             :   uword *p;
    1501             : 
    1502             :   if (!cm->parse_rule_index_by_name)
    1503             :     cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
    1504             :                                                     sizeof (r->name[0]),
    1505             :                                                     sizeof (uword));
    1506             : 
    1507             :   /* Make vector copy of name. */
    1508             :   r_name = format (0, "%s", r_reg->name);
    1509             : 
    1510             :   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
    1511             :     {
    1512             :       vec_free (r_name);
    1513             :       return clib_error_return (0, "duplicate parse rule name `%s'",
    1514             :                                 r_reg->name);
    1515             :     }
    1516             : 
    1517             :   vec_add2 (cm->parse_rules, r, 1);
    1518             :   r[0] = r_reg[0];
    1519             :   r->name = (char *) r_name;
    1520             :   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
    1521             : 
    1522             :   return error;
    1523             : }
    1524             : 
    1525             : static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
    1526             :                                                     vlib_cli_parse_rule_t *
    1527             :                                                     lo,
    1528             :                                                     vlib_cli_parse_rule_t *
    1529             :                                                     hi)
    1530             :   __attribute__ ((unused))
    1531             : {
    1532             :   clib_error_t *error = 0;
    1533             :   vlib_cli_parse_rule_t *r;
    1534             : 
    1535             :   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
    1536             :     {
    1537             :       if (!r->name || strlen (r->name) == 0)
    1538             :         {
    1539             :           error = clib_error_return (0, "parse rule with no name");
    1540             :           goto done;
    1541             :         }
    1542             : 
    1543             :       error = vlib_cli_register_parse_rule (vm, r);
    1544             :       if (error)
    1545             :         goto done;
    1546             :     }
    1547             : 
    1548             : done:
    1549             :   return error;
    1550             : }
    1551             : #endif
    1552             : 
    1553             : static clib_error_t *
    1554           6 : event_logger_trace_command_fn (vlib_main_t * vm,
    1555             :                                unformat_input_t * input,
    1556             :                                vlib_cli_command_t * cmd)
    1557             : {
    1558           6 :   unformat_input_t _line_input, *line_input = &_line_input;
    1559           6 :   int enable = 1;
    1560           6 :   int api = 0, cli = 0, barrier = 0, dispatch = 0, circuit = 0;
    1561             :   u32 circuit_node_index;
    1562             : 
    1563           6 :   if (!unformat_user (input, unformat_line_input, line_input))
    1564           1 :     goto print_status;
    1565             : 
    1566          16 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1567             :     {
    1568          11 :       if (unformat (line_input, "api"))
    1569           2 :         api = 1;
    1570           9 :       else if (unformat (line_input, "dispatch"))
    1571           0 :         dispatch = 1;
    1572           9 :       else if (unformat (line_input, "circuit-node %U",
    1573             :                          unformat_vlib_node, vm, &circuit_node_index))
    1574           2 :         circuit = 1;
    1575           7 :       else if (unformat (line_input, "cli"))
    1576           2 :         cli = 1;
    1577           5 :       else if (unformat (line_input, "barrier"))
    1578           2 :         barrier = 1;
    1579           3 :       else if (unformat (line_input, "disable"))
    1580           2 :         enable = 0;
    1581           1 :       else if (unformat (line_input, "enable"))
    1582           1 :         enable = 1;
    1583             :       else
    1584           0 :         break;
    1585             :     }
    1586           5 :   unformat_free (line_input);
    1587             : 
    1588           8 :   vl_api_set_elog_trace_api_messages
    1589           3 :     (api ? enable : vl_api_get_elog_trace_api_messages ());
    1590           5 :   vm->elog_trace_cli_commands = cli ? enable : vm->elog_trace_cli_commands;
    1591           5 :   vm->elog_trace_graph_dispatch = dispatch ?
    1592           5 :     enable : vm->elog_trace_graph_dispatch;
    1593           5 :   vm->elog_trace_graph_circuit = circuit ?
    1594           5 :     enable : vm->elog_trace_graph_circuit;
    1595           5 :   vlib_worker_threads->barrier_elog_enabled =
    1596           3 :     barrier ? enable : vlib_worker_threads->barrier_elog_enabled;
    1597           5 :   vm->elog_trace_graph_circuit_node_index = circuit_node_index;
    1598             : 
    1599             :   /*
    1600             :    * Set up start-of-buffer logic-analyzer trigger
    1601             :    * for main loop event logs, which are fairly heavyweight.
    1602             :    * See src/vlib/main/vlib_elog_main_loop_event(...), which
    1603             :    * will fully disable the scheme when the elog buffer fills.
    1604             :    */
    1605           5 :   if (dispatch || circuit)
    1606             :     {
    1607           2 :       elog_main_t *em = &vlib_global_main.elog_main;
    1608             : 
    1609           2 :       em->n_total_events_disable_limit =
    1610           2 :         em->n_total_events + vec_len (em->event_ring);
    1611             :     }
    1612             : 
    1613             : 
    1614           3 : print_status:
    1615           6 :   vlib_cli_output (vm, "Current status:");
    1616             : 
    1617          12 :   vlib_cli_output
    1618             :     (vm, "    Event log API message trace: %s\n    CLI command trace: %s",
    1619           6 :      vl_api_get_elog_trace_api_messages ()? "on" : "off",
    1620           6 :      vm->elog_trace_cli_commands ? "on" : "off");
    1621           6 :   vlib_cli_output
    1622             :     (vm, "    Barrier sync trace: %s",
    1623           6 :      vlib_worker_threads->barrier_elog_enabled ? "on" : "off");
    1624           6 :   vlib_cli_output
    1625             :     (vm, "    Graph Dispatch: %s",
    1626           6 :      vm->elog_trace_graph_dispatch ? "on" : "off");
    1627           6 :   vlib_cli_output
    1628             :     (vm, "    Graph Circuit: %s",
    1629           6 :      vm->elog_trace_graph_circuit ? "on" : "off");
    1630           6 :   if (vm->elog_trace_graph_circuit)
    1631           1 :     vlib_cli_output
    1632             :       (vm, "                   node %U",
    1633             :        format_vlib_node_name, vm, vm->elog_trace_graph_circuit_node_index);
    1634             : 
    1635           6 :   return 0;
    1636             : }
    1637             : 
    1638             : /*?
    1639             :  * Control event logging of api, cli, and thread barrier events
    1640             :  * With no arguments, displays the current trace status.
    1641             :  * Name the event groups you wish to trace or stop tracing.
    1642             :  *
    1643             :  * @cliexpar
    1644             :  * @clistart
    1645             :  * event-logger trace api cli barrier
    1646             :  * event-logger trace api cli barrier disable
    1647             :  * event-logger trace dispatch
    1648             :  * event-logger trace circuit-node ethernet-input
    1649             :  * @cliend
    1650             :  * @cliexcmd{event-logger trace [api][cli][barrier][disable]}
    1651             : ?*/
    1652             : /* *INDENT-OFF* */
    1653      285289 : VLIB_CLI_COMMAND (event_logger_trace_command, static) =
    1654             : {
    1655             :   .path = "event-logger trace",
    1656             :   .short_help = "event-logger trace [api][cli][barrier][dispatch]\n"
    1657             :   "[circuit-node <name> e.g. ethernet-input][disable]",
    1658             :   .function = event_logger_trace_command_fn,
    1659             : };
    1660             : /* *INDENT-ON* */
    1661             : 
    1662             : static clib_error_t *
    1663           0 : suspend_command_fn (vlib_main_t * vm,
    1664             :                     unformat_input_t * input, vlib_cli_command_t * cmd)
    1665             : {
    1666           0 :   vlib_process_suspend (vm, 30e-3);
    1667           0 :   return 0;
    1668             : }
    1669             : 
    1670             : /* *INDENT-OFF* */
    1671      285289 : VLIB_CLI_COMMAND (suspend_command, static) =
    1672             : {
    1673             :   .path = "suspend",
    1674             :   .short_help = "suspend debug CLI for 30ms",
    1675             :   .function = suspend_command_fn,
    1676             :   .is_mp_safe = 1,
    1677             : };
    1678             : /* *INDENT-ON* */
    1679             : 
    1680             : 
    1681             : static int
    1682           0 : sort_cmds_by_path (void *a1, void *a2)
    1683             : {
    1684           0 :   u32 *index1 = a1;
    1685           0 :   u32 *index2 = a2;
    1686           0 :   vlib_global_main_t *vgm = vlib_get_global_main ();
    1687           0 :   vlib_cli_main_t *cm = &vgm->cli_main;
    1688             :   vlib_cli_command_t *c1, *c2;
    1689             :   int i, lmin;
    1690             : 
    1691           0 :   c1 = vec_elt_at_index (cm->commands, *index1);
    1692           0 :   c2 = vec_elt_at_index (cm->commands, *index2);
    1693             : 
    1694           0 :   lmin = vec_len (c1->path);
    1695           0 :   lmin = (vec_len (c2->path) >= lmin) ? lmin : vec_len (c2->path);
    1696             : 
    1697           0 :   for (i = 0; i < lmin; i++)
    1698             :     {
    1699           0 :       if (c1->path[i] < c2->path[i])
    1700           0 :         return -1;
    1701           0 :       else if (c1->path[i] > c2->path[i])
    1702           0 :         return 1;
    1703             :     }
    1704             : 
    1705           0 :   return 0;
    1706             : }
    1707             : 
    1708             : typedef struct
    1709             : {
    1710             :   vlib_cli_main_t *cm;
    1711             :   u32 parent_command_index;
    1712             :   int show_mp_safe;
    1713             :   int show_not_mp_safe;
    1714             :   int show_hit;
    1715             :   int clear_hit;
    1716             : } vlib_cli_walk_args_t;
    1717             : 
    1718             : static void
    1719           0 : cli_recursive_walk (vlib_cli_walk_args_t * aa)
    1720             : {
    1721             :   vlib_cli_command_t *parent;
    1722             :   vlib_cli_sub_command_t *sub;
    1723           0 :   vlib_cli_walk_args_t _a, *a = &_a;
    1724             :   vlib_cli_main_t *cm;
    1725             :   int i;
    1726             : 
    1727             :   /* Copy args into this stack frame */
    1728           0 :   *a = *aa;
    1729           0 :   cm = a->cm;
    1730             : 
    1731           0 :   parent = vec_elt_at_index (cm->commands, a->parent_command_index);
    1732             : 
    1733           0 :   if (parent->function)
    1734             :     {
    1735           0 :       if (((a->show_mp_safe && parent->is_mp_safe)
    1736           0 :            || (a->show_not_mp_safe && !parent->is_mp_safe))
    1737           0 :           && (a->show_hit == 0 || parent->hit_counter))
    1738             :         {
    1739           0 :           vec_add1 (cm->sort_vector, a->parent_command_index);
    1740             :         }
    1741             : 
    1742           0 :       if (a->clear_hit)
    1743           0 :         parent->hit_counter = 0;
    1744             :     }
    1745             : 
    1746           0 :   for (i = 0; i < vec_len (parent->sub_commands); i++)
    1747             :     {
    1748           0 :       sub = vec_elt_at_index (parent->sub_commands, i);
    1749           0 :       a->parent_command_index = sub->index;
    1750           0 :       cli_recursive_walk (a);
    1751             :     }
    1752           0 : }
    1753             : 
    1754             : static u8 *
    1755           0 : format_mp_safe (u8 * s, va_list * args)
    1756             : {
    1757           0 :   vlib_cli_main_t *cm = va_arg (*args, vlib_cli_main_t *);
    1758           0 :   int show_mp_safe = va_arg (*args, int);
    1759           0 :   int show_not_mp_safe = va_arg (*args, int);
    1760           0 :   int show_hit = va_arg (*args, int);
    1761           0 :   int clear_hit = va_arg (*args, int);
    1762             :   vlib_cli_command_t *c;
    1763           0 :   vlib_cli_walk_args_t _a, *a = &_a;
    1764             :   int i;
    1765           0 :   char *format_string = "\n%v";
    1766             : 
    1767           0 :   if (show_hit)
    1768           0 :     format_string = "\n%v: %u";
    1769             : 
    1770           0 :   vec_reset_length (cm->sort_vector);
    1771             : 
    1772           0 :   a->cm = cm;
    1773           0 :   a->parent_command_index = 0;
    1774           0 :   a->show_mp_safe = show_mp_safe;
    1775           0 :   a->show_not_mp_safe = show_not_mp_safe;
    1776           0 :   a->show_hit = show_hit;
    1777           0 :   a->clear_hit = clear_hit;
    1778             : 
    1779           0 :   cli_recursive_walk (a);
    1780             : 
    1781           0 :   vec_sort_with_function (cm->sort_vector, sort_cmds_by_path);
    1782             : 
    1783           0 :   for (i = 0; i < vec_len (cm->sort_vector); i++)
    1784             :     {
    1785           0 :       c = vec_elt_at_index (cm->commands, cm->sort_vector[i]);
    1786           0 :       s = format (s, format_string, c->path, c->hit_counter);
    1787             :     }
    1788             : 
    1789           0 :   return s;
    1790             : }
    1791             : 
    1792             : 
    1793             : static clib_error_t *
    1794           0 : show_cli_command_fn (vlib_main_t * vm,
    1795             :                      unformat_input_t * input, vlib_cli_command_t * cmd)
    1796             : {
    1797           0 :   vlib_global_main_t *vgm = vlib_get_global_main ();
    1798           0 :   int show_mp_safe = 0;
    1799           0 :   int show_not_mp_safe = 0;
    1800           0 :   int show_hit = 0;
    1801           0 :   int clear_hit = 0;
    1802             : 
    1803           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1804             :     {
    1805           0 :       if (unformat (input, "mp-safe"))
    1806           0 :         show_mp_safe = 1;
    1807           0 :       if (unformat (input, "not-mp-safe"))
    1808           0 :         show_not_mp_safe = 1;
    1809           0 :       else if (unformat (input, "hit"))
    1810           0 :         show_hit = 1;
    1811           0 :       else if (unformat (input, "clear-hit"))
    1812           0 :         clear_hit = 1;
    1813             :       else
    1814           0 :         break;
    1815             :     }
    1816             : 
    1817             :   /* default set: all cli commands */
    1818           0 :   if (clear_hit == 0 && (show_mp_safe + show_not_mp_safe) == 0)
    1819           0 :     show_mp_safe = show_not_mp_safe = 1;
    1820             : 
    1821           0 :   vlib_cli_output (vm, "%U", format_mp_safe, &vgm->cli_main, show_mp_safe,
    1822             :                    show_not_mp_safe, show_hit, clear_hit);
    1823           0 :   if (clear_hit)
    1824           0 :     vlib_cli_output (vm, "hit counters cleared...");
    1825             : 
    1826           0 :   return 0;
    1827             : }
    1828             : 
    1829             : /*?
    1830             :  * Displays debug cli command information
    1831             :  *
    1832             :  * @cliexpar
    1833             :  * @cliexstart{show cli [mp-safe][not-mp-safe][hit][clear-hit]}
    1834             :  *
    1835             :  * "show cli" displays the entire debug cli:
    1836             :  *
    1837             :  * abf attach
    1838             :  * abf policy
    1839             :  * adjacency counters
    1840             :  * api trace
    1841             :  * app ns
    1842             :  * bfd key del
    1843             :  * ... and so on ...
    1844             :  *
    1845             :  * "show cli mp-safe" displays mp-safe debug CLI commands:
    1846             :  *
    1847             :  * abf policy
    1848             :  * binary-api
    1849             :  * create vhost-user
    1850             :  * exec
    1851             :  * ip container
    1852             :  * ip mroute
    1853             :  * ip probe-neighbor
    1854             :  * ip route
    1855             :  * ip scan-neighbor
    1856             :  * ip table
    1857             :  * ip6 table
    1858             :  *
    1859             :  * "show cli not-mp-safe" displays debug CLI commands
    1860             :  * which cause worker thread barrier synchronization
    1861             :  *
    1862             :  * "show cli hit" displays commands which have been executed. Qualify
    1863             :  * as desired with "mp-safe" or "not-mp-safe".
    1864             :  *
    1865             :  * "show cli clear-hit" clears the per-command hit counters.
    1866             :  * @cliexend
    1867             : ?*/
    1868             : 
    1869             : /* *INDENT-OFF* */
    1870      285289 : VLIB_CLI_COMMAND (show_cli_command, static) =
    1871             : {
    1872             :   .path = "show cli",
    1873             :   .short_help = "show cli [mp-safe][not-mp-safe][hit][clear-hit]",
    1874             :   .function = show_cli_command_fn,
    1875             :   .is_mp_safe = 1,
    1876             : };
    1877             : /* *INDENT-ON* */
    1878             : 
    1879             : static clib_error_t *
    1880         575 : vlib_cli_init (vlib_main_t * vm)
    1881             : {
    1882         575 :   vlib_global_main_t *vgm = vlib_get_global_main ();
    1883         575 :   vlib_cli_main_t *cm = &vgm->cli_main;
    1884         575 :   clib_error_t *error = 0;
    1885             :   vlib_cli_command_t *cmd;
    1886             : 
    1887         575 :   cmd = cm->cli_command_registrations;
    1888             : 
    1889      553895 :   while (cmd)
    1890             :     {
    1891      553320 :       error = vlib_cli_register (vm, cmd);
    1892      553320 :       if (error)
    1893           0 :         return error;
    1894      553320 :       cmd = cmd->next_cli_command;
    1895             :     }
    1896             : 
    1897         575 :   cm->log = vlib_log_register_class_rate_limit (
    1898             :     "cli", "log", 0x7FFFFFFF /* aka no rate limit */);
    1899         575 :   return error;
    1900             : }
    1901             : 
    1902        1151 : VLIB_INIT_FUNCTION (vlib_cli_init);
    1903             : 
    1904             : /*
    1905             :  * fd.io coding-style-patch-verification: ON
    1906             :  *
    1907             :  * Local Variables:
    1908             :  * eval: (c-set-style "gnu")
    1909             :  * End:
    1910             :  */

Generated by: LCOV version 1.14