FD.io VPP  v20.05.1-6-gf53edbc3b
Vector Packet Processing
cli.c
Go to the documentation of this file.
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/unix/unix.h>
42 #include <vppinfra/cpu.h>
43 #include <vppinfra/elog.h>
44 #include <unistd.h>
45 #include <ctype.h>
46 
47 /** \file src/vlib/cli.c Debug CLI Implementation
48  */
49 
50 int vl_api_set_elog_trace_api_messages (int enable);
52 
53 static void *current_traced_heap;
54 
55 /* Root of all show commands. */
56 /* *INDENT-OFF* */
57 VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
58  .path = "show",
59  .short_help = "Show commands",
60 };
61 /* *INDENT-ON* */
62 
63 /* Root of all clear commands. */
64 /* *INDENT-OFF* */
65 VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
66  .path = "clear",
67  .short_help = "Clear commands",
68 };
69 /* *INDENT-ON* */
70 
71 /* Root of all set commands. */
72 /* *INDENT-OFF* */
73 VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
74  .path = "set",
75  .short_help = "Set commands",
76 };
77 /* *INDENT-ON* */
78 
79 /* Root of all test commands. */
80 /* *INDENT-OFF* */
81 VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
82  .path = "test",
83  .short_help = "Test commands",
84 };
85 /* *INDENT-ON* */
86 
87 /* Returns bitmap of commands which match key. */
88 static uword *
90 {
91  int i, n;
92  uword *match = 0;
94 
96 
97  for (i = 0;; i++)
98  {
99  uword k;
100 
101  k = unformat_get_input (input);
102  switch (k)
103  {
104  case 'a' ... 'z':
105  case 'A' ... 'Z':
106  case '0' ... '9':
107  case '-':
108  case '_':
109  break;
110 
111  case ' ':
112  case '\t':
113  case '\r':
114  case '\n':
116  /* White space or end of input removes any non-white
117  matches that were before possible. */
118  if (i < vec_len (c->sub_command_positions)
119  && clib_bitmap_count_set_bits (match) > 1)
120  {
122  for (n = 0; n < vec_len (p->bitmaps); n++)
123  match = clib_bitmap_andnot (match, p->bitmaps[n]);
124  }
125  goto done;
126 
127  default:
128  unformat_put_input (input);
129  goto done;
130  }
131 
132  if (i >= vec_len (c->sub_command_positions))
133  {
134  no_match:
135  clib_bitmap_free (match);
136  return 0;
137  }
138 
140  if (vec_len (p->bitmaps) == 0)
141  goto no_match;
142 
143  n = k - p->min_char;
144  if (n < 0 || n >= vec_len (p->bitmaps))
145  goto no_match;
146 
147  if (i == 0)
148  match = clib_bitmap_dup (p->bitmaps[n]);
149  else
150  match = clib_bitmap_and (match, p->bitmaps[n]);
151 
152  if (clib_bitmap_is_zero (match))
153  goto no_match;
154  }
155 
156 done:
157  return match;
158 }
159 
160 /* Looks for string based sub-input formatted { SUB-INPUT }. */
161 uword
163 {
164  unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
165  u8 *s;
166  uword c;
167 
168  while (1)
169  {
170  c = unformat_get_input (i);
171  switch (c)
172  {
173  case ' ':
174  case '\t':
175  case '\n':
176  case '\r':
177  case '\f':
178  break;
179 
180  case '{':
181  default:
182  /* Put back paren. */
183  if (c != UNFORMAT_END_OF_INPUT)
184  unformat_put_input (i);
185 
186  if (c == '{' && unformat (i, "%v", &s))
187  {
188  unformat_init_vector (sub_input, s);
189  return 1;
190  }
191  return 0;
192  }
193  }
194  return 0;
195 }
196 
197 static vlib_cli_command_t *
199 {
201  return vec_elt_at_index (cm->commands, s->index);
202 }
203 
204 static uword
206 {
207  vlib_main_t *vm = va_arg (*args, vlib_main_t *);
208  vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
209  vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
210  vlib_cli_main_t *cm = &vm->cli_main;
211  uword *match_bitmap, is_unique, index;
212 
213  match_bitmap = vlib_cli_sub_command_match (c, i);
214  is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
215  index = ~0;
216  if (is_unique)
217  {
218  index = clib_bitmap_first_set (match_bitmap);
219  *result = get_sub_command (cm, c, index);
220  }
221  clib_bitmap_free (match_bitmap);
222 
223  return is_unique;
224 }
225 
226 static int
227 vlib_cli_cmp_strings (void *a1, void *a2)
228 {
229  u8 *c1 = *(u8 **) a1;
230  u8 *c2 = *(u8 **) a2;
231 
232  return vec_cmp (c1, c2);
233 }
234 
235 u8 **
237 {
240  vlib_main_t *vm = vlib_get_main ();
241  vlib_cli_main_t *vcm = &vm->cli_main;
242  uword *match_bitmap = 0;
243  uword index, is_unique, help_next_level;
244  u8 **result = 0;
245  unformat_input_t input;
246  unformat_init_vector (&input, vec_dup (str));
247  c = vec_elt_at_index (vcm->commands, 0);
248 
249  /* remove trailing whitespace, except for one of them */
250  while (vec_len (input.buffer) >= 2 &&
251  isspace (input.buffer[vec_len (input.buffer) - 1]) &&
252  isspace (input.buffer[vec_len (input.buffer) - 2]))
253  {
254  vec_del1 (input.buffer, vec_len (input.buffer) - 1);
255  }
256 
257  /* if input is empty, directly return list of root commands */
258  if (vec_len (input.buffer) == 0 ||
259  (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
260  {
261  vec_foreach (sc, c->sub_commands)
262  {
263  vec_add1 (result, (u8 *) sc->name);
264  }
265  goto done;
266  }
267 
268  /* add a trailing '?' so that vlib_cli_sub_command_match can find
269  * all commands starting with the input string */
270  vec_add1 (input.buffer, '?');
271 
272  while (1)
273  {
274  match_bitmap = vlib_cli_sub_command_match (c, &input);
275  /* no match: return no result */
276  if (match_bitmap == 0)
277  {
278  goto done;
279  }
280  is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
281  /* unique match: try to step one subcommand level further */
282  if (is_unique)
283  {
284  /* stop if no more input */
285  if (input.index >= vec_len (input.buffer) - 1)
286  {
287  break;
288  }
289 
290  index = clib_bitmap_first_set (match_bitmap);
291  c = get_sub_command (vcm, c, index);
292  clib_bitmap_free (match_bitmap);
293  continue;
294  }
295  /* multiple matches: stop here, return all matches */
296  break;
297  }
298 
299  /* remove trailing '?' */
300  vec_del1 (input.buffer, vec_len (input.buffer) - 1);
301 
302  /* if we have a space at the end of input, and a unique match,
303  * autocomplete the next level of subcommands */
304  help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
305  /* *INDENT-OFF* */
306  clib_bitmap_foreach(index, match_bitmap, {
307  if (help_next_level && is_unique) {
308  c = get_sub_command (vcm, c, index);
309  vec_foreach (sc, c->sub_commands) {
310  vec_add1 (result, (u8*) sc->name);
311  }
312  goto done; /* break doesn't work in this macro-loop */
313  }
314  sc = &c->sub_commands[index];
315  vec_add1(result, (u8*) sc->name);
316  });
317  /* *INDENT-ON* */
318 
319 done:
320  clib_bitmap_free (match_bitmap);
321  unformat_free (&input);
322 
323  if (result)
325  return result;
326 }
327 
328 static u8 *
329 format_vlib_cli_command_help (u8 * s, va_list * args)
330 {
331  vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
332  int is_long = va_arg (*args, int);
333  if (is_long && c->long_help)
334  s = format (s, "%s", c->long_help);
335  else if (c->short_help)
336  s = format (s, "%s", c->short_help);
337  else
338  s = format (s, "%v commands", c->path);
339  return s;
340 }
341 
342 static u8 *
343 format_vlib_cli_path (u8 * s, va_list * args)
344 {
345  u8 *path = va_arg (*args, u8 *);
346 
347  s = format (s, "%v", path);
348 
349  return s;
350 }
351 
352 static vlib_cli_command_t *
354 {
355  vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
357 
358  if (c->function)
359  vec_add1 (subs, c[0]);
360 
361  vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
362 
363  return subs;
364 }
365 
366 static int
367 vlib_cli_cmp_rule (void *a1, void *a2)
368 {
369  vlib_cli_sub_rule_t *r1 = a1;
370  vlib_cli_sub_rule_t *r2 = a2;
371 
372  return vec_cmp (r1->name, r2->name);
373 }
374 
375 static int
376 vlib_cli_cmp_command (void *a1, void *a2)
377 {
378  vlib_cli_command_t *c1 = a1;
379  vlib_cli_command_t *c2 = a2;
380 
381  return vec_cmp (c1->path, c2->path);
382 }
383 
384 static clib_error_t *
387  unformat_input_t * input,
388  uword parent_command_index)
389 {
390  vlib_cli_command_t *parent, *c;
391  clib_error_t *error = 0;
392  unformat_input_t sub_input;
393  u8 *string;
394  uword is_main_dispatch = cm == &vm->cli_main;
395 
396  parent = vec_elt_at_index (cm->commands, parent_command_index);
397  if (is_main_dispatch && unformat (input, "help"))
398  {
399  uword help_at_end_of_line, i;
400 
401  help_at_end_of_line =
403  while (1)
404  {
405  c = parent;
406  if (unformat_user
407  (input, unformat_vlib_cli_sub_command, vm, c, &parent))
408  ;
409 
410  else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
411  goto unknown;
412 
413  else
414  break;
415  }
416 
417  /* help SUB-COMMAND => long format help.
418  "help" at end of line: show all commands. */
419  if (!help_at_end_of_line)
421  /* is_long */ 1);
422 
423  else if (vec_len (c->sub_commands) == 0)
424  vlib_cli_output (vm, "%v: no sub-commands", c->path);
425 
426  else
427  {
428  vlib_cli_sub_rule_t *sr, *subs = 0;
430 
431  vec_foreach (sc, c->sub_commands)
432  {
433  vec_add2 (subs, sr, 1);
434  sr->name = sc->name;
435  sr->command_index = sc->index;
436  sr->rule_index = ~0;
437  }
438 
440 
441  for (i = 0; i < vec_len (subs); i++)
442  {
444 
445  d = vec_elt_at_index (cm->commands, subs[i].command_index);
447  (vm, " %-30v %U", subs[i].name,
448  format_vlib_cli_command_help, d, /* is_long */ 0);
449  }
450 
451  vec_free (subs);
452  }
453  }
454 
455  else if (is_main_dispatch
456  && (unformat (input, "choices") || unformat (input, "?")))
457  {
458  vlib_cli_command_t *sub, *subs;
459 
460  subs = all_subs (cm, 0, parent_command_index);
462  vec_foreach (sub, subs)
463  vlib_cli_output (vm, " %-40U %U",
465  format_vlib_cli_command_help, sub, /* is_long */ 0);
466  vec_free (subs);
467  }
468 
469  else if (unformat (input, "comment %v", &string))
470  {
471  vec_free (string);
472  }
473 
474  else if (unformat (input, "uncomment %U",
475  unformat_vlib_cli_sub_input, &sub_input))
476  {
477  error =
478  vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
479  parent_command_index);
480  unformat_free (&sub_input);
481  }
482  else if (unformat (input, "leak-check %U",
483  unformat_vlib_cli_sub_input, &sub_input))
484  {
485  u8 *leak_report;
487  {
488  void *oldheap;
490  clib_mem_trace (0);
491  clib_mem_set_heap (oldheap);
493  }
494  clib_mem_trace (1);
495  error =
496  vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
497  parent_command_index);
498  unformat_free (&sub_input);
499 
500  /* Otherwise, the clib_error_t shows up as a leak... */
501  if (error)
502  {
503  vlib_cli_output (vm, "%v", error->what);
504  clib_error_free (error);
505  error = 0;
506  }
507 
509  leak_report = format (0, "%U", format_mheap, clib_mem_get_heap (),
510  1 /* verbose, i.e. print leaks */ );
511  clib_mem_trace (0);
512  vlib_cli_output (vm, "%v", leak_report);
513  vec_free (leak_report);
514  }
515 
516  else
517  if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
518  {
520  uword has_sub_commands =
521  vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
522 
523  si = input;
524  if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
525  si = &sub_input;
526 
527  if (has_sub_commands)
528  error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
529 
530  if (has_sub_commands && !error)
531  /* Found valid sub-command. */ ;
532 
533  else if (c->function)
534  {
535  clib_error_t *c_error;
536 
537  /* Skip white space for benefit of called function. */
539 
540  if (unformat (si, "?"))
541  {
542  vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
543  0);
544  }
545  else
546  {
548  {
549  /* *INDENT-OFF* */
550  ELOG_TYPE_DECLARE (e) =
551  {
552  .format = "cli-cmd: %s",
553  .format_args = "T4",
554  };
555  /* *INDENT-ON* */
556  struct
557  {
558  u32 c;
559  } *ed;
560  ed = ELOG_DATA (&vm->elog_main, e);
561  ed->c = elog_string (&vm->elog_main, "%v", c->path);
562  }
563 
564  if (!c->is_mp_safe)
566 
567  c->hit_counter++;
568  c_error = c->function (vm, si, c);
569 
570  if (!c->is_mp_safe)
572 
574  {
575  /* *INDENT-OFF* */
576  ELOG_TYPE_DECLARE (e) =
577  {
578  .format = "cli-cmd: %s %s",
579  .format_args = "T4T4",
580  };
581  /* *INDENT-ON* */
582  struct
583  {
584  u32 c, err;
585  } *ed;
586  ed = ELOG_DATA (&vm->elog_main, e);
587  ed->c = elog_string (&vm->elog_main, "%v", c->path);
588  if (c_error)
589  {
590  vec_add1 (c_error->what, 0);
591  ed->err =
592  elog_string (&vm->elog_main, (char *) c_error->what);
593  _vec_len (c_error->what) -= 1;
594  }
595  else
596  ed->err = elog_string (&vm->elog_main, "OK");
597  }
598 
599  if (c_error)
600  {
601  error =
602  clib_error_return (0, "%v: %v", c->path, c_error->what);
603  clib_error_free (c_error);
604  /* Free sub input. */
605  if (si != input)
606  unformat_free (si);
607 
608  return error;
609  }
610  }
611 
612  /* Free any previous error. */
613  clib_error_free (error);
614  }
615 
616  else if (!error)
617  error = clib_error_return (0, "%v: no sub-commands", c->path);
618 
619  /* Free sub input. */
620  if (si != input)
621  unformat_free (si);
622  }
623 
624  else
625  goto unknown;
626 
627  return error;
628 
629 unknown:
630  if (parent->path)
631  return clib_error_return (0, "%v: unknown input `%U'", parent->path,
632  format_unformat_error, input);
633  else
634  return clib_error_return (0, "unknown input `%U'", format_unformat_error,
635  input);
636 }
637 
638 
640  __attribute__ ((weak));
641 
642 void
644 {
645 }
646 
647 /* Process CLI input. */
648 int
650  unformat_input_t * input,
651  vlib_cli_output_function_t * function, uword function_arg)
652 {
654  clib_error_t *error;
655  vlib_cli_output_function_t *save_function;
656  uword save_function_arg;
657  int rv = 0;
658 
659  save_function = cp->output_function;
660  save_function_arg = cp->output_function_arg;
661 
662  cp->output_function = function;
663  cp->output_function_arg = function_arg;
664 
665  do
666  {
667  error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input,
668  /* parent */ 0);
669  }
670  while (!error && !unformat (input, "%U", unformat_eof));
671 
672  if (error)
673  {
674  vlib_cli_output (vm, "%v", error->what);
675  vlib_unix_error_report (vm, error);
676  /* clib_error_return is unfortunately often called with a '0'
677  return code */
678  rv = error->code != 0 ? error->code : -1;
679  clib_error_free (error);
680  }
681 
682  cp->output_function = save_function;
683  cp->output_function_arg = save_function_arg;
684  return rv;
685 }
686 
687 /* Output to current CLI connection. */
688 void
689 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
690 {
692  va_list va;
693  u8 *s;
694 
695  va_start (va, fmt);
696  s = va_format (0, fmt, &va);
697  va_end (va);
698 
699  /* Terminate with \n if not present. */
700  if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
701  vec_add1 (s, '\n');
702 
703  if ((!cp) || (!cp->output_function))
704  fformat (stdout, "%v", s);
705  else
706  cp->output_function (cp->output_function_arg, s, vec_len (s));
707 
708  vec_free (s);
709 }
710 
711 void *vl_msg_push_heap (void) __attribute__ ((weak));
712 void *
714 {
715  return 0;
716 }
717 
718 void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
719 void
720 vl_msg_pop_heap (void *oldheap)
721 {
722 }
723 
724 void *vlib_stats_push_heap (void *) __attribute__ ((weak));
725 void *
726 vlib_stats_push_heap (void *notused)
727 {
728  return 0;
729 }
730 
731 static clib_error_t *
733  unformat_input_t * input, vlib_cli_command_t * cmd)
734 {
735  int verbose __attribute__ ((unused)) = 0;
736  int api_segment = 0, stats_segment = 0, main_heap = 0, numa_heaps = 0;
737  clib_error_t *error;
738  u32 index = 0;
739  int i;
741  uword was_enabled;
742 
743 
745  {
746  if (unformat (input, "verbose"))
747  verbose = 1;
748  else if (unformat (input, "api-segment"))
749  api_segment = 1;
750  else if (unformat (input, "stats-segment"))
751  stats_segment = 1;
752  else if (unformat (input, "main-heap"))
753  main_heap = 1;
754  else if (unformat (input, "numa-heaps"))
755  numa_heaps = 1;
756  else
757  {
758  error = clib_error_return (0, "unknown input `%U'",
759  format_unformat_error, input);
760  return error;
761  }
762  }
763 
764  if ((api_segment + stats_segment + main_heap + numa_heaps) == 0)
765  return clib_error_return
766  (0, "Need one of api-segment, stats-segment, main-heap or numa-heaps");
767 
768  if (api_segment)
769  {
770  void *oldheap = vl_msg_push_heap ();
771  was_enabled = clib_mem_trace_enable_disable (0);
772  u8 *s_in_svm =
773  format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
774  vl_msg_pop_heap (oldheap);
775  u8 *s = vec_dup (s_in_svm);
776 
777  oldheap = vl_msg_push_heap ();
778  vec_free (s_in_svm);
779  clib_mem_trace_enable_disable (was_enabled);
780  vl_msg_pop_heap (oldheap);
781  vlib_cli_output (vm, "API segment");
782  vlib_cli_output (vm, "%v", s);
783  vec_free (s);
784  }
785  if (stats_segment)
786  {
787  void *oldheap = vlib_stats_push_heap (0);
788  was_enabled = clib_mem_trace_enable_disable (0);
789  u8 *s_in_svm =
790  format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
791  if (oldheap)
792  clib_mem_set_heap (oldheap);
793  u8 *s = vec_dup (s_in_svm);
794 
795  oldheap = vlib_stats_push_heap (0);
796  vec_free (s_in_svm);
797  if (oldheap)
798  {
799  clib_mem_trace_enable_disable (was_enabled);
800  clib_mem_set_heap (oldheap);
801  }
802  vlib_cli_output (vm, "Stats segment");
803  vlib_cli_output (vm, "%v", s);
804  vec_free (s);
805  }
806 
807 
808  {
809  if (main_heap)
810  {
811  /*
812  * Note: the foreach_vlib_main causes allocator traffic,
813  * so shut off tracing before we go there...
814  */
815  was_enabled = clib_mem_trace_enable_disable (0);
816 
817  /* *INDENT-OFF* */
819  ({
820  struct dlmallinfo mi;
821  void *mspace;
822  mspace = clib_per_cpu_mheaps[index];
823 
824  mi = mspace_mallinfo (mspace);
825  vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
826  vlib_worker_threads[index].name);
827  vlib_cli_output (vm, " %U\n", format_page_map,
829  mi.arena);
830  vlib_cli_output (vm, " %U\n", format_mheap,
831  clib_per_cpu_mheaps[index],
832  verbose);
833  index++;
834  }));
835  /* *INDENT-ON* */
836 
837  /* Restore the trace flag */
838  clib_mem_trace_enable_disable (was_enabled);
839  }
840  if (numa_heaps)
841  {
842  struct dlmallinfo mi;
843  void *mspace;
844 
845  for (i = 0; i < ARRAY_LEN (clib_per_numa_mheaps); i++)
846  {
847  if (clib_per_numa_mheaps[i] == 0)
848  continue;
850  {
851  vlib_cli_output (vm, "Numa %d uses the main heap...", i);
852  continue;
853  }
854  was_enabled = clib_mem_trace_enable_disable (0);
855  mspace = clib_per_numa_mheaps[i];
856 
857  mi = mspace_mallinfo (mspace);
858  vlib_cli_output (vm, "Numa %d:", i);
859  vlib_cli_output (vm, " %U\n", format_page_map,
861  mi.arena);
862  vlib_cli_output (vm, " %U\n", format_mheap,
863  clib_per_numa_mheaps[index], verbose);
864  }
865  }
866  }
867  return 0;
868 }
869 
870 /* *INDENT-OFF* */
871 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
872  .path = "show memory",
873  .short_help = "show memory [api-segment][stats-segment][verbose]\n"
874  " [numa-heaps]",
875  .function = show_memory_usage,
876 };
877 /* *INDENT-ON* */
878 
879 static clib_error_t *
881  vlib_cli_command_t * cmd)
882 {
883 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
884  _("Model name", "%U", format_cpu_model_name);
885  _("Microarch model (family)", "%U", format_cpu_uarch);
886  _("Flags", "%U", format_cpu_flags);
887  _("Base frequency", "%.2f GHz",
888  ((f64) vm->clib_time.clocks_per_second) * 1e-9);
889 #undef _
890  return 0;
891 }
892 
893 /*?
894  * Displays various information about the CPU.
895  *
896  * @cliexpar
897  * @cliexstart{show cpu}
898  * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
899  * Microarchitecture: Broadwell (Broadwell-EP/EX)
900  * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
901  * Base Frequency: 3.20 GHz
902  * @cliexend
903 ?*/
904 /* *INDENT-OFF* */
905 VLIB_CLI_COMMAND (show_cpu_command, static) = {
906  .path = "show cpu",
907  .short_help = "Show cpu information",
908  .function = show_cpu,
909 };
910 /* *INDENT-ON* */
911 
912 static clib_error_t *
914  unformat_input_t * input,
915  vlib_cli_command_t * cmd)
916 {
917  unformat_input_t _line_input, *line_input = &_line_input;
918  int enable = 1;
919  int api_segment = 0;
920  int stats_segment = 0;
921  int main_heap = 0;
922  u32 numa_id = ~0;
923  void *oldheap;
924 
925  if (!unformat_user (input, unformat_line_input, line_input))
926  return 0;
927 
928  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
929  {
930  if (unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
931  ;
932  else if (unformat (line_input, "api-segment"))
933  api_segment = 1;
934  else if (unformat (line_input, "stats-segment"))
935  stats_segment = 1;
936  else if (unformat (line_input, "main-heap"))
937  main_heap = 1;
938  else if (unformat (line_input, "numa-heap %d", &numa_id))
939  ;
940  else
941  {
942  unformat_free (line_input);
943  return clib_error_return (0, "invalid input");
944  }
945  }
946  unformat_free (line_input);
947 
948  if ((api_segment + stats_segment + main_heap + (enable == 0)
949  + (numa_id != ~0)) == 0)
950  {
951  return clib_error_return
952  (0, "Need one of main-heap, stats-segment, api-segment,\n"
953  "numa-heap <nn> or disable");
954  }
955 
956  /* Turn off current trace, if any */
958  {
959  void *oldheap;
961  clib_mem_trace (0);
962  clib_mem_set_heap (oldheap);
964  }
965 
966  if (enable == 0)
967  return 0;
968 
969  /* API segment */
970  if (api_segment)
971  {
972  oldheap = vl_msg_push_heap ();
974  clib_mem_trace (1);
975  vl_msg_pop_heap (oldheap);
976 
977  }
978 
979  /* Stats segment */
980  if (stats_segment)
981  {
982  oldheap = vlib_stats_push_heap (0);
984  clib_mem_trace (stats_segment);
985  /* We don't want to call vlib_stats_pop_heap... */
986  if (oldheap)
987  clib_mem_set_heap (oldheap);
988  }
989 
990  /* main_heap */
991  if (main_heap)
992  {
994  clib_mem_trace (main_heap);
995  }
996 
997  if (numa_id != ~0)
998  {
999  if (numa_id >= ARRAY_LEN (clib_per_numa_mheaps))
1000  return clib_error_return (0, "Numa %d out of range", numa_id);
1001  if (clib_per_numa_mheaps[numa_id] == 0)
1002  return clib_error_return (0, "Numa %d heap not active", numa_id);
1003 
1004  if (clib_per_numa_mheaps[numa_id] == clib_mem_get_heap ())
1005  return clib_error_return (0, "Numa %d uses the main heap...",
1006  numa_id);
1009  clib_mem_trace (1);
1010  clib_mem_set_heap (oldheap);
1011  }
1012 
1013 
1014  return 0;
1015 }
1016 
1017 /* *INDENT-OFF* */
1018 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
1019  .path = "memory-trace",
1020  .short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n"
1021  " [numa-heap <numa-id>]\n",
1022  .function = enable_disable_memory_trace,
1023 };
1024 /* *INDENT-ON* */
1025 
1026 static clib_error_t *
1028  vlib_cli_command_t * cmd)
1029 {
1031  clib_file_t *f;
1032 
1033  /* environ(7) does not indicate a header for this */
1034  extern char **environ;
1035 
1036  /* Close all known open files */
1037  /* *INDENT-OFF* */
1038  pool_foreach(f, fm->file_pool,
1039  ({
1040  if (f->file_descriptor > 2)
1041  close(f->file_descriptor);
1042  }));
1043  /* *INDENT-ON* */
1044 
1045  /* Exec ourself */
1046  execve (vm->name, (char **) vm->argv, environ);
1047 
1048  return 0;
1049 }
1050 
1051 /* *INDENT-OFF* */
1052 VLIB_CLI_COMMAND (restart_cmd,static) = {
1053  .path = "restart",
1054  .short_help = "restart process",
1055  .function = restart_cmd_fn,
1056 };
1057 /* *INDENT-ON* */
1058 
1059 #ifdef TEST_CODE
1060 /*
1061  * A trivial test harness to verify the per-process output_function
1062  * is working correcty.
1063  */
1064 
1065 static clib_error_t *
1066 sleep_ten_seconds (vlib_main_t * vm,
1067  unformat_input_t * input, vlib_cli_command_t * cmd)
1068 {
1069  u16 i;
1070  u16 my_id = rand ();
1071 
1072  vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
1073 
1074  for (i = 0; i < 10; i++)
1075  {
1077  vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
1078  }
1079  vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
1080  return 0;
1081 }
1082 
1083 /* *INDENT-OFF* */
1084 VLIB_CLI_COMMAND (ping_command, static) = {
1085  .path = "test sleep",
1086  .function = sleep_ten_seconds,
1087  .short_help = "Sleep for 10 seconds",
1088 };
1089 /* *INDENT-ON* */
1090 #endif /* ifdef TEST_CODE */
1091 
1092 static uword
1093 vlib_cli_normalize_path (char *input, char **result)
1094 {
1095  char *i = input;
1096  char *s = 0;
1097  uword l = 0;
1098  uword index_of_last_space = ~0;
1099 
1100  while (*i != 0)
1101  {
1102  u8 c = *i++;
1103  /* Multiple white space -> single space. */
1104  switch (c)
1105  {
1106  case ' ':
1107  case '\t':
1108  case '\n':
1109  case '\r':
1110  if (l > 0 && s[l - 1] != ' ')
1111  {
1112  vec_add1 (s, ' ');
1113  l++;
1114  }
1115  break;
1116 
1117  default:
1118  if (l > 0 && s[l - 1] == ' ')
1119  index_of_last_space = vec_len (s);
1120  vec_add1 (s, c);
1121  l++;
1122  break;
1123  }
1124  }
1125 
1126  /* Remove any extra space at end. */
1127  if (l > 0 && s[l - 1] == ' ')
1128  _vec_len (s) -= 1;
1129 
1130  *result = s;
1131  return index_of_last_space;
1132 }
1133 
1136 {
1137  word i;
1138  for (i = vec_len (path) - 1; i >= 0; i--)
1139  {
1140  if (path[i] == ' ')
1141  return i;
1142  }
1143  return ~0;
1144 }
1145 
1146 static void
1147 add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
1148 {
1149  vlib_cli_command_t *p, *c;
1150  vlib_cli_sub_command_t *sub_c;
1151  u8 *sub_name;
1152  word i, l;
1153 
1154  p = vec_elt_at_index (cm->commands, parent_index);
1155  c = vec_elt_at_index (cm->commands, child_index);
1156 
1157  l = parent_path_len (c->path);
1158  if (l == ~0)
1159  sub_name = vec_dup ((u8 *) c->path);
1160  else
1161  {
1162  ASSERT (l + 1 < vec_len (c->path));
1163  sub_name = 0;
1164  vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
1165  }
1166 
1167  if (sub_name[0] == '%')
1168  {
1169  uword *q;
1170  vlib_cli_sub_rule_t *sr;
1171 
1172  /* Remove %. */
1173  vec_delete (sub_name, 1, 0);
1174 
1175  if (!p->sub_rule_index_by_name)
1176  p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1177  sizeof (sub_name[0]),
1178  sizeof (uword));
1179  q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1180  if (q)
1181  {
1182  sr = vec_elt_at_index (p->sub_rules, q[0]);
1183  ASSERT (sr->command_index == child_index);
1184  return;
1185  }
1186 
1187  hash_set_mem (p->sub_rule_index_by_name, sub_name,
1188  vec_len (p->sub_rules));
1189  vec_add2 (p->sub_rules, sr, 1);
1190  sr->name = sub_name;
1191  sr->rule_index = sr - p->sub_rules;
1192  sr->command_index = child_index;
1193  return;
1194  }
1195 
1196  if (!p->sub_command_index_by_name)
1197  p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1198  sizeof (c->path[0]),
1199  sizeof (uword));
1200 
1201  /* Check if sub-command has already been created. */
1202  if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1203  {
1204  vec_free (sub_name);
1205  return;
1206  }
1207 
1208  vec_add2 (p->sub_commands, sub_c, 1);
1209  sub_c->index = child_index;
1210  sub_c->name = sub_name;
1212  sub_c - p->sub_commands);
1213 
1214  vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1215  for (i = 0; i < vec_len (sub_c->name); i++)
1216  {
1217  int n;
1219 
1221 
1222  if (!pos->bitmaps)
1223  pos->min_char = sub_c->name[i];
1224 
1225  n = sub_c->name[i] - pos->min_char;
1226  if (n < 0)
1227  {
1228  pos->min_char = sub_c->name[i];
1229  vec_insert (pos->bitmaps, -n, 0);
1230  n = 0;
1231  }
1232 
1233  vec_validate (pos->bitmaps, n);
1234  pos->bitmaps[n] =
1235  clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
1236  }
1237 }
1238 
1239 static void
1241 {
1242  uword p_len, pi, *p;
1243  char *p_path;
1244  vlib_cli_command_t *c, *parent;
1245 
1246  /* Root command (index 0) should have already been added. */
1247  ASSERT (vec_len (cm->commands) > 0);
1248 
1249  c = vec_elt_at_index (cm->commands, ci);
1250  p_len = parent_path_len (c->path);
1251 
1252  /* No space? Parent is root command. */
1253  if (p_len == ~0)
1254  {
1255  add_sub_command (cm, 0, ci);
1256  return;
1257  }
1258 
1259  p_path = 0;
1260  vec_add (p_path, c->path, p_len);
1261 
1262  p = hash_get_mem (cm->command_index_by_path, p_path);
1263 
1264  /* Parent exists? */
1265  if (!p)
1266  {
1267  /* Parent does not exist; create it. */
1268  vec_add2 (cm->commands, parent, 1);
1269  parent->path = p_path;
1270  hash_set_mem (cm->command_index_by_path, parent->path,
1271  parent - cm->commands);
1272  pi = parent - cm->commands;
1273  }
1274  else
1275  {
1276  pi = p[0];
1277  vec_free (p_path);
1278  }
1279 
1280  add_sub_command (cm, pi, ci);
1281 
1282  /* Create parent's parent. */
1283  if (!p)
1284  vlib_cli_make_parent (cm, pi);
1285 }
1286 
1289 {
1290  return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1291 }
1292 
1293 clib_error_t *
1295 {
1296  vlib_cli_main_t *cm = &vm->cli_main;
1297  clib_error_t *error = 0;
1298  uword ci, *p;
1299  char *normalized_path;
1300 
1301  if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1302  return error;
1303 
1304  (void) vlib_cli_normalize_path (c->path, &normalized_path);
1305 
1306  if (!cm->command_index_by_path)
1307  cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1308  sizeof (c->path[0]),
1309  sizeof (uword));
1310 
1311  /* See if command already exists with given path. */
1312  p = hash_get_mem (cm->command_index_by_path, normalized_path);
1313  if (p)
1314  {
1315  vlib_cli_command_t *d;
1316 
1317  ci = p[0];
1318  d = vec_elt_at_index (cm->commands, ci);
1319 
1320  /* If existing command was created via vlib_cli_make_parent
1321  replaced it with callers data. */
1322  if (vlib_cli_command_is_empty (d))
1323  {
1324  vlib_cli_command_t save = d[0];
1325 
1327 
1328  /* Copy callers fields. */
1329  d[0] = c[0];
1330 
1331  /* Save internal fields. */
1332  d->path = save.path;
1333  d->sub_commands = save.sub_commands;
1336  d->sub_rules = save.sub_rules;
1337  }
1338  else
1339  error =
1340  clib_error_return (0, "duplicate command name with path %v",
1341  normalized_path);
1342 
1343  vec_free (normalized_path);
1344  if (error)
1345  return error;
1346  }
1347  else
1348  {
1349  /* Command does not exist: create it. */
1350 
1351  /* Add root command (index 0). */
1352  if (vec_len (cm->commands) == 0)
1353  {
1354  /* Create command with index 0; path is empty string. */
1355  vec_resize (cm->commands, 1);
1356  }
1357 
1358  ci = vec_len (cm->commands);
1359  hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1360  vec_add1 (cm->commands, c[0]);
1361 
1362  c = vec_elt_at_index (cm->commands, ci);
1363  c->path = normalized_path;
1364 
1365  /* Don't inherit from registration. */
1366  c->sub_commands = 0;
1368  c->sub_command_positions = 0;
1369  }
1370 
1371  vlib_cli_make_parent (cm, ci);
1372  return 0;
1373 }
1374 
1375 #if 0
1376 /* $$$ turn back on again someday, maybe */
1377 clib_error_t *
1379 {
1380  vlib_cli_main_t *cm = &vm->cli_main;
1382  clib_error_t *error = 0;
1383  u8 *r_name;
1384  uword *p;
1385 
1386  if (!cm->parse_rule_index_by_name)
1387  cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1388  sizeof (r->name[0]),
1389  sizeof (uword));
1390 
1391  /* Make vector copy of name. */
1392  r_name = format (0, "%s", r_reg->name);
1393 
1394  if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1395  {
1396  vec_free (r_name);
1397  return clib_error_return (0, "duplicate parse rule name `%s'",
1398  r_reg->name);
1399  }
1400 
1401  vec_add2 (cm->parse_rules, r, 1);
1402  r[0] = r_reg[0];
1403  r->name = (char *) r_name;
1404  hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1405 
1406  return error;
1407 }
1408 
1409 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1411  lo,
1413  hi)
1414  __attribute__ ((unused))
1415 {
1416  clib_error_t *error = 0;
1418 
1419  for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1420  {
1421  if (!r->name || strlen (r->name) == 0)
1422  {
1423  error = clib_error_return (0, "parse rule with no name");
1424  goto done;
1425  }
1426 
1427  error = vlib_cli_register_parse_rule (vm, r);
1428  if (error)
1429  goto done;
1430  }
1431 
1432 done:
1433  return error;
1434 }
1435 #endif
1436 
1437 static clib_error_t *
1439  unformat_input_t * input, vlib_cli_command_t * cmd)
1440 {
1441  unformat_input_t _line_input, *line_input = &_line_input;
1442  int enable = 1;
1443  int api = 0, cli = 0, barrier = 0, dispatch = 0, circuit = 0;
1444  u32 circuit_node_index;
1445 
1446  if (!unformat_user (input, unformat_line_input, line_input))
1447  goto print_status;
1448 
1449  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1450  {
1451  if (unformat (line_input, "api"))
1452  api = 1;
1453  else if (unformat (line_input, "dispatch"))
1454  dispatch = 1;
1455  else if (unformat (line_input, "circuit-node %U",
1456  unformat_vlib_node, vm, &circuit_node_index))
1457  circuit = 1;
1458  else if (unformat (line_input, "cli"))
1459  cli = 1;
1460  else if (unformat (line_input, "barrier"))
1461  barrier = 1;
1462  else if (unformat (line_input, "disable"))
1463  enable = 0;
1464  else if (unformat (line_input, "enable"))
1465  enable = 1;
1466  else
1467  break;
1468  }
1469  unformat_free (line_input);
1470 
1472  (api ? enable : vl_api_get_elog_trace_api_messages ());
1473  vm->elog_trace_cli_commands = cli ? enable : vm->elog_trace_cli_commands;
1474  vm->elog_trace_graph_dispatch = dispatch ?
1475  enable : vm->elog_trace_graph_dispatch;
1476  vm->elog_trace_graph_circuit = circuit ?
1477  enable : vm->elog_trace_graph_circuit;
1479  barrier ? enable : vlib_worker_threads->barrier_elog_enabled;
1480  vm->elog_trace_graph_circuit_node_index = circuit_node_index;
1481 
1482  /*
1483  * Set up start-of-buffer logic-analyzer trigger
1484  * for main loop event logs, which are fairly heavyweight.
1485  * See src/vlib/main/vlib_elog_main_loop_event(...), which
1486  * will fully disable the scheme when the elog buffer fills.
1487  */
1488  if (dispatch || circuit)
1489  {
1490  elog_main_t *em = &vm->elog_main;
1491 
1493  em->n_total_events + vec_len (em->event_ring);
1494  }
1495 
1496 
1497 print_status:
1498  vlib_cli_output (vm, "Current status:");
1499 
1501  (vm, " Event log API message trace: %s\n CLI command trace: %s",
1502  vl_api_get_elog_trace_api_messages ()? "on" : "off",
1503  vm->elog_trace_cli_commands ? "on" : "off");
1505  (vm, " Barrier sync trace: %s",
1506  vlib_worker_threads->barrier_elog_enabled ? "on" : "off");
1508  (vm, " Graph Dispatch: %s",
1509  vm->elog_trace_graph_dispatch ? "on" : "off");
1511  (vm, " Graph Circuit: %s",
1512  vm->elog_trace_graph_circuit ? "on" : "off");
1513  if (vm->elog_trace_graph_circuit)
1515  (vm, " node %U",
1517 
1518  return 0;
1519 }
1520 
1521 /*?
1522  * Control event logging of api, cli, and thread barrier events
1523  * With no arguments, displays the current trace status.
1524  * Name the event groups you wish to trace or stop tracing.
1525  *
1526  * @cliexpar
1527  * @clistart
1528  * elog trace api cli barrier
1529  * elog trace api cli barrier disable
1530  * elog trace dispatch
1531  * elog trace circuit-node ethernet-input
1532  * elog trace
1533  * @cliend
1534  * @cliexcmd{elog trace [api][cli][barrier][disable]}
1535 ?*/
1536 /* *INDENT-OFF* */
1537 VLIB_CLI_COMMAND (elog_trace_command, static) =
1538 {
1539  .path = "elog trace",
1540  .short_help = "elog trace [api][cli][barrier][dispatch]\n"
1541  "[circuit-node <name> e.g. ethernet-input][disable]",
1542  .function = elog_trace_command_fn,
1543 };
1544 /* *INDENT-ON* */
1545 
1546 static clib_error_t *
1548  unformat_input_t * input, vlib_cli_command_t * cmd)
1549 {
1550  vlib_process_suspend (vm, 30e-3);
1551  return 0;
1552 }
1553 
1554 /* *INDENT-OFF* */
1555 VLIB_CLI_COMMAND (suspend_command, static) =
1556 {
1557  .path = "suspend",
1558  .short_help = "suspend debug CLI for 30ms",
1559  .function = suspend_command_fn,
1560  .is_mp_safe = 1,
1561 };
1562 /* *INDENT-ON* */
1563 
1564 
1565 static int
1566 sort_cmds_by_path (void *a1, void *a2)
1567 {
1568  u32 *index1 = a1;
1569  u32 *index2 = a2;
1570  vlib_main_t *vm = vlib_get_main ();
1571  vlib_cli_main_t *cm = &vm->cli_main;
1572  vlib_cli_command_t *c1, *c2;
1573  int i, lmin;
1574 
1575  c1 = vec_elt_at_index (cm->commands, *index1);
1576  c2 = vec_elt_at_index (cm->commands, *index2);
1577 
1578  lmin = vec_len (c1->path);
1579  lmin = (vec_len (c2->path) >= lmin) ? lmin : vec_len (c2->path);
1580 
1581  for (i = 0; i < lmin; i++)
1582  {
1583  if (c1->path[i] < c2->path[i])
1584  return -1;
1585  else if (c1->path[i] > c2->path[i])
1586  return 1;
1587  }
1588 
1589  return 0;
1590 }
1591 
1592 typedef struct
1593 {
1601 
1602 static void
1604 {
1605  vlib_cli_command_t *parent;
1607  vlib_cli_walk_args_t _a, *a = &_a;
1609  int i;
1610 
1611  /* Copy args into this stack frame */
1612  *a = *aa;
1613  cm = a->cm;
1614 
1615  parent = vec_elt_at_index (cm->commands, a->parent_command_index);
1616 
1617  if (parent->function)
1618  {
1619  if (((a->show_mp_safe && parent->is_mp_safe)
1620  || (a->show_not_mp_safe && !parent->is_mp_safe))
1621  && (a->show_hit == 0 || parent->hit_counter))
1622  {
1624  }
1625 
1626  if (a->clear_hit)
1627  parent->hit_counter = 0;
1628  }
1629 
1630  for (i = 0; i < vec_len (parent->sub_commands); i++)
1631  {
1632  sub = vec_elt_at_index (parent->sub_commands, i);
1633  a->parent_command_index = sub->index;
1634  cli_recursive_walk (a);
1635  }
1636 }
1637 
1638 static u8 *
1639 format_mp_safe (u8 * s, va_list * args)
1640 {
1641  vlib_cli_main_t *cm = va_arg (*args, vlib_cli_main_t *);
1642  int show_mp_safe = va_arg (*args, int);
1643  int show_not_mp_safe = va_arg (*args, int);
1644  int show_hit = va_arg (*args, int);
1645  int clear_hit = va_arg (*args, int);
1647  vlib_cli_walk_args_t _a, *a = &_a;
1648  int i;
1649  char *format_string = "\n%v";
1650 
1651  if (show_hit)
1652  format_string = "\n%v: %u";
1653 
1655 
1656  a->cm = cm;
1657  a->parent_command_index = 0;
1658  a->show_mp_safe = show_mp_safe;
1659  a->show_not_mp_safe = show_not_mp_safe;
1660  a->show_hit = show_hit;
1661  a->clear_hit = clear_hit;
1662 
1663  cli_recursive_walk (a);
1664 
1666 
1667  for (i = 0; i < vec_len (cm->sort_vector); i++)
1668  {
1669  c = vec_elt_at_index (cm->commands, cm->sort_vector[i]);
1670  s = format (s, format_string, c->path, c->hit_counter);
1671  }
1672 
1673  return s;
1674 }
1675 
1676 
1677 static clib_error_t *
1679  unformat_input_t * input, vlib_cli_command_t * cmd)
1680 {
1681  int show_mp_safe = 0;
1682  int show_not_mp_safe = 0;
1683  int show_hit = 0;
1684  int clear_hit = 0;
1685 
1686  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1687  {
1688  if (unformat (input, "mp-safe"))
1689  show_mp_safe = 1;
1690  if (unformat (input, "not-mp-safe"))
1691  show_not_mp_safe = 1;
1692  else if (unformat (input, "hit"))
1693  show_hit = 1;
1694  else if (unformat (input, "clear-hit"))
1695  clear_hit = 1;
1696  else
1697  break;
1698  }
1699 
1700  /* default set: all cli commands */
1701  if (clear_hit == 0 && (show_mp_safe + show_not_mp_safe) == 0)
1702  show_mp_safe = show_not_mp_safe = 1;
1703 
1704  vlib_cli_output (vm, "%U", format_mp_safe, &vm->cli_main,
1705  show_mp_safe, show_not_mp_safe, show_hit, clear_hit);
1706  if (clear_hit)
1707  vlib_cli_output (vm, "hit counters cleared...");
1708 
1709  return 0;
1710 }
1711 
1712 /*?
1713  * Displays debug cli command information
1714  *
1715  * @cliexpar
1716  * @cliexstart{show cli [mp-safe][not-mp-safe][hit][clear-hit]}
1717  *
1718  * "show cli" displays the entire debug cli:
1719  *
1720  * abf attach
1721  * abf policy
1722  * adjacency counters
1723  * api trace
1724  * app ns
1725  * bfd key del
1726  * ... and so on ...
1727  *
1728  * "show cli mp-safe" displays mp-safe debug CLI commands:
1729  *
1730  * abf policy
1731  * binary-api
1732  * create vhost-user
1733  * exec
1734  * ip container
1735  * ip mroute
1736  * ip probe-neighbor
1737  * ip route
1738  * ip scan-neighbor
1739  * ip table
1740  * ip6 table
1741  *
1742  * "show cli not-mp-safe" displays debug CLI commands
1743  * which cause worker thread barrier synchronization
1744  *
1745  * "show cli hit" displays commands which have been executed. Qualify
1746  * as desired with "mp-safe" or "not-mp-safe".
1747  *
1748  * "show cli clear-hit" clears the per-command hit counters.
1749  * @cliexend
1750 ?*/
1751 
1752 /* *INDENT-OFF* */
1753 VLIB_CLI_COMMAND (show_cli_command, static) =
1754 {
1755  .path = "show cli",
1756  .short_help = "show cli [mp-safe][not-mp-safe][hit][clear-hit]",
1757  .function = show_cli_command_fn,
1758  .is_mp_safe = 1,
1759 };
1760 /* *INDENT-ON* */
1761 
1762 static clib_error_t *
1764 {
1765  vlib_cli_main_t *cm = &vm->cli_main;
1766  clib_error_t *error = 0;
1767  vlib_cli_command_t *cmd;
1768 
1769  cmd = cm->cli_command_registrations;
1770 
1771  while (cmd)
1772  {
1773  error = vlib_cli_register (vm, cmd);
1774  if (error)
1775  return error;
1776  cmd = cmd->next_cli_command;
1777  }
1778  return error;
1779 }
1780 
1782 
1783 /*
1784  * fd.io coding-style-patch-verification: ON
1785  *
1786  * Local Variables:
1787  * eval: (c-set-style "gnu")
1788  * End:
1789  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:507
uword output_function_arg
Definition: node.h:614
void * clib_per_cpu_mheaps[CLIB_MAX_MHEAPS]
Definition: mem_dlmalloc.c:25
void * mspace
Definition: dlmalloc.h:1306
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:673
format_function_t format_vlib_node_name
Definition: node_funcs.h:1141
a
Definition: bitmap.h:538
unformat_function_t unformat_eof
Definition: format.h:293
static uword unformat_get_input(unformat_input_t *input)
Definition: format.h:192
int elog_trace_cli_commands
Definition: main.h:197
u32 parent_command_index
Definition: cli.c:1595
vlib_cli_command_t * commands
Definition: cli.h:138
int vl_api_get_elog_trace_api_messages(void)
Definition: api_shared.c:1202
f64 clocks_per_second
Definition: time.h:54
static clib_error_t * show_cli_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1678
format_function_t format_cpu_flags
Definition: cpu.h:413
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:590
static int vlib_cli_cmp_strings(void *a1, void *a2)
Definition: cli.c:227
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:628
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
uword * sub_rule_index_by_name
Definition: cli.h:121
#define hash_set_mem(h, key, value)
Definition: hash.h:275
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u8 * va_format(u8 *s, const char *fmt, va_list *va)
Definition: format.c:387
clib_time_t clib_time
Definition: main.h:87
vl_api_fib_path_t path
Definition: mfib_types.api:34
DLMALLOC_EXPORT struct dlmallinfo mspace_mallinfo(mspace msp)
int vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:649
void * vlib_stats_push_heap(void *)
Definition: cli.c:726
vlib_cli_main_t cli_main
Definition: main.h:161
static clib_error_t * enable_disable_memory_trace(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:913
unsigned char u8
Definition: types.h:56
#define clib_bitmap_dup(v)
Duplicate a bitmap.
Definition: bitmap.h:87
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:204
clib_error_t * vlib_cli_register_parse_rule(struct vlib_main_t *vm, vlib_cli_parse_rule_t *c)
#define fm
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:666
clib_file_t * file_pool
Definition: file.h:88
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:422
i64 word
Definition: types.h:111
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:513
static u8 * format_mp_safe(u8 *s, va_list *args)
Definition: cli.c:1639
MALLINFO_FIELD_TYPE arena
Definition: dlmalloc.h:800
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
void vlib_unix_error_report(vlib_main_t *, clib_error_t *)
Definition: cli.c:643
static clib_error_t * vlib_cli_dispatch_sub_commands(vlib_main_t *vm, vlib_cli_main_t *cm, unformat_input_t *input, uword parent_command_index)
Definition: cli.c:385
static uword clib_bitmap_is_zero(uword *ai)
predicate function; is an entire bitmap empty?
Definition: bitmap.h:57
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u8 * format_page_map(u8 *s, va_list *args)
Definition: unix-formats.c:969
#define clib_error_return(e, args...)
Definition: error.h:99
uword * command_index_by_path
Definition: cli.h:141
clib_file_main_t file_main
Definition: main.c:63
static int vlib_cli_cmp_rule(void *a1, void *a2)
Definition: cli.c:367
static void * current_traced_heap
Definition: cli.c:53
u32 command_index
Definition: cli.h:68
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:281
void * clib_per_numa_mheaps[CLIB_MAX_NUMAS]
Definition: mem_dlmalloc.c:26
static uword vlib_cli_normalize_path(char *input, char **result)
Definition: cli.c:1093
unsigned int u32
Definition: types.h:88
static u8 * format_vlib_cli_path(u8 *s, va_list *args)
Definition: cli.c:343
#define vlib_call_init_function(vm, x)
Definition: init.h:270
uword clib_mem_trace_enable_disable(uword enable)
Definition: mem_dlmalloc.c:475
static clib_error_t * show_memory_usage(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:732
static clib_error_t * show_cpu(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:880
unformat_function_t unformat_line_input
Definition: format.h:283
u8 * format_mheap(u8 *s, va_list *va)
Definition: mem_dlmalloc.c:388
char * name
Definition: main.h:140
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:34
#define clib_bitmap_foreach(i, ai, body)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
static void add_sub_command(vlib_cli_main_t *cm, uword parent_index, uword child_index)
Definition: cli.c:1147
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:753
void vl_msg_pop_heap(void *oldheap)
Definition: cli.c:720
vlib_cli_command_function_t * function
Definition: cli.h:102
static uword clib_bitmap_first_set(uword *ai)
Return the lowest numbered set bit in a bitmap.
Definition: bitmap.h:385
static vlib_cli_command_t * get_sub_command(vlib_cli_main_t *cm, vlib_cli_command_t *parent, u32 si)
Definition: cli.c:198
vlib_cli_sub_rule_t * sub_rules
Definition: cli.h:124
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static int vlib_cli_cmp_command(void *a1, void *a2)
Definition: cli.c:376
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:427
#define ELOG_DATA(em, f)
Definition: elog.h:484
elog_event_t * event_ring
Vector of events (circular buffer).
Definition: elog.h:149
#define PREDICT_FALSE(x)
Definition: clib.h:118
#define always_inline
Definition: ipsec.h:28
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:873
static void unformat_put_input(unformat_input_t *input)
Definition: format.h:205
static void vlib_cli_make_parent(vlib_cli_main_t *cm, uword ci)
Definition: cli.c:1240
#define foreach_vlib_main(body)
Definition: threads.h:241
void * vl_msg_push_heap(void)
Definition: cli.c:713
clib_error_t * vlib_cli_register(vlib_main_t *vm, vlib_cli_command_t *c)
Definition: cli.c:1294
word fformat(FILE *f, char *fmt,...)
Definition: format.c:462
void unformat_init_vector(unformat_input_t *input, u8 *vector_string)
Definition: unformat.c:1037
static uword * vlib_cli_sub_command_match(vlib_cli_command_t *c, unformat_input_t *input)
Definition: cli.c:89
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
vlib_cli_sub_command_t * sub_commands
Definition: cli.h:111
u8 ** argv
Definition: main.h:234
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
svmdb_client_t * c
static vlib_process_t * vlib_get_current_process(vlib_main_t *vm)
Definition: node_funcs.h:391
int elog_trace_graph_dispatch
Definition: main.h:198
int show_not_mp_safe
Definition: cli.c:1597
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
int vl_api_set_elog_trace_api_messages(int enable)
Definition: api_shared.c:1191
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
static void * clib_mem_set_heap(void *heap)
Definition: mem.h:268
static uword * clib_bitmap_andnot(uword *ai, uword *bi)
Logical operator across two bitmaps.
elog_main_t elog_main
Definition: main.h:193
static uword parent_path_len(char *path)
Definition: cli.c:1135
static clib_error_t * vlib_cli_init(vlib_main_t *vm)
Definition: cli.c:1763
#define ARRAY_LEN(x)
Definition: clib.h:66
uword ** bitmaps
Definition: cli.h:52
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:442
u32 n_total_events_disable_limit
When count reaches limit logging is disabled.
Definition: elog.h:139
string name[64]
Definition: ip.api:44
static void * clib_mem_get_heap(void)
Definition: mem.h:262
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
uword unformat_vlib_cli_sub_input(unformat_input_t *i, va_list *args)
Definition: cli.c:162
#define clib_elf_section_data_next(a, extra)
Definition: elf_clib.h:57
static clib_error_t * suspend_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1547
#define ASSERT(truth)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:852
u32 hit_counter
Definition: cli.h:130
char * long_help
Definition: cli.h:99
uword is_mp_safe
Definition: cli.h:108
char * path
Definition: cli.h:95
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
static int sort_cmds_by_path(void *a1, void *a2)
Definition: cli.c:1566
uword * sub_command_index_by_name
Definition: cli.h:114
u32 elog_trace_graph_circuit_node_index
Definition: main.h:200
#define vec_cmp(v1, v2)
Compare two vectors (only applicable to vectors of signed numbers).
Definition: vec.h:989
static uword pointer_to_uword(const void *p)
Definition: types.h:131
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
vl_api_ip4_address_t hi
Definition: arp.api:37
static vlib_cli_command_t * all_subs(vlib_cli_main_t *cm, vlib_cli_command_t *subs, u32 command_index)
Definition: cli.c:353
static uword clib_bitmap_count_set_bits(uword *ai)
Return the number of set bits in a bitmap.
Definition: bitmap.h:462
struct vlib_cli_command_t * next_cli_command
Definition: cli.h:127
#define hash_create_vec(elts, key_bytes, value_bytes)
Definition: hash.h:668
static uword unformat_vlib_cli_sub_command(unformat_input_t *i, va_list *args)
Definition: cli.c:205
u32 elog_string(elog_main_t *em, char *fmt,...)
add a string to the event-log string table
Definition: elog.c:562
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
uword unformat_vlib_enable_disable(unformat_input_t *input, va_list *args)
Definition: format.c:116
static u8 * format_vlib_cli_command_help(u8 *s, va_list *args)
Definition: cli.c:329
static void cli_recursive_walk(vlib_cli_walk_args_t *aa)
Definition: cli.c:1603
static uword vlib_cli_command_is_empty(vlib_cli_command_t *c)
Definition: cli.c:1288
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:1053
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
format_function_t format_cpu_uarch
Definition: cpu.h:411
#define clib_error_free(e)
Definition: error.h:86
unformat_function_t unformat_vlib_node
Definition: node_funcs.h:1147
#define hash_get_mem(h, key)
Definition: hash.h:269
static clib_error_t * elog_trace_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1438
vlib_cli_command_t * cli_command_registrations
Definition: cli.h:144
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1540
#define vec_foreach(var, vec)
Vector iterator.
Definition: file.h:51
vlib_cli_parse_position_t * sub_command_positions
Definition: cli.h:118
u32 n_total_events
Total number of events in buffer.
Definition: elog.h:135
u8 si
Definition: lisp_types.api:47
void() vlib_cli_output_function_t(uword arg, u8 *buffer, uword buffer_bytes)
Definition: cli.h:133
vlib_cli_output_function_t * output_function
Definition: node.h:613
u32 * sort_vector
Definition: cli.h:147
void clib_mem_trace(int enable)
Definition: mem_dlmalloc.c:454
import vnet interface_types api
Definition: sample.api:20
char * short_help
Definition: cli.h:98
static clib_error_t * restart_cmd_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1027
uword unformat_skip_white_space(unformat_input_t *input)
Definition: unformat.c:821
format_function_t format_cpu_model_name
Definition: cpu.h:412
DLMALLOC_EXPORT void * mspace_least_addr(mspace msp)
int elog_trace_graph_circuit
Definition: main.h:199
static uword * clib_bitmap_and(uword *ai, uword *bi)
Logical operator across two bitmaps.
vlib_cli_main_t * cm
Definition: cli.c:1594
u8 ** vlib_cli_get_possible_completions(u8 *str)
Definition: cli.c:236
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
u32 rule_index
Definition: cli.h:66
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171