FD.io VPP  v19.08.3-2-gbabecb413
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  {
216  vec_foreach (sr, c->sub_rules)
217  {
218  void **d;
219  r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
220  vec_add2 (cm->parse_rule_data, d, 1);
221  vec_reset_length (d[0]);
222  if (r->data_size)
223  d[0] = _vec_resize (d[0],
224  /* length increment */ 1,
225  r->data_size,
226  /* header_bytes */ 0,
227  /* data align */ sizeof (uword));
228  if (unformat_user (i, r->unformat_function, vm, d[0]))
229  {
230  *result = vec_elt_at_index (cm->commands, sr->command_index);
231  return 1;
232  }
233  }
234  }
235 
236  match_bitmap = vlib_cli_sub_command_match (c, i);
237  is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
238  index = ~0;
239  if (is_unique)
240  {
241  index = clib_bitmap_first_set (match_bitmap);
242  *result = get_sub_command (cm, c, index);
243  }
244  clib_bitmap_free (match_bitmap);
245 
246  return is_unique;
247 }
248 
249 static int
250 vlib_cli_cmp_strings (void *a1, void *a2)
251 {
252  u8 *c1 = *(u8 **) a1;
253  u8 *c2 = *(u8 **) a2;
254 
255  return vec_cmp (c1, c2);
256 }
257 
258 u8 **
260 {
263  vlib_main_t *vm = vlib_get_main ();
264  vlib_cli_main_t *vcm = &vm->cli_main;
265  uword *match_bitmap = 0;
266  uword index, is_unique, help_next_level;
267  u8 **result = 0;
268  unformat_input_t input;
269  unformat_init_vector (&input, vec_dup (str));
270  c = vec_elt_at_index (vcm->commands, 0);
271 
272  /* remove trailing whitespace, except for one of them */
273  while (vec_len (input.buffer) >= 2 &&
274  isspace (input.buffer[vec_len (input.buffer) - 1]) &&
275  isspace (input.buffer[vec_len (input.buffer) - 2]))
276  {
277  vec_del1 (input.buffer, vec_len (input.buffer) - 1);
278  }
279 
280  /* if input is empty, directly return list of root commands */
281  if (vec_len (input.buffer) == 0 ||
282  (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
283  {
284  vec_foreach (sc, c->sub_commands)
285  {
286  vec_add1 (result, (u8 *) sc->name);
287  }
288  goto done;
289  }
290 
291  /* add a trailing '?' so that vlib_cli_sub_command_match can find
292  * all commands starting with the input string */
293  vec_add1 (input.buffer, '?');
294 
295  while (1)
296  {
297  match_bitmap = vlib_cli_sub_command_match (c, &input);
298  /* no match: return no result */
299  if (match_bitmap == 0)
300  {
301  goto done;
302  }
303  is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
304  /* unique match: try to step one subcommand level further */
305  if (is_unique)
306  {
307  /* stop if no more input */
308  if (input.index >= vec_len (input.buffer) - 1)
309  {
310  break;
311  }
312 
313  index = clib_bitmap_first_set (match_bitmap);
314  c = get_sub_command (vcm, c, index);
315  clib_bitmap_free (match_bitmap);
316  continue;
317  }
318  /* multiple matches: stop here, return all matches */
319  break;
320  }
321 
322  /* remove trailing '?' */
323  vec_del1 (input.buffer, vec_len (input.buffer) - 1);
324 
325  /* if we have a space at the end of input, and a unique match,
326  * autocomplete the next level of subcommands */
327  help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
328  /* *INDENT-OFF* */
329  clib_bitmap_foreach(index, match_bitmap, {
330  if (help_next_level && is_unique) {
331  c = get_sub_command (vcm, c, index);
332  vec_foreach (sc, c->sub_commands) {
333  vec_add1 (result, (u8*) sc->name);
334  }
335  goto done; /* break doesn't work in this macro-loop */
336  }
337  sc = &c->sub_commands[index];
338  vec_add1(result, (u8*) sc->name);
339  });
340  /* *INDENT-ON* */
341 
342 done:
343  clib_bitmap_free (match_bitmap);
344  unformat_free (&input);
345 
346  if (result)
348  return result;
349 }
350 
351 static u8 *
352 format_vlib_cli_command_help (u8 * s, va_list * args)
353 {
354  vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
355  int is_long = va_arg (*args, int);
356  if (is_long && c->long_help)
357  s = format (s, "%s", c->long_help);
358  else if (c->short_help)
359  s = format (s, "%s", c->short_help);
360  else
361  s = format (s, "%v commands", c->path);
362  return s;
363 }
364 
365 static u8 *
366 format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
367 {
368  vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
369  return format (s, "<%U>", format_c_identifier, r->name);
370 }
371 
372 static u8 *
373 format_vlib_cli_path (u8 * s, va_list * args)
374 {
375  u8 *path = va_arg (*args, u8 *);
376  int i, in_rule;
377  in_rule = 0;
378  for (i = 0; i < vec_len (path); i++)
379  {
380  switch (path[i])
381  {
382  case '%':
383  in_rule = 1;
384  vec_add1 (s, '<'); /* start of <RULE> */
385  break;
386 
387  case '_':
388  /* _ -> space in rules. */
389  vec_add1 (s, in_rule ? ' ' : '_');
390  break;
391 
392  case ' ':
393  if (in_rule)
394  {
395  vec_add1 (s, '>'); /* end of <RULE> */
396  in_rule = 0;
397  }
398  vec_add1 (s, ' ');
399  break;
400 
401  default:
402  vec_add1 (s, path[i]);
403  break;
404  }
405  }
406 
407  if (in_rule)
408  vec_add1 (s, '>'); /* terminate <RULE> */
409 
410  return s;
411 }
412 
413 static vlib_cli_command_t *
415 {
416  vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
419 
420  if (c->function)
421  vec_add1 (subs, c[0]);
422 
423  vec_foreach (sr, c->sub_rules)
424  subs = all_subs (cm, subs, sr->command_index);
425  vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
426 
427  return subs;
428 }
429 
430 static int
431 vlib_cli_cmp_rule (void *a1, void *a2)
432 {
433  vlib_cli_sub_rule_t *r1 = a1;
434  vlib_cli_sub_rule_t *r2 = a2;
435 
436  return vec_cmp (r1->name, r2->name);
437 }
438 
439 static int
440 vlib_cli_cmp_command (void *a1, void *a2)
441 {
442  vlib_cli_command_t *c1 = a1;
443  vlib_cli_command_t *c2 = a2;
444 
445  return vec_cmp (c1->path, c2->path);
446 }
447 
448 static clib_error_t *
451  unformat_input_t * input,
452  uword parent_command_index)
453 {
454  vlib_cli_command_t *parent, *c;
455  clib_error_t *error = 0;
456  unformat_input_t sub_input;
457  u8 *string;
458  uword is_main_dispatch = cm == &vm->cli_main;
459 
460  parent = vec_elt_at_index (cm->commands, parent_command_index);
461  if (is_main_dispatch && unformat (input, "help"))
462  {
463  uword help_at_end_of_line, i;
464 
465  help_at_end_of_line =
467  while (1)
468  {
469  c = parent;
470  if (unformat_user
471  (input, unformat_vlib_cli_sub_command, vm, c, &parent))
472  ;
473 
474  else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
475  goto unknown;
476 
477  else
478  break;
479  }
480 
481  /* help SUB-COMMAND => long format help.
482  "help" at end of line: show all commands. */
483  if (!help_at_end_of_line)
485  /* is_long */ 1);
486 
487  else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
488  vlib_cli_output (vm, "%v: no sub-commands", c->path);
489 
490  else
491  {
493  vlib_cli_sub_rule_t *sr, *subs;
494 
495  subs = vec_dup (c->sub_rules);
496 
497  /* Add in rules if any. */
498  vec_foreach (sc, c->sub_commands)
499  {
500  vec_add2 (subs, sr, 1);
501  sr->name = sc->name;
502  sr->command_index = sc->index;
503  sr->rule_index = ~0;
504  }
505 
507 
508  for (i = 0; i < vec_len (subs); i++)
509  {
512 
513  d = vec_elt_at_index (cm->commands, subs[i].command_index);
514  r =
515  subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
516  subs
517  [i].rule_index) :
518  0;
519 
520  if (r)
522  (vm, " %-30U %U",
524  format_vlib_cli_command_help, d, /* is_long */ 0);
525  else
527  (vm, " %-30v %U",
528  subs[i].name,
529  format_vlib_cli_command_help, d, /* is_long */ 0);
530  }
531 
532  vec_free (subs);
533  }
534  }
535 
536  else if (is_main_dispatch
537  && (unformat (input, "choices") || unformat (input, "?")))
538  {
539  vlib_cli_command_t *sub, *subs;
540 
541  subs = all_subs (cm, 0, parent_command_index);
543  vec_foreach (sub, subs)
544  vlib_cli_output (vm, " %-40U %U",
546  format_vlib_cli_command_help, sub, /* is_long */ 0);
547  vec_free (subs);
548  }
549 
550  else if (unformat (input, "comment %v", &string))
551  {
552  vec_free (string);
553  }
554 
555  else if (unformat (input, "uncomment %U",
556  unformat_vlib_cli_sub_input, &sub_input))
557  {
558  error =
559  vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
560  parent_command_index);
561  unformat_free (&sub_input);
562  }
563  else if (unformat (input, "leak-check %U",
564  unformat_vlib_cli_sub_input, &sub_input))
565  {
566  u8 *leak_report;
568  {
569  void *oldheap;
571  clib_mem_trace (0);
572  clib_mem_set_heap (oldheap);
574  }
575  clib_mem_trace (1);
576  error =
577  vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
578  parent_command_index);
579  unformat_free (&sub_input);
580 
581  /* Otherwise, the clib_error_t shows up as a leak... */
582  if (error)
583  {
584  vlib_cli_output (vm, "%v", error->what);
585  clib_error_free (error);
586  error = 0;
587  }
588 
590  leak_report = format (0, "%U", format_mheap, clib_mem_get_heap (),
591  1 /* verbose, i.e. print leaks */ );
592  clib_mem_trace (0);
593  vlib_cli_output (vm, "%v", leak_report);
594  vec_free (leak_report);
595  }
596 
597  else
598  if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
599  {
600  unformat_input_t *si;
601  uword has_sub_commands =
602  vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
603 
604  si = input;
605  if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
606  si = &sub_input;
607 
608  if (has_sub_commands)
609  error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
610 
611  if (has_sub_commands && !error)
612  /* Found valid sub-command. */ ;
613 
614  else if (c->function)
615  {
616  clib_error_t *c_error;
617 
618  /* Skip white space for benefit of called function. */
620 
621  if (unformat (si, "?"))
622  {
623  vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
624  0);
625  }
626  else
627  {
629  {
630  /* *INDENT-OFF* */
631  ELOG_TYPE_DECLARE (e) =
632  {
633  .format = "cli-cmd: %s",
634  .format_args = "T4",
635  };
636  /* *INDENT-ON* */
637  struct
638  {
639  u32 c;
640  } *ed;
641  ed = ELOG_DATA (&vm->elog_main, e);
642  ed->c = elog_string (&vm->elog_main, "%v", c->path);
643  }
644 
645  if (!c->is_mp_safe)
647 
648  c->hit_counter++;
649  c_error = c->function (vm, si, c);
650 
651  if (!c->is_mp_safe)
653 
655  {
656  /* *INDENT-OFF* */
657  ELOG_TYPE_DECLARE (e) =
658  {
659  .format = "cli-cmd: %s %s",
660  .format_args = "T4T4",
661  };
662  /* *INDENT-ON* */
663  struct
664  {
665  u32 c, err;
666  } *ed;
667  ed = ELOG_DATA (&vm->elog_main, e);
668  ed->c = elog_string (&vm->elog_main, "%v", c->path);
669  if (c_error)
670  {
671  vec_add1 (c_error->what, 0);
672  ed->err = elog_string (&vm->elog_main,
673  (char *) c_error->what);
674  _vec_len (c_error->what) -= 1;
675  }
676  else
677  ed->err = elog_string (&vm->elog_main, "OK");
678  }
679 
680  if (c_error)
681  {
682  error =
683  clib_error_return (0, "%v: %v", c->path, c_error->what);
684  clib_error_free (c_error);
685  /* Free sub input. */
686  if (si != input)
687  unformat_free (si);
688 
689  return error;
690  }
691  }
692 
693  /* Free any previous error. */
694  clib_error_free (error);
695  }
696 
697  else if (!error)
698  error = clib_error_return (0, "%v: no sub-commands", c->path);
699 
700  /* Free sub input. */
701  if (si != input)
702  unformat_free (si);
703  }
704 
705  else
706  goto unknown;
707 
708  return error;
709 
710 unknown:
711  if (parent->path)
712  return clib_error_return (0, "%v: unknown input `%U'", parent->path,
713  format_unformat_error, input);
714  else
715  return clib_error_return (0, "unknown input `%U'", format_unformat_error,
716  input);
717 }
718 
719 
721  __attribute__ ((weak));
722 
723 void
725 {
726 }
727 
728 /* Process CLI input. */
729 int
731  unformat_input_t * input,
732  vlib_cli_output_function_t * function, uword function_arg)
733 {
735  vlib_cli_main_t *cm = &vm->cli_main;
736  clib_error_t *error;
737  vlib_cli_output_function_t *save_function;
738  uword save_function_arg;
739  int rv = 0;
740 
741  save_function = cp->output_function;
742  save_function_arg = cp->output_function_arg;
743 
744  cp->output_function = function;
745  cp->output_function_arg = function_arg;
746 
747  do
748  {
750  error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
751  0);
752  }
753  while (!error && !unformat (input, "%U", unformat_eof));
754 
755  if (error)
756  {
757  vlib_cli_output (vm, "%v", error->what);
758  vlib_unix_error_report (vm, error);
759  /* clib_error_return is unfortunately often called with a '0'
760  return code */
761  rv = error->code != 0 ? error->code : -1;
762  clib_error_free (error);
763  }
764 
765  cp->output_function = save_function;
766  cp->output_function_arg = save_function_arg;
767  return rv;
768 }
769 
770 /* Output to current CLI connection. */
771 void
772 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
773 {
775  va_list va;
776  u8 *s;
777 
778  va_start (va, fmt);
779  s = va_format (0, fmt, &va);
780  va_end (va);
781 
782  /* Terminate with \n if not present. */
783  if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
784  vec_add1 (s, '\n');
785 
786  if ((!cp) || (!cp->output_function))
787  fformat (stdout, "%v", s);
788  else
789  cp->output_function (cp->output_function_arg, s, vec_len (s));
790 
791  vec_free (s);
792 }
793 
794 void *vl_msg_push_heap (void) __attribute__ ((weak));
795 void *
797 {
798  return 0;
799 }
800 
801 void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
802 void
803 vl_msg_pop_heap (void *oldheap)
804 {
805 }
806 
807 void *vlib_stats_push_heap (void *) __attribute__ ((weak));
808 void *
809 vlib_stats_push_heap (void *notused)
810 {
811  return 0;
812 }
813 
814 static clib_error_t *
816  unformat_input_t * input, vlib_cli_command_t * cmd)
817 {
818  int verbose __attribute__ ((unused)) = 0;
819  int api_segment = 0, stats_segment = 0, main_heap = 0;
820  clib_error_t *error;
821  u32 index = 0;
823  uword was_enabled;
824 
825 
827  {
828  if (unformat (input, "verbose"))
829  verbose = 1;
830  else if (unformat (input, "api-segment"))
831  api_segment = 1;
832  else if (unformat (input, "stats-segment"))
833  stats_segment = 1;
834  else if (unformat (input, "main-heap"))
835  main_heap = 1;
836  else
837  {
838  error = clib_error_return (0, "unknown input `%U'",
839  format_unformat_error, input);
840  return error;
841  }
842  }
843 
844  if ((api_segment + stats_segment + main_heap) == 0)
845  return clib_error_return
846  (0, "Please supply one of api-segment, stats-segment or main-heap");
847 
848  if (api_segment)
849  {
850  void *oldheap = vl_msg_push_heap ();
851  was_enabled = clib_mem_trace_enable_disable (0);
852  u8 *s_in_svm =
853  format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
854  vl_msg_pop_heap (oldheap);
855  u8 *s = vec_dup (s_in_svm);
856 
857  oldheap = vl_msg_push_heap ();
858  vec_free (s_in_svm);
859  clib_mem_trace_enable_disable (was_enabled);
860  vl_msg_pop_heap (oldheap);
861  vlib_cli_output (vm, "API segment");
862  vlib_cli_output (vm, "%v", s);
863  vec_free (s);
864  }
865  if (stats_segment)
866  {
867  void *oldheap = vlib_stats_push_heap (0);
868  was_enabled = clib_mem_trace_enable_disable (0);
869  u8 *s_in_svm =
870  format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
871  if (oldheap)
872  clib_mem_set_heap (oldheap);
873  u8 *s = vec_dup (s_in_svm);
874 
875  oldheap = vlib_stats_push_heap (0);
876  vec_free (s_in_svm);
877  if (oldheap)
878  {
879  clib_mem_trace_enable_disable (was_enabled);
880  clib_mem_set_heap (oldheap);
881  }
882  vlib_cli_output (vm, "Stats segment");
883  vlib_cli_output (vm, "%v", s);
884  vec_free (s);
885  }
886 
887 #if USE_DLMALLOC == 0
888  /* *INDENT-OFF* */
890  ({
892  vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
893  vlib_worker_threads[index].name);
896  h->vm_alloc_size);
897  vlib_cli_output (vm, " %U\n", format_mheap, clib_per_cpu_mheaps[index],
898  verbose);
899  index++;
900  }));
901  /* *INDENT-ON* */
902 #else
903  {
904  if (main_heap)
905  {
906  /*
907  * Note: the foreach_vlib_main causes allocator traffic,
908  * so shut off tracing before we go there...
909  */
910  was_enabled = clib_mem_trace_enable_disable (0);
911 
912  /* *INDENT-OFF* */
914  ({
915  struct dlmallinfo mi;
916  void *mspace;
917  mspace = clib_per_cpu_mheaps[index];
918 
919  mi = mspace_mallinfo (mspace);
920  vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index,
921  vlib_worker_threads[index].name);
922  vlib_cli_output (vm, " %U\n", format_page_map,
924  mi.arena);
925  vlib_cli_output (vm, " %U\n", format_mheap,
926  clib_per_cpu_mheaps[index],
927  verbose);
928  index++;
929  }));
930  /* *INDENT-ON* */
931 
932  /* Restore the trace flag */
933  clib_mem_trace_enable_disable (was_enabled);
934  }
935  }
936 #endif /* USE_DLMALLOC */
937  return 0;
938 }
939 
940 /* *INDENT-OFF* */
941 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
942  .path = "show memory",
943  .short_help = "show memory [api-segment][stats-segment][verbose]",
944  .function = show_memory_usage,
945 };
946 /* *INDENT-ON* */
947 
948 static clib_error_t *
950  vlib_cli_command_t * cmd)
951 {
952 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
953  _("Model name", "%U", format_cpu_model_name);
954  _("Microarch model (family)", "%U", format_cpu_uarch);
955  _("Flags", "%U", format_cpu_flags);
956  _("Base frequency", "%.2f GHz",
957  ((f64) vm->clib_time.clocks_per_second) * 1e-9);
958 #undef _
959  return 0;
960 }
961 
962 /*?
963  * Displays various information about the CPU.
964  *
965  * @cliexpar
966  * @cliexstart{show cpu}
967  * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
968  * Microarchitecture: Broadwell (Broadwell-EP/EX)
969  * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
970  * Base Frequency: 3.20 GHz
971  * @cliexend
972 ?*/
973 /* *INDENT-OFF* */
974 VLIB_CLI_COMMAND (show_cpu_command, static) = {
975  .path = "show cpu",
976  .short_help = "Show cpu information",
977  .function = show_cpu,
978 };
979 /* *INDENT-ON* */
980 
981 static clib_error_t *
983  unformat_input_t * input,
984  vlib_cli_command_t * cmd)
985 {
986  unformat_input_t _line_input, *line_input = &_line_input;
987  int enable = 1;
988  int api_segment = 0;
989  int stats_segment = 0;
990  int main_heap = 0;
991  void *oldheap;
992 
993  if (!unformat_user (input, unformat_line_input, line_input))
994  return 0;
995 
996  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
997  {
998  if (unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
999  ;
1000  else if (unformat (line_input, "api-segment"))
1001  api_segment = 1;
1002  else if (unformat (line_input, "stats-segment"))
1003  stats_segment = 1;
1004  else if (unformat (line_input, "main-heap"))
1005  main_heap = 1;
1006  else
1007  {
1008  unformat_free (line_input);
1009  return clib_error_return (0, "invalid input");
1010  }
1011  }
1012  unformat_free (line_input);
1013 
1014  if ((api_segment + stats_segment + main_heap + (enable == 0)) == 0)
1015  {
1016  return clib_error_return
1017  (0, "Need one of main-heap, stats-segment or api-segment");
1018  }
1019 
1020  /* Turn off current trace, if any */
1021  if (current_traced_heap)
1022  {
1023  void *oldheap;
1025  clib_mem_trace (0);
1026  clib_mem_set_heap (oldheap);
1027  current_traced_heap = 0;
1028  }
1029 
1030  if (enable == 0)
1031  return 0;
1032 
1033  /* API segment */
1034  if (api_segment)
1035  {
1036  oldheap = vl_msg_push_heap ();
1038  clib_mem_trace (1);
1039  vl_msg_pop_heap (oldheap);
1040 
1041  }
1042 
1043  /* Stats segment */
1044  if (stats_segment)
1045  {
1046  oldheap = vlib_stats_push_heap (0);
1048  clib_mem_trace (stats_segment);
1049  /* We don't want to call vlib_stats_pop_heap... */
1050  if (oldheap)
1051  clib_mem_set_heap (oldheap);
1052  }
1053 
1054  /* main_heap */
1055  if (main_heap)
1056  {
1058  clib_mem_trace (main_heap);
1059  }
1060 
1061  return 0;
1062 }
1063 
1064 /* *INDENT-OFF* */
1065 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
1066  .path = "memory-trace",
1067  .short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n",
1068  .function = enable_disable_memory_trace,
1069 };
1070 /* *INDENT-ON* */
1071 
1072 
1073 static clib_error_t *
1075  vlib_cli_command_t * cmd)
1076 {
1077 #if USE_DLMALLOC == 0
1078  clib_error_t *error = 0;
1079  void *heap;
1080  mheap_t *mheap;
1081 
1082  if (unformat (input, "on"))
1083  {
1084  /* *INDENT-OFF* */
1086  heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
1087  mheap = mheap_header(heap);
1088  mheap->flags |= MHEAP_FLAG_VALIDATE;
1089  // Turn off small object cache because it delays detection of errors
1091  });
1092  /* *INDENT-ON* */
1093 
1094  }
1095  else if (unformat (input, "off"))
1096  {
1097  /* *INDENT-OFF* */
1099  heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
1100  mheap = mheap_header(heap);
1101  mheap->flags &= ~MHEAP_FLAG_VALIDATE;
1103  });
1104  /* *INDENT-ON* */
1105  }
1106  else if (unformat (input, "now"))
1107  {
1108  /* *INDENT-OFF* */
1110  heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
1111  mheap = mheap_header(heap);
1112  mheap_validate(heap);
1113  });
1114  /* *INDENT-ON* */
1115  vlib_cli_output (vm, "heap validation complete");
1116 
1117  }
1118  else
1119  {
1120  return clib_error_return (0, "unknown input `%U'",
1121  format_unformat_error, input);
1122  }
1123 
1124  return error;
1125 #else
1126  return clib_error_return (0, "unimplemented...");
1127 #endif /* USE_DLMALLOC */
1128 }
1129 
1130 /* *INDENT-OFF* */
1131 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
1132  .path = "test heap-validate",
1133  .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
1134  .function = test_heap_validate,
1135 };
1136 /* *INDENT-ON* */
1137 
1138 static clib_error_t *
1140  vlib_cli_command_t * cmd)
1141 {
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  pool_foreach(f, fm->file_pool,
1151  ({
1152  if (f->file_descriptor > 2)
1153  close(f->file_descriptor);
1154  }));
1155  /* *INDENT-ON* */
1156 
1157  /* Exec ourself */
1158  execve (vm->name, (char **) vm->argv, environ);
1159 
1160  return 0;
1161 }
1162 
1163 /* *INDENT-OFF* */
1164 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  {
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 vlib_cli_normalize_path (char *input, char **result)
1206 {
1207  char *i = input;
1208  char *s = 0;
1209  uword l = 0;
1210  uword index_of_last_space = ~0;
1211 
1212  while (*i != 0)
1213  {
1214  u8 c = *i++;
1215  /* Multiple white space -> single space. */
1216  switch (c)
1217  {
1218  case ' ':
1219  case '\t':
1220  case '\n':
1221  case '\r':
1222  if (l > 0 && s[l - 1] != ' ')
1223  {
1224  vec_add1 (s, ' ');
1225  l++;
1226  }
1227  break;
1228 
1229  default:
1230  if (l > 0 && s[l - 1] == ' ')
1231  index_of_last_space = vec_len (s);
1232  vec_add1 (s, c);
1233  l++;
1234  break;
1235  }
1236  }
1237 
1238  /* Remove any extra space at end. */
1239  if (l > 0 && s[l - 1] == ' ')
1240  _vec_len (s) -= 1;
1241 
1242  *result = s;
1243  return index_of_last_space;
1244 }
1245 
1247 parent_path_len (char *path)
1248 {
1249  word i;
1250  for (i = vec_len (path) - 1; i >= 0; i--)
1251  {
1252  if (path[i] == ' ')
1253  return i;
1254  }
1255  return ~0;
1256 }
1257 
1258 static void
1259 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  p = vec_elt_at_index (cm->commands, parent_index);
1267  c = vec_elt_at_index (cm->commands, child_index);
1268 
1269  l = parent_path_len (c->path);
1270  if (l == ~0)
1271  sub_name = vec_dup ((u8 *) c->path);
1272  else
1273  {
1274  ASSERT (l + 1 < vec_len (c->path));
1275  sub_name = 0;
1276  vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
1277  }
1278 
1279  if (sub_name[0] == '%')
1280  {
1281  uword *q;
1282  vlib_cli_sub_rule_t *sr;
1283 
1284  /* Remove %. */
1285  vec_delete (sub_name, 1, 0);
1286 
1287  if (!p->sub_rule_index_by_name)
1288  p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1289  sizeof (sub_name[0]),
1290  sizeof (uword));
1291  q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1292  if (q)
1293  {
1294  sr = vec_elt_at_index (p->sub_rules, q[0]);
1295  ASSERT (sr->command_index == child_index);
1296  return;
1297  }
1298 
1299  q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
1300  if (!q)
1301  {
1302  clib_error ("reference to unknown rule `%%%v' in path `%v'",
1303  sub_name, c->path);
1304  return;
1305  }
1306 
1307  hash_set_mem (p->sub_rule_index_by_name, sub_name,
1308  vec_len (p->sub_rules));
1309  vec_add2 (p->sub_rules, sr, 1);
1310  sr->name = sub_name;
1311  sr->rule_index = sr - p->sub_rules;
1312  sr->command_index = child_index;
1313  return;
1314  }
1315 
1316  if (!p->sub_command_index_by_name)
1317  p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1318  sizeof (c->path[0]),
1319  sizeof (uword));
1320 
1321  /* Check if sub-command has already been created. */
1322  if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1323  {
1324  vec_free (sub_name);
1325  return;
1326  }
1327 
1328  vec_add2 (p->sub_commands, sub_c, 1);
1329  sub_c->index = child_index;
1330  sub_c->name = sub_name;
1332  sub_c - p->sub_commands);
1333 
1334  vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1335  for (i = 0; i < vec_len (sub_c->name); i++)
1336  {
1337  int n;
1339 
1341 
1342  if (!pos->bitmaps)
1343  pos->min_char = sub_c->name[i];
1344 
1345  n = sub_c->name[i] - pos->min_char;
1346  if (n < 0)
1347  {
1348  pos->min_char = sub_c->name[i];
1349  vec_insert (pos->bitmaps, -n, 0);
1350  n = 0;
1351  }
1352 
1353  vec_validate (pos->bitmaps, n);
1354  pos->bitmaps[n] =
1355  clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
1356  }
1357 }
1358 
1359 static void
1361 {
1362  uword p_len, pi, *p;
1363  char *p_path;
1364  vlib_cli_command_t *c, *parent;
1365 
1366  /* Root command (index 0) should have already been added. */
1367  ASSERT (vec_len (cm->commands) > 0);
1368 
1369  c = vec_elt_at_index (cm->commands, ci);
1370  p_len = parent_path_len (c->path);
1371 
1372  /* No space? Parent is root command. */
1373  if (p_len == ~0)
1374  {
1375  add_sub_command (cm, 0, ci);
1376  return;
1377  }
1378 
1379  p_path = 0;
1380  vec_add (p_path, c->path, p_len);
1381 
1382  p = hash_get_mem (cm->command_index_by_path, p_path);
1383 
1384  /* Parent exists? */
1385  if (!p)
1386  {
1387  /* Parent does not exist; create it. */
1388  vec_add2 (cm->commands, parent, 1);
1389  parent->path = p_path;
1390  hash_set_mem (cm->command_index_by_path, parent->path,
1391  parent - cm->commands);
1392  pi = parent - cm->commands;
1393  }
1394  else
1395  {
1396  pi = p[0];
1397  vec_free (p_path);
1398  }
1399 
1400  add_sub_command (cm, pi, ci);
1401 
1402  /* Create parent's parent. */
1403  if (!p)
1404  vlib_cli_make_parent (cm, pi);
1405 }
1406 
1409 {
1410  return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1411 }
1412 
1413 clib_error_t *
1415 {
1416  vlib_cli_main_t *cm = &vm->cli_main;
1417  clib_error_t *error = 0;
1418  uword ci, *p;
1419  char *normalized_path;
1420 
1421  if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1422  return error;
1423 
1424  (void) vlib_cli_normalize_path (c->path, &normalized_path);
1425 
1426  if (!cm->command_index_by_path)
1427  cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1428  sizeof (c->path[0]),
1429  sizeof (uword));
1430 
1431  /* See if command already exists with given path. */
1432  p = hash_get_mem (cm->command_index_by_path, normalized_path);
1433  if (p)
1434  {
1435  vlib_cli_command_t *d;
1436 
1437  ci = p[0];
1438  d = vec_elt_at_index (cm->commands, ci);
1439 
1440  /* If existing command was created via vlib_cli_make_parent
1441  replaced it with callers data. */
1442  if (vlib_cli_command_is_empty (d))
1443  {
1444  vlib_cli_command_t save = d[0];
1445 
1447 
1448  /* Copy callers fields. */
1449  d[0] = c[0];
1450 
1451  /* Save internal fields. */
1452  d->path = save.path;
1453  d->sub_commands = save.sub_commands;
1456  d->sub_rules = save.sub_rules;
1457  }
1458  else
1459  error =
1460  clib_error_return (0, "duplicate command name with path %v",
1461  normalized_path);
1462 
1463  vec_free (normalized_path);
1464  if (error)
1465  return error;
1466  }
1467  else
1468  {
1469  /* Command does not exist: create it. */
1470 
1471  /* Add root command (index 0). */
1472  if (vec_len (cm->commands) == 0)
1473  {
1474  /* Create command with index 0; path is empty string. */
1475  vec_resize (cm->commands, 1);
1476  }
1477 
1478  ci = vec_len (cm->commands);
1479  hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1480  vec_add1 (cm->commands, c[0]);
1481 
1482  c = vec_elt_at_index (cm->commands, ci);
1483  c->path = normalized_path;
1484 
1485  /* Don't inherit from registration. */
1486  c->sub_commands = 0;
1488  c->sub_command_positions = 0;
1489  }
1490 
1491  vlib_cli_make_parent (cm, ci);
1492  return 0;
1493 }
1494 
1495 clib_error_t *
1497 {
1498  vlib_cli_main_t *cm = &vm->cli_main;
1500  clib_error_t *error = 0;
1501  u8 *r_name;
1502  uword *p;
1503 
1504  if (!cm->parse_rule_index_by_name)
1505  cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1506  sizeof (r->name[0]),
1507  sizeof (uword));
1508 
1509  /* Make vector copy of name. */
1510  r_name = format (0, "%s", r_reg->name);
1511 
1512  if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1513  {
1514  vec_free (r_name);
1515  return clib_error_return (0, "duplicate parse rule name `%s'",
1516  r_reg->name);
1517  }
1518 
1519  vec_add2 (cm->parse_rules, r, 1);
1520  r[0] = r_reg[0];
1521  r->name = (char *) r_name;
1523 
1524  return error;
1525 }
1526 
1527 #if 0
1528 /* $$$ turn back on again someday, maybe */
1529 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1531  lo,
1533  hi)
1534  __attribute__ ((unused))
1535 {
1536  clib_error_t *error = 0;
1538 
1539  for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1540  {
1541  if (!r->name || strlen (r->name) == 0)
1542  {
1543  error = clib_error_return (0, "parse rule with no name");
1544  goto done;
1545  }
1546 
1547  error = vlib_cli_register_parse_rule (vm, r);
1548  if (error)
1549  goto done;
1550  }
1551 
1552 done:
1553  return error;
1554 }
1555 #endif
1556 
1557 static clib_error_t *
1559  unformat_input_t * input, vlib_cli_command_t * cmd)
1560 {
1561  unformat_input_t _line_input, *line_input = &_line_input;
1562  int enable = 1;
1563  int api = 0, cli = 0, barrier = 0, dispatch = 0, circuit = 0;
1564  u32 circuit_node_index;
1565 
1566  if (!unformat_user (input, unformat_line_input, line_input))
1567  goto print_status;
1568 
1569  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1570  {
1571  if (unformat (line_input, "api"))
1572  api = 1;
1573  else if (unformat (line_input, "dispatch"))
1574  dispatch = 1;
1575  else if (unformat (line_input, "circuit-node %U",
1576  unformat_vlib_node, vm, &circuit_node_index))
1577  circuit = 1;
1578  else if (unformat (line_input, "cli"))
1579  cli = 1;
1580  else if (unformat (line_input, "barrier"))
1581  barrier = 1;
1582  else if (unformat (line_input, "disable"))
1583  enable = 0;
1584  else if (unformat (line_input, "enable"))
1585  enable = 1;
1586  else
1587  break;
1588  }
1589  unformat_free (line_input);
1590 
1592  (api ? enable : vl_api_get_elog_trace_api_messages ());
1593  vm->elog_trace_cli_commands = cli ? enable : vm->elog_trace_cli_commands;
1594  vm->elog_trace_graph_dispatch = dispatch ?
1595  enable : vm->elog_trace_graph_dispatch;
1596  vm->elog_trace_graph_circuit = circuit ?
1597  enable : vm->elog_trace_graph_circuit;
1599  barrier ? enable : vlib_worker_threads->barrier_elog_enabled;
1600  vm->elog_trace_graph_circuit_node_index = circuit_node_index;
1601 
1602  /*
1603  * Set up start-of-buffer logic-analyzer trigger
1604  * for main loop event logs, which are fairly heavyweight.
1605  * See src/vlib/main/vlib_elog_main_loop_event(...), which
1606  * will fully disable the scheme when the elog buffer fills.
1607  */
1608  if (dispatch || circuit)
1609  {
1610  elog_main_t *em = &vm->elog_main;
1611 
1613  em->n_total_events + vec_len (em->event_ring);
1614  }
1615 
1616 
1617 print_status:
1618  vlib_cli_output (vm, "Current status:");
1619 
1621  (vm, " Event log API message trace: %s\n CLI command trace: %s",
1622  vl_api_get_elog_trace_api_messages ()? "on" : "off",
1623  vm->elog_trace_cli_commands ? "on" : "off");
1625  (vm, " Barrier sync trace: %s",
1626  vlib_worker_threads->barrier_elog_enabled ? "on" : "off");
1628  (vm, " Graph Dispatch: %s",
1629  vm->elog_trace_graph_dispatch ? "on" : "off");
1631  (vm, " Graph Circuit: %s",
1632  vm->elog_trace_graph_circuit ? "on" : "off");
1633  if (vm->elog_trace_graph_circuit)
1635  (vm, " node %U",
1637 
1638  return 0;
1639 }
1640 
1641 /*?
1642  * Control event logging of api, cli, and thread barrier events
1643  * With no arguments, displays the current trace status.
1644  * Name the event groups you wish to trace or stop tracing.
1645  *
1646  * @cliexpar
1647  * @clistart
1648  * elog trace api cli barrier
1649  * elog trace api cli barrier disable
1650  * elog trace dispatch
1651  * elog trace circuit-node ethernet-input
1652  * elog trace
1653  * @cliend
1654  * @cliexcmd{elog trace [api][cli][barrier][disable]}
1655 ?*/
1656 /* *INDENT-OFF* */
1657 VLIB_CLI_COMMAND (elog_trace_command, static) =
1658 {
1659  .path = "elog trace",
1660  .short_help = "elog trace [api][cli][barrier][dispatch]\n"
1661  "[circuit-node <name> e.g. ethernet-input][disable]",
1662  .function = elog_trace_command_fn,
1663 };
1664 /* *INDENT-ON* */
1665 
1666 static clib_error_t *
1668  unformat_input_t * input, vlib_cli_command_t * cmd)
1669 {
1670  vlib_process_suspend (vm, 30e-3);
1671  return 0;
1672 }
1673 
1674 /* *INDENT-OFF* */
1675 VLIB_CLI_COMMAND (suspend_command, static) =
1676 {
1677  .path = "suspend",
1678  .short_help = "suspend debug CLI for 30ms",
1679  .function = suspend_command_fn,
1680  .is_mp_safe = 1,
1681 };
1682 /* *INDENT-ON* */
1683 
1684 
1685 static int
1686 sort_cmds_by_path (void *a1, void *a2)
1687 {
1688  u32 *index1 = a1;
1689  u32 *index2 = a2;
1690  vlib_main_t *vm = vlib_get_main ();
1691  vlib_cli_main_t *cm = &vm->cli_main;
1692  vlib_cli_command_t *c1, *c2;
1693  int i, lmin;
1694 
1695  c1 = vec_elt_at_index (cm->commands, *index1);
1696  c2 = vec_elt_at_index (cm->commands, *index2);
1697 
1698  lmin = vec_len (c1->path);
1699  lmin = (vec_len (c2->path) >= lmin) ? lmin : vec_len (c2->path);
1700 
1701  for (i = 0; i < lmin; i++)
1702  {
1703  if (c1->path[i] < c2->path[i])
1704  return -1;
1705  else if (c1->path[i] > c2->path[i])
1706  return 1;
1707  }
1708 
1709  return 0;
1710 }
1711 
1712 typedef struct
1713 {
1721 
1722 static void
1724 {
1725  vlib_cli_command_t *parent;
1727  vlib_cli_walk_args_t _a, *a = &_a;
1729  int i;
1730 
1731  /* Copy args into this stack frame */
1732  *a = *aa;
1733  cm = a->cm;
1734 
1735  parent = vec_elt_at_index (cm->commands, a->parent_command_index);
1736 
1737  if (parent->function)
1738  {
1739  if (((a->show_mp_safe && parent->is_mp_safe)
1740  || (a->show_not_mp_safe && !parent->is_mp_safe))
1741  && (a->show_hit == 0 || parent->hit_counter))
1742  {
1744  }
1745 
1746  if (a->clear_hit)
1747  parent->hit_counter = 0;
1748  }
1749 
1750  for (i = 0; i < vec_len (parent->sub_commands); i++)
1751  {
1752  sub = vec_elt_at_index (parent->sub_commands, i);
1753  a->parent_command_index = sub->index;
1754  cli_recursive_walk (a);
1755  }
1756 }
1757 
1758 static u8 *
1759 format_mp_safe (u8 * s, va_list * args)
1760 {
1761  vlib_cli_main_t *cm = va_arg (*args, vlib_cli_main_t *);
1762  int show_mp_safe = va_arg (*args, int);
1763  int show_not_mp_safe = va_arg (*args, int);
1764  int show_hit = va_arg (*args, int);
1765  int clear_hit = va_arg (*args, int);
1767  vlib_cli_walk_args_t _a, *a = &_a;
1768  int i;
1769  char *format_string = "\n%v";
1770 
1771  if (show_hit)
1772  format_string = "\n%v: %u";
1773 
1775 
1776  a->cm = cm;
1777  a->parent_command_index = 0;
1778  a->show_mp_safe = show_mp_safe;
1779  a->show_not_mp_safe = show_not_mp_safe;
1780  a->show_hit = show_hit;
1781  a->clear_hit = clear_hit;
1782 
1783  cli_recursive_walk (a);
1784 
1786 
1787  for (i = 0; i < vec_len (cm->sort_vector); i++)
1788  {
1789  c = vec_elt_at_index (cm->commands, cm->sort_vector[i]);
1790  s = format (s, format_string, c->path, c->hit_counter);
1791  }
1792 
1793  return s;
1794 }
1795 
1796 
1797 static clib_error_t *
1799  unformat_input_t * input, vlib_cli_command_t * cmd)
1800 {
1801  int show_mp_safe = 0;
1802  int show_not_mp_safe = 0;
1803  int show_hit = 0;
1804  int clear_hit = 0;
1805 
1806  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1807  {
1808  if (unformat (input, "mp-safe"))
1809  show_mp_safe = 1;
1810  if (unformat (input, "not-mp-safe"))
1811  show_not_mp_safe = 1;
1812  else if (unformat (input, "hit"))
1813  show_hit = 1;
1814  else if (unformat (input, "clear-hit"))
1815  clear_hit = 1;
1816  else
1817  break;
1818  }
1819 
1820  /* default set: all cli commands */
1821  if (clear_hit == 0 && (show_mp_safe + show_not_mp_safe) == 0)
1822  show_mp_safe = show_not_mp_safe = 1;
1823 
1824  vlib_cli_output (vm, "%U", format_mp_safe, &vm->cli_main,
1825  show_mp_safe, show_not_mp_safe, show_hit, clear_hit);
1826  if (clear_hit)
1827  vlib_cli_output (vm, "hit counters cleared...");
1828 
1829  return 0;
1830 }
1831 
1832 /*?
1833  * Displays debug cli command information
1834  *
1835  * @cliexpar
1836  * @cliexstart{show cli [mp-safe][not-mp-safe][hit][clear-hit]}
1837  *
1838  * "show cli" displays the entire debug cli:
1839  *
1840  * abf attach
1841  * abf policy
1842  * adjacency counters
1843  * api trace
1844  * app ns
1845  * bfd key del
1846  * ... and so on ...
1847  *
1848  * "show cli mp-safe" displays mp-safe debug CLI commands:
1849  *
1850  * abf policy
1851  * binary-api
1852  * create vhost-user
1853  * exec
1854  * ip container
1855  * ip mroute
1856  * ip probe-neighbor
1857  * ip route
1858  * ip scan-neighbor
1859  * ip table
1860  * ip6 table
1861  *
1862  * "show cli not-mp-safe" displays debug CLI commands
1863  * which cause worker thread barrier synchronization
1864  *
1865  * "show cli hit" displays commands which have been executed. Qualify
1866  * as desired with "mp-safe" or "not-mp-safe".
1867  *
1868  * "show cli clear-hit" clears the per-command hit counters.
1869  * @cliexend
1870 ?*/
1871 
1872 /* *INDENT-OFF* */
1873 VLIB_CLI_COMMAND (show_cli_command, static) =
1874 {
1875  .path = "show cli",
1876  .short_help = "show cli [mp-safe][not-mp-safe][hit][clear-hit]",
1877  .function = show_cli_command_fn,
1878  .is_mp_safe = 1,
1879 };
1880 /* *INDENT-ON* */
1881 
1882 static clib_error_t *
1884 {
1885  vlib_cli_main_t *cm = &vm->cli_main;
1886  clib_error_t *error = 0;
1887  vlib_cli_command_t *cmd;
1888 
1889  cmd = cm->cli_command_registrations;
1890 
1891  while (cmd)
1892  {
1893  error = vlib_cli_register (vm, cmd);
1894  if (error)
1895  return error;
1896  cmd = cmd->next_cli_command;
1897  }
1898  return error;
1899 }
1900 
1902 
1903 /*
1904  * fd.io coding-style-patch-verification: ON
1905  *
1906  * Local Variables:
1907  * eval: (c-set-style "gnu")
1908  * End:
1909  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
uword output_function_arg
Definition: node.h:612
void * vlib_stats_push_heap(void *)
Definition: cli.c:809
vmrglw vmrglh hi
unformat_function_t * unformat_function
Definition: cli.h:80
void * clib_per_cpu_mheaps[CLIB_MAX_MHEAPS]
Definition: mem_dlmalloc.c:23
static clib_error_t * show_cpu(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:949
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
uword data_size
Definition: cli.h:78
uword vm_alloc_offset_from_header
unformat_function_t unformat_eof
Definition: format.h:293
static u8 * format_vlib_cli_parse_rule_name(u8 *s, va_list *args)
Definition: cli.c:366
static clib_error_t * show_cli_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1798
static uword unformat_get_input(unformat_input_t *input)
Definition: format.h:192
int elog_trace_cli_commands
Definition: main.h:197
#define clib_error(format, args...)
Definition: error.h:62
u32 parent_command_index
Definition: cli.c:1715
vlib_cli_command_t * commands
Definition: cli.h:138
f64 clocks_per_second
Definition: time.h:54
format_function_t format_cpu_flags
Definition: cpu.h:391
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:560
int i
static uword parent_path_len(char *path)
Definition: cli.c:1247
static mheap_t * mheap_header(u8 *v)
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
DLMALLOC_EXPORT struct dlmallinfo mspace_mallinfo(mspace msp)
vlib_cli_main_t cli_main
Definition: main.h:161
static vlib_cli_command_t * all_subs(vlib_cli_main_t *cm, vlib_cli_command_t *subs, u32 command_index)
Definition: cli.c:414
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
#define fm
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:598
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
static clib_error_t * test_heap_validate(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1074
i64 word
Definition: types.h:111
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
MALLINFO_FIELD_TYPE arena
Definition: dlmalloc.h:800
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define always_inline
Definition: clib.h:99
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
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:242
unsigned int u32
Definition: types.h:88
#define vlib_call_init_function(vm, x)
Definition: init.h:270
static void add_sub_command(vlib_cli_main_t *cm, uword parent_index, uword child_index)
Definition: cli.c:1259
static uword unformat_vlib_cli_sub_command(unformat_input_t *i, va_list *args)
Definition: cli.c:205
static int vlib_cli_cmp_strings(void *a1, void *a2)
Definition: cli.c:250
uword clib_mem_trace_enable_disable(uword enable)
Definition: mem_dlmalloc.c:441
static int vlib_cli_cmp_rule(void *a1, void *a2)
Definition: cli.c:431
unformat_function_t unformat_line_input
Definition: format.h:283
u8 * format_c_identifier(u8 *s, va_list *va)
Definition: std-formats.c:274
u8 * format_mheap(u8 *s, va_list *va)
Definition: mem_dlmalloc.c:354
char * name
Definition: main.h:140
vnet_crypto_main_t * cm
Definition: quic_crypto.c:41
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:37
vlib_cli_parse_rule_t * parse_rules
Definition: cli.h:144
static clib_error_t * enable_disable_memory_trace(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:982
#define clib_bitmap_foreach(i, ai, body)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
static vlib_cli_command_t * get_sub_command(vlib_cli_main_t *cm, vlib_cli_command_t *parent, u32 si)
Definition: cli.c:198
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:685
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 clib_error_t * elog_trace_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1558
clib_error_t * vlib_cli_register_parse_rule(vlib_main_t *vm, vlib_cli_parse_rule_t *r_reg)
Definition: cli.c:1496
u8 ** vlib_cli_get_possible_completions(u8 *str)
Definition: cli.c:259
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
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:375
#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:112
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:804
static void unformat_put_input(unformat_input_t *input)
Definition: format.h:205
void vl_msg_pop_heap(void *oldheap)
Definition: cli.c:803
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:449
#define foreach_vlib_main(body)
Definition: threads.h:241
u8 name[64]
Definition: memclnt.api:152
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
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
static u8 * format_mp_safe(u8 *s, va_list *args)
Definition: cli.c:1759
int elog_trace_graph_dispatch
Definition: main.h:198
int show_not_mp_safe
Definition: cli.c:1717
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
void * vl_msg_push_heap(void)
Definition: cli.c:796
static void * clib_mem_set_heap(void *heap)
Definition: mem.h:290
static uword * clib_bitmap_andnot(uword *ai, uword *bi)
Logical operator across two bitmaps.
int vl_api_get_elog_trace_api_messages(void)
Definition: main.c:2006
elog_main_t elog_main
Definition: main.h:193
static void cli_recursive_walk(vlib_cli_walk_args_t *aa)
Definition: cli.c:1723
uword ** bitmaps
Definition: cli.h:52
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:442
static u8 * format_vlib_cli_command_help(u8 *s, va_list *args)
Definition: cli.c:352
u32 n_total_events_disable_limit
When count reaches limit logging is disabled.
Definition: elog.h:139
static uword * vlib_cli_sub_command_match(vlib_cli_command_t *c, unformat_input_t *input)
Definition: cli.c:89
static uword vlib_cli_command_is_empty(vlib_cli_command_t *c)
Definition: cli.c:1408
static void * clib_mem_get_heap(void)
Definition: mem.h:284
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:161
static int vlib_cli_cmp_command(void *a1, void *a2)
Definition: cli.c:440
#define clib_elf_section_data_next(a, extra)
Definition: elf_clib.h:57
static void vlib_cli_make_parent(vlib_cli_main_t *cm, uword ci)
Definition: cli.c:1360
#define ASSERT(truth)
static clib_error_t * vlib_cli_init(vlib_main_t *vm)
Definition: cli.c:1883
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:784
uword * parse_rule_index_by_name
Definition: cli.h:147
u32 hit_counter
Definition: cli.h:130
uword vm_alloc_size
char * long_help
Definition: cli.h:99
uword is_mp_safe
Definition: cli.h:108
#define MHEAP_FLAG_VALIDATE
char * path
Definition: cli.h:95
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
int vl_api_set_elog_trace_api_messages(int enable)
Definition: main.c:1998
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:919
int vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:730
static uword pointer_to_uword(const void *p)
Definition: types.h:131
static clib_error_t * show_memory_usage(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:815
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
#define MHEAP_FLAG_SMALL_OBJECT_CACHE
static uword clib_bitmap_count_set_bits(uword *ai)
Return the number of set bits in a bitmap.
Definition: bitmap.h:462
static int sort_cmds_by_path(void *a1, void *a2)
Definition: cli.c:1686
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 void * current_traced_heap
Definition: cli.c:53
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
uword unformat_vlib_cli_sub_input(unformat_input_t *i, va_list *args)
Definition: cli.c:162
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:983
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
void ** parse_rule_data
Definition: cli.h:150
format_function_t format_cpu_uarch
Definition: cpu.h:389
#define clib_error_free(e)
Definition: error.h:86
static clib_error_t * suspend_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1667
unformat_function_t unformat_vlib_node
Definition: node_funcs.h:1147
#define hash_get_mem(h, key)
Definition: hash.h:269
clib_error_t * vlib_cli_register(vlib_main_t *vm, vlib_cli_command_t *c)
Definition: cli.c:1414
vlib_cli_command_t * cli_command_registrations
Definition: cli.h:153
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
import vnet fib fib_types api
Definition: bier.api:23
void vlib_unix_error_report(vlib_main_t *, clib_error_t *)
Definition: cli.c:724
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1520
void mheap_validate(void *v)
Definition: mheap.c:1378
static clib_error_t * restart_cmd_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:1139
#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
static uword vlib_cli_normalize_path(char *input, char **result)
Definition: cli.c:1205
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:611
u32 * sort_vector
Definition: cli.h:156
void clib_mem_trace(int enable)
Definition: mem_dlmalloc.c:420
char * short_help
Definition: cli.h:98
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:772
uword unformat_skip_white_space(unformat_input_t *input)
Definition: unformat.c:821
format_function_t format_cpu_model_name
Definition: cpu.h:390
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.
static u8 * format_vlib_cli_path(u8 *s, va_list *args)
Definition: cli.c:373
vlib_cli_main_t * cm
Definition: cli.c:1714
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