FD.io VPP  v17.01.1-3-gc6833f8
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 <vppinfra/cpu.h>
42 
43 /* Root of all show commands. */
44 /* *INDENT-OFF* */
45 VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
46  .path = "show",
47  .short_help = "Show commands",
48 };
49 /* *INDENT-ON* */
50 
51 /* Root of all clear commands. */
52 /* *INDENT-OFF* */
53 VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
54  .path = "clear",
55  .short_help = "Clear commands",
56 };
57 /* *INDENT-ON* */
58 
59 /* Root of all set commands. */
60 /* *INDENT-OFF* */
61 VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
62  .path = "set",
63  .short_help = "Set commands",
64 };
65 /* *INDENT-ON* */
66 
67 /* Root of all test commands. */
68 /* *INDENT-OFF* */
69 VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
70  .path = "test",
71  .short_help = "Test commands",
72 };
73 /* *INDENT-ON* */
74 
75 /* Returns bitmap of commands which match key. */
76 static uword *
78 {
79  int i, n;
80  uword *match = 0;
82 
84 
85  for (i = 0;; i++)
86  {
87  uword k;
88 
89  k = unformat_get_input (input);
90  switch (k)
91  {
92  case 'a' ... 'z':
93  case 'A' ... 'Z':
94  case '0' ... '9':
95  case '-':
96  case '_':
97  break;
98 
99  case ' ':
100  case '\t':
101  case '\r':
102  case '\n':
104  /* White space or end of input removes any non-white
105  matches that were before possible. */
106  if (i < vec_len (c->sub_command_positions)
107  && clib_bitmap_count_set_bits (match) > 1)
108  {
110  for (n = 0; n < vec_len (p->bitmaps); n++)
111  match = clib_bitmap_andnot (match, p->bitmaps[n]);
112  }
113  goto done;
114 
115  default:
116  unformat_put_input (input);
117  goto done;
118  }
119 
120  if (i >= vec_len (c->sub_command_positions))
121  {
122  no_match:
123  clib_bitmap_free (match);
124  return 0;
125  }
126 
128  if (vec_len (p->bitmaps) == 0)
129  goto no_match;
130 
131  n = k - p->min_char;
132  if (n < 0 || n >= vec_len (p->bitmaps))
133  goto no_match;
134 
135  if (i == 0)
136  match = clib_bitmap_dup (p->bitmaps[n]);
137  else
138  match = clib_bitmap_and (match, p->bitmaps[n]);
139 
140  if (clib_bitmap_is_zero (match))
141  goto no_match;
142  }
143 
144 done:
145  return match;
146 }
147 
148 /* Looks for string based sub-input formatted { SUB-INPUT }. */
149 uword
151 {
152  unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
153  u8 *s;
154  uword c;
155 
156  while (1)
157  {
158  c = unformat_get_input (i);
159  switch (c)
160  {
161  case ' ':
162  case '\t':
163  case '\n':
164  case '\r':
165  case '\f':
166  break;
167 
168  case '{':
169  default:
170  /* Put back paren. */
171  if (c != UNFORMAT_END_OF_INPUT)
172  unformat_put_input (i);
173 
174  if (c == '{' && unformat (i, "%v", &s))
175  {
176  unformat_init_vector (sub_input, s);
177  return 1;
178  }
179  return 0;
180  }
181  }
182  return 0;
183 }
184 
185 static vlib_cli_command_t *
187 {
189  return vec_elt_at_index (cm->commands, s->index);
190 }
191 
192 static uword
194 {
195  vlib_main_t *vm = va_arg (*args, vlib_main_t *);
196  vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
197  vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
198  vlib_cli_main_t *cm = &vm->cli_main;
199  uword *match_bitmap, is_unique, index;
200 
201  {
204  vec_foreach (sr, c->sub_rules)
205  {
206  void **d;
207  r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
208  vec_add2 (cm->parse_rule_data, d, 1);
209  vec_reset_length (d[0]);
210  if (r->data_size)
211  d[0] = _vec_resize (d[0],
212  /* length increment */ 1,
213  r->data_size,
214  /* header_bytes */ 0,
215  /* data align */ sizeof (uword));
216  if (unformat_user (i, r->unformat_function, vm, d[0]))
217  {
218  *result = vec_elt_at_index (cm->commands, sr->command_index);
219  return 1;
220  }
221  }
222  }
223 
224  match_bitmap = vlib_cli_sub_command_match (c, i);
225  is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
226  index = ~0;
227  if (is_unique)
228  {
229  index = clib_bitmap_first_set (match_bitmap);
230  *result = get_sub_command (cm, c, index);
231  }
232  clib_bitmap_free (match_bitmap);
233 
234  return is_unique;
235 }
236 
237 static u8 *
238 format_vlib_cli_command_help (u8 * s, va_list * args)
239 {
240  vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
241  int is_long = va_arg (*args, int);
242  if (is_long && c->long_help)
243  s = format (s, "%s", c->long_help);
244  else if (c->short_help)
245  s = format (s, "%s", c->short_help);
246  else
247  s = format (s, "%v commands", c->path);
248  return s;
249 }
250 
251 static u8 *
252 format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
253 {
254  vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
255  return format (s, "<%U>", format_c_identifier, r->name);
256 }
257 
258 static u8 *
259 format_vlib_cli_path (u8 * s, va_list * args)
260 {
261  u8 *path = va_arg (*args, u8 *);
262  int i, in_rule;
263  in_rule = 0;
264  for (i = 0; i < vec_len (path); i++)
265  {
266  switch (path[i])
267  {
268  case '%':
269  in_rule = 1;
270  vec_add1 (s, '<'); /* start of <RULE> */
271  break;
272 
273  case '_':
274  /* _ -> space in rules. */
275  vec_add1 (s, in_rule ? ' ' : '_');
276  break;
277 
278  case ' ':
279  if (in_rule)
280  {
281  vec_add1 (s, '>'); /* end of <RULE> */
282  in_rule = 0;
283  }
284  vec_add1 (s, ' ');
285  break;
286 
287  default:
288  vec_add1 (s, path[i]);
289  break;
290  }
291  }
292 
293  if (in_rule)
294  vec_add1 (s, '>'); /* terminate <RULE> */
295 
296  return s;
297 }
298 
299 static vlib_cli_command_t *
300 all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
301 {
302  vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
305 
306  if (c->function)
307  vec_add1 (subs, c[0]);
308 
309  vec_foreach (sr, c->sub_rules)
310  subs = all_subs (cm, subs, sr->command_index);
311  vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
312 
313  return subs;
314 }
315 
316 static int
317 vlib_cli_cmp_rule (void *a1, void *a2)
318 {
319  vlib_cli_sub_rule_t *r1 = a1;
320  vlib_cli_sub_rule_t *r2 = a2;
321 
322  return vec_cmp (r1->name, r2->name);
323 }
324 
325 static int
326 vlib_cli_cmp_command (void *a1, void *a2)
327 {
328  vlib_cli_command_t *c1 = a1;
329  vlib_cli_command_t *c2 = a2;
330 
331  return vec_cmp (c1->path, c2->path);
332 }
333 
334 static clib_error_t *
336  vlib_cli_main_t * cm,
337  unformat_input_t * input,
338  uword parent_command_index)
339 {
340  vlib_cli_command_t *parent, *c;
341  clib_error_t *error = 0;
342  unformat_input_t sub_input;
343  u8 *string;
344  uword is_main_dispatch = cm == &vm->cli_main;
345 
346  parent = vec_elt_at_index (cm->commands, parent_command_index);
347  if (is_main_dispatch && unformat (input, "help"))
348  {
349  uword help_at_end_of_line, i;
350 
351  help_at_end_of_line =
353  while (1)
354  {
355  c = parent;
356  if (unformat_user
357  (input, unformat_vlib_cli_sub_command, vm, c, &parent))
358  ;
359 
360  else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
361  goto unknown;
362 
363  else
364  break;
365  }
366 
367  /* help SUB-COMMAND => long format help.
368  "help" at end of line: show all commands. */
369  if (!help_at_end_of_line)
371  /* is_long */ 1);
372 
373  else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
374  vlib_cli_output (vm, "%v: no sub-commands", c->path);
375 
376  else
377  {
379  vlib_cli_sub_rule_t *sr, *subs;
380 
381  subs = vec_dup (c->sub_rules);
382 
383  /* Add in rules if any. */
384  vec_foreach (sc, c->sub_commands)
385  {
386  vec_add2 (subs, sr, 1);
387  sr->name = sc->name;
388  sr->command_index = sc->index;
389  sr->rule_index = ~0;
390  }
391 
393 
394  for (i = 0; i < vec_len (subs); i++)
395  {
398 
399  d = vec_elt_at_index (cm->commands, subs[i].command_index);
400  r =
401  subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
402  subs
403  [i].rule_index) :
404  0;
405 
406  if (r)
408  (vm, " %-30U %U",
410  format_vlib_cli_command_help, d, /* is_long */ 0);
411  else
413  (vm, " %-30v %U",
414  subs[i].name,
415  format_vlib_cli_command_help, d, /* is_long */ 0);
416  }
417 
418  vec_free (subs);
419  }
420  }
421 
422  else if (is_main_dispatch
423  && (unformat (input, "choices") || unformat (input, "?")))
424  {
425  vlib_cli_command_t *sub, *subs;
426 
427  subs = all_subs (cm, 0, parent_command_index);
429  vec_foreach (sub, subs)
430  vlib_cli_output (vm, " %-40U %U",
432  format_vlib_cli_command_help, sub, /* is_long */ 0);
433  vec_free (subs);
434  }
435 
436  else if (unformat (input, "comment %v", &string))
437  {
438  vec_free (string);
439  }
440 
441  else if (unformat (input, "uncomment %U",
442  unformat_vlib_cli_sub_input, &sub_input))
443  {
444  error =
445  vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
446  parent_command_index);
447  unformat_free (&sub_input);
448  }
449 
450  else
451  if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
452  {
453  unformat_input_t *si;
454  uword has_sub_commands =
455  vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
456 
457  si = input;
458  if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
459  si = &sub_input;
460 
461  if (has_sub_commands)
462  error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
463 
464  if (has_sub_commands && !error)
465  /* Found valid sub-command. */ ;
466 
467  else if (c->function)
468  {
469  clib_error_t *c_error;
470 
471  /* Skip white space for benefit of called function. */
473 
474  if (unformat (si, "?"))
475  {
476  vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */
477  0);
478  }
479  else
480  {
481  if (!c->is_mp_safe)
483 
484  c_error = c->function (vm, si, c);
485 
486  if (!c->is_mp_safe)
488 
489  if (c_error)
490  {
491  error =
492  clib_error_return (0, "%v: %v", c->path, c_error->what);
493  clib_error_free (c_error);
494  /* Free sub input. */
495  if (si != input)
496  unformat_free (si);
497 
498  return error;
499  }
500  }
501 
502  /* Free any previous error. */
503  clib_error_free (error);
504  }
505 
506  else if (!error)
507  error = clib_error_return (0, "%v: no sub-commands", c->path);
508 
509  /* Free sub input. */
510  if (si != input)
511  unformat_free (si);
512  }
513 
514  else
515  goto unknown;
516 
517  return error;
518 
519 unknown:
520  if (parent->path)
521  return clib_error_return (0, "%v: unknown input `%U'", parent->path,
522  format_unformat_error, input);
523  else
524  return clib_error_return (0, "unknown input `%U'", format_unformat_error,
525  input);
526 }
527 
528 
530  __attribute__ ((weak));
531 
532 void
534 {
535 }
536 
537 /* Process CLI input. */
538 void
540  unformat_input_t * input,
541  vlib_cli_output_function_t * function, uword function_arg)
542 {
544  vlib_cli_main_t *cm = &vm->cli_main;
545  clib_error_t *error;
546  vlib_cli_output_function_t *save_function;
547  uword save_function_arg;
548 
549  save_function = cp->output_function;
550  save_function_arg = cp->output_function_arg;
551 
552  cp->output_function = function;
553  cp->output_function_arg = function_arg;
554 
555  do
556  {
558  error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
559  0);
560  }
561  while (!error && !unformat (input, "%U", unformat_eof));
562 
563  if (error)
564  {
565  vlib_cli_output (vm, "%v", error->what);
566  vlib_unix_error_report (vm, error);
567  clib_error_free (error);
568  }
569 
570  cp->output_function = save_function;
571  cp->output_function_arg = save_function_arg;
572 }
573 
574 /* Output to current CLI connection. */
575 void
576 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
577 {
579  va_list va;
580  u8 *s;
581 
582  va_start (va, fmt);
583  s = va_format (0, fmt, &va);
584  va_end (va);
585 
586  /* Terminate with \n if not present. */
587  if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
588  vec_add1 (s, '\n');
589 
590  if ((!cp) || (!cp->output_function))
591  fformat (stdout, "%v", s);
592  else
593  cp->output_function (cp->output_function_arg, s, vec_len (s));
594 
595  vec_free (s);
596 }
597 
598 static clib_error_t *
600  unformat_input_t * input, vlib_cli_command_t * cmd)
601 {
602  int verbose = 0;
603  clib_error_t *error;
604  u32 index = 0;
605 
607  {
608  if (unformat (input, "verbose"))
609  verbose = 1;
610  else
611  {
612  error = clib_error_return (0, "unknown input `%U'",
613  format_unformat_error, input);
614  return error;
615  }
616  }
617 
618  /* *INDENT-OFF* */
620  ({
621  vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
622  vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
623  index++;
624  }));
625  /* *INDENT-ON* */
626  return 0;
627 }
628 
629 /* *INDENT-OFF* */
630 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
631  .path = "show memory",
632  .short_help = "Show current memory usage",
633  .function = show_memory_usage,
634 };
635 /* *INDENT-ON* */
636 
637 static clib_error_t *
639  vlib_cli_command_t * cmd)
640 {
641 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
642  _("Model name", "%U", format_cpu_model_name);
643  _("Microarchitecture", "%U", format_cpu_uarch);
644  _("Flags", "%U", format_cpu_flags);
645  _("Base frequency", "%.2f GHz",
646  ((f64) vm->clib_time.clocks_per_second) * 1e-9);
647 #undef _
648  return 0;
649 }
650 
651 /*?
652  * Displays various information about the CPU.
653  *
654  * @cliexpar
655  * @cliexstart{show cpu}
656  * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
657  * Microarchitecture: Broadwell (Broadwell-EP/EX)
658  * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes
659  * Base Frequency: 3.20 GHz
660  * @cliexend
661 ?*/
662 /* *INDENT-OFF* */
663 VLIB_CLI_COMMAND (show_cpu_command, static) = {
664  .path = "show cpu",
665  .short_help = "Show cpu information",
666  .function = show_cpu,
667 };
668 
669 /* *INDENT-ON* */
670 static clib_error_t *
672  unformat_input_t * input,
673  vlib_cli_command_t * cmd)
674 {
675  clib_error_t *error = 0;
676  int enable;
677 
678  if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
679  {
680  error = clib_error_return (0, "expecting enable/on or disable/off");
681  goto done;
682  }
683 
684  clib_mem_trace (enable);
685 
686 done:
687  return error;
688 }
689 
690 /* *INDENT-OFF* */
691 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
692  .path = "memory-trace",
693  .short_help = "Enable/disable memory allocation trace",
694  .function = enable_disable_memory_trace,
695 };
696 /* *INDENT-ON* */
697 
698 
699 static clib_error_t *
701  vlib_cli_command_t * cmd)
702 {
703  clib_error_t *error = 0;
704  void *heap;
705  mheap_t *mheap;
706 
707  if (unformat (input, "on"))
708  {
709  /* *INDENT-OFF* */
711  heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
712  mheap = mheap_header(heap);
713  mheap->flags |= MHEAP_FLAG_VALIDATE;
714  // Turn off small object cache because it delays detection of errors
716  });
717  /* *INDENT-ON* */
718 
719  }
720  else if (unformat (input, "off"))
721  {
722  /* *INDENT-OFF* */
724  heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
725  mheap = mheap_header(heap);
726  mheap->flags &= ~MHEAP_FLAG_VALIDATE;
728  });
729  /* *INDENT-ON* */
730  }
731  else if (unformat (input, "now"))
732  {
733  /* *INDENT-OFF* */
735  heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
736  mheap = mheap_header(heap);
737  mheap_validate(heap);
738  });
739  /* *INDENT-ON* */
740  vlib_cli_output (vm, "heap validation complete");
741 
742  }
743  else
744  {
745  return clib_error_return (0, "unknown input `%U'",
746  format_unformat_error, input);
747  }
748 
749  return error;
750 }
751 
752 /* *INDENT-OFF* */
753 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
754  .path = "test heap-validate",
755  .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
756  .function = test_heap_validate,
757 };
758 /* *INDENT-ON* */
759 
760 #ifdef TEST_CODE
761 /*
762  * A trivial test harness to verify the per-process output_function
763  * is working correcty.
764  */
765 
766 static clib_error_t *
767 sleep_ten_seconds (vlib_main_t * vm,
768  unformat_input_t * input, vlib_cli_command_t * cmd)
769 {
770  u16 i;
771  u16 my_id = rand ();
772 
773  vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
774 
775  for (i = 0; i < 10; i++)
776  {
778  vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
779  }
780  vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
781  return 0;
782 }
783 
784 /* *INDENT-OFF* */
785 VLIB_CLI_COMMAND (ping_command, static) = {
786  .path = "test sleep",
787  .function = sleep_ten_seconds,
788  .short_help = "Sleep for 10 seconds",
789 };
790 /* *INDENT-ON* */
791 #endif /* ifdef TEST_CODE */
792 
793 static uword
794 vlib_cli_normalize_path (char *input, char **result)
795 {
796  char *i = input;
797  char *s = 0;
798  uword l = 0;
799  uword index_of_last_space = ~0;
800 
801  while (*i != 0)
802  {
803  u8 c = *i++;
804  /* Multiple white space -> single space. */
805  switch (c)
806  {
807  case ' ':
808  case '\t':
809  case '\n':
810  case '\r':
811  if (l > 0 && s[l - 1] != ' ')
812  {
813  vec_add1 (s, ' ');
814  l++;
815  }
816  break;
817 
818  default:
819  if (l > 0 && s[l - 1] == ' ')
820  index_of_last_space = vec_len (s);
821  vec_add1 (s, c);
822  l++;
823  break;
824  }
825  }
826 
827  /* Remove any extra space at end. */
828  if (l > 0 && s[l - 1] == ' ')
829  _vec_len (s) -= 1;
830 
831  *result = s;
832  return index_of_last_space;
833 }
834 
836 parent_path_len (char *path)
837 {
838  word i;
839  for (i = vec_len (path) - 1; i >= 0; i--)
840  {
841  if (path[i] == ' ')
842  return i;
843  }
844  return ~0;
845 }
846 
847 static void
848 add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
849 {
850  vlib_cli_command_t *p, *c;
851  vlib_cli_sub_command_t *sub_c;
852  u8 *sub_name;
853  word i, l;
854 
855  p = vec_elt_at_index (cm->commands, parent_index);
856  c = vec_elt_at_index (cm->commands, child_index);
857 
858  l = parent_path_len (c->path);
859  if (l == ~0)
860  sub_name = vec_dup ((u8 *) c->path);
861  else
862  {
863  ASSERT (l + 1 < vec_len (c->path));
864  sub_name = 0;
865  vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
866  }
867 
868  if (sub_name[0] == '%')
869  {
870  uword *q;
872 
873  /* Remove %. */
874  vec_delete (sub_name, 1, 0);
875 
876  if (!p->sub_rule_index_by_name)
877  p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
878  sizeof (sub_name[0]),
879  sizeof (uword));
880  q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
881  if (q)
882  {
883  sr = vec_elt_at_index (p->sub_rules, q[0]);
884  ASSERT (sr->command_index == child_index);
885  return;
886  }
887 
888  q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
889  if (!q)
890  {
891  clib_error ("reference to unknown rule `%%%v' in path `%v'",
892  sub_name, c->path);
893  return;
894  }
895 
896  hash_set_mem (p->sub_rule_index_by_name, sub_name,
897  vec_len (p->sub_rules));
898  vec_add2 (p->sub_rules, sr, 1);
899  sr->name = sub_name;
900  sr->rule_index = q[0];
901  sr->command_index = child_index;
902  return;
903  }
904 
906  p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
907  sizeof (c->path[0]),
908  sizeof (uword));
909 
910  /* Check if sub-command has already been created. */
911  if (hash_get_mem (p->sub_command_index_by_name, sub_name))
912  {
913  vec_free (sub_name);
914  return;
915  }
916 
917  vec_add2 (p->sub_commands, sub_c, 1);
918  sub_c->index = child_index;
919  sub_c->name = sub_name;
921  sub_c - p->sub_commands);
922 
923  vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
924  for (i = 0; i < vec_len (sub_c->name); i++)
925  {
926  int n;
928 
930 
931  if (!pos->bitmaps)
932  pos->min_char = sub_c->name[i];
933 
934  n = sub_c->name[i] - pos->min_char;
935  if (n < 0)
936  {
937  pos->min_char = sub_c->name[i];
938  vec_insert (pos->bitmaps, -n, 0);
939  n = 0;
940  }
941 
942  vec_validate (pos->bitmaps, n);
943  pos->bitmaps[n] =
944  clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
945  }
946 }
947 
948 static void
950 {
951  uword p_len, pi, *p;
952  char *p_path;
953  vlib_cli_command_t *c, *parent;
954 
955  /* Root command (index 0) should have already been added. */
956  ASSERT (vec_len (cm->commands) > 0);
957 
958  c = vec_elt_at_index (cm->commands, ci);
959  p_len = parent_path_len (c->path);
960 
961  /* No space? Parent is root command. */
962  if (p_len == ~0)
963  {
964  add_sub_command (cm, 0, ci);
965  return;
966  }
967 
968  p_path = 0;
969  vec_add (p_path, c->path, p_len);
970 
971  p = hash_get_mem (cm->command_index_by_path, p_path);
972 
973  /* Parent exists? */
974  if (!p)
975  {
976  /* Parent does not exist; create it. */
977  vec_add2 (cm->commands, parent, 1);
978  parent->path = p_path;
980  parent - cm->commands);
981  pi = parent - cm->commands;
982  }
983  else
984  {
985  pi = p[0];
986  vec_free (p_path);
987  }
988 
989  add_sub_command (cm, pi, ci);
990 
991  /* Create parent's parent. */
992  if (!p)
993  vlib_cli_make_parent (cm, pi);
994 }
995 
998 {
999  return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1000 }
1001 
1002 clib_error_t *
1004 {
1005  vlib_cli_main_t *cm = &vm->cli_main;
1006  clib_error_t *error = 0;
1007  uword ci, *p;
1008  char *normalized_path;
1009 
1010  if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1011  return error;
1012 
1013  (void) vlib_cli_normalize_path (c->path, &normalized_path);
1014 
1015  if (!cm->command_index_by_path)
1016  cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1017  sizeof (c->path[0]),
1018  sizeof (uword));
1019 
1020  /* See if command already exists with given path. */
1021  p = hash_get_mem (cm->command_index_by_path, normalized_path);
1022  if (p)
1023  {
1024  vlib_cli_command_t *d;
1025 
1026  ci = p[0];
1027  d = vec_elt_at_index (cm->commands, ci);
1028 
1029  /* If existing command was created via vlib_cli_make_parent
1030  replaced it with callers data. */
1031  if (vlib_cli_command_is_empty (d))
1032  {
1033  vlib_cli_command_t save = d[0];
1034 
1036 
1037  /* Copy callers fields. */
1038  d[0] = c[0];
1039 
1040  /* Save internal fields. */
1041  d->path = save.path;
1042  d->sub_commands = save.sub_commands;
1045  d->sub_rules = save.sub_rules;
1046  }
1047  else
1048  error =
1049  clib_error_return (0, "duplicate command name with path %v",
1050  normalized_path);
1051 
1052  vec_free (normalized_path);
1053  if (error)
1054  return error;
1055  }
1056  else
1057  {
1058  /* Command does not exist: create it. */
1059 
1060  /* Add root command (index 0). */
1061  if (vec_len (cm->commands) == 0)
1062  {
1063  /* Create command with index 0; path is empty string. */
1064  vec_resize (cm->commands, 1);
1065  }
1066 
1067  ci = vec_len (cm->commands);
1068  hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1069  vec_add1 (cm->commands, c[0]);
1070 
1071  c = vec_elt_at_index (cm->commands, ci);
1072  c->path = normalized_path;
1073 
1074  /* Don't inherit from registration. */
1075  c->sub_commands = 0;
1077  c->sub_command_positions = 0;
1078  }
1079 
1080  vlib_cli_make_parent (cm, ci);
1081  return 0;
1082 }
1083 
1084 clib_error_t *
1086 {
1087  vlib_cli_main_t *cm = &vm->cli_main;
1089  clib_error_t *error = 0;
1090  u8 *r_name;
1091  uword *p;
1092 
1093  if (!cm->parse_rule_index_by_name)
1094  cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1095  sizeof (r->name[0]),
1096  sizeof (uword));
1097 
1098  /* Make vector copy of name. */
1099  r_name = format (0, "%s", r_reg->name);
1100 
1101  if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1102  {
1103  vec_free (r_name);
1104  return clib_error_return (0, "duplicate parse rule name `%s'",
1105  r_reg->name);
1106  }
1107 
1108  vec_add2 (cm->parse_rules, r, 1);
1109  r[0] = r_reg[0];
1110  r->name = (char *) r_name;
1112 
1113  return error;
1114 }
1115 
1116 #if 0
1117 /* $$$ turn back on again someday, maybe */
1118 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1120  lo,
1122  hi)
1123  __attribute__ ((unused))
1124 {
1125  clib_error_t *error = 0;
1127 
1128  for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1129  {
1130  if (!r->name || strlen (r->name) == 0)
1131  {
1132  error = clib_error_return (0, "parse rule with no name");
1133  goto done;
1134  }
1135 
1136  error = vlib_cli_register_parse_rule (vm, r);
1137  if (error)
1138  goto done;
1139  }
1140 
1141 done:
1142  return error;
1143 }
1144 #endif
1145 
1146 static clib_error_t *
1148 {
1149  vlib_cli_main_t *cm = &vm->cli_main;
1150  clib_error_t *error = 0;
1151  vlib_cli_command_t *cmd;
1152 
1153  cmd = cm->cli_command_registrations;
1154 
1155  while (cmd)
1156  {
1157  error = vlib_cli_register (vm, cmd);
1158  if (error)
1159  return error;
1160  cmd = cmd->next_cli_command;
1161  }
1162  return error;
1163 }
1164 
1166 
1167 /*
1168  * fd.io coding-style-patch-verification: ON
1169  *
1170  * Local Variables:
1171  * eval: (c-set-style "gnu")
1172  * End:
1173  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
uword output_function_arg
Definition: node.h:543
static void add_sub_command(vlib_cli_main_t *cm, uword parent_index, uword child_index)
Definition: cli.c:848
vmrglw vmrglh hi
unformat_function_t * unformat_function
Definition: cli.h:80
static clib_error_t * vlib_cli_init(vlib_main_t *vm)
Definition: cli.c:1147
void unformat_init_vector(unformat_input_t *input, u8 *vector_string)
Definition: unformat.c:1025
static vlib_cli_command_t * all_subs(vlib_cli_main_t *cm, vlib_cli_command_t *subs, u32 command_index)
Definition: cli.c:300
static uword unformat_get_input(unformat_input_t *input)
Definition: format.h:190
static int vlib_cli_cmp_command(void *a1, void *a2)
Definition: cli.c:326
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
void * clib_per_cpu_mheaps[CLIB_MAX_MHEAPS]
Definition: mem_mheap.c:46
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
foreach_x86_64_flags format_function_t format_cpu_uarch
Definition: cpu.h:102
static uword vlib_cli_normalize_path(char *input, char **result)
Definition: cli.c:794
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:684
static vlib_cli_command_t * get_sub_command(vlib_cli_main_t *cm, vlib_cli_command_t *parent, u32 si)
Definition: cli.c:186
uword data_size
Definition: cli.h:78
u8 * va_format(u8 *s, const char *fmt, va_list *va)
Definition: format.c:386
clib_error_t * vlib_cli_register_parse_rule(vlib_main_t *vm, vlib_cli_parse_rule_t *r_reg)
Definition: cli.c:1085
vlib_cli_command_t * commands
Definition: cli.h:136
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
f64 clocks_per_second
Definition: time.h:53
static uword vlib_cli_command_is_empty(vlib_cli_command_t *c)
Definition: cli.c:997
uword unformat_vlib_cli_sub_input(unformat_input_t *i, va_list *args)
Definition: cli.c:150
#define clib_error(format, args...)
Definition: error.h:62
format_function_t format_cpu_flags
Definition: cpu.h:104
add_epi add_epi sub
Definition: vector_sse2.h:289
u8 * format_c_identifier(u8 *s, va_list *va)
Definition: std-formats.c:258
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
static mheap_t * mheap_header(u8 *v)
static void unformat_put_input(unformat_input_t *input)
Definition: format.h:203
uword * sub_rule_index_by_name
Definition: cli.h:121
#define hash_set_mem(h, key, value)
Definition: hash.h:274
clib_time_t clib_time
Definition: main.h:62
vlib_cli_main_t cli_main
Definition: main.h:118
u8 * format_mheap(u8 *s, va_list *va)
Definition: mheap.c:1168
#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.
u8 * what
Definition: error.h:78
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:559
static clib_error_t * test_heap_validate(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:700
static uword parent_path_len(char *path)
Definition: cli.c:836
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
#define always_inline
Definition: clib.h:84
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.
uword * command_index_by_path
Definition: cli.h:139
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
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:201
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
#define vlib_call_init_function(vm, x)
Definition: init.h:161
static void vlib_cli_make_parent(vlib_cli_main_t *cm, uword ci)
Definition: cli.c:949
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:54
vlib_cli_parse_rule_t * parse_rules
Definition: cli.h:142
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:646
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
uword unformat_skip_white_space(unformat_input_t *input)
Definition: unformat.c:809
clib_error_t * vlib_cli_register(vlib_main_t *vm, vlib_cli_command_t *c)
Definition: cli.c:1003
vlib_cli_sub_rule_t * sub_rules
Definition: cli.h:124
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:334
#define foreach_vlib_main(body)
Definition: threads.h:225
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
unformat_function_t unformat_eof
Definition: format.h:291
vlib_cli_sub_command_t * sub_commands
Definition: cli.h:111
svmdb_client_t * c
static vlib_process_t * vlib_get_current_process(vlib_main_t *vm)
Definition: node_funcs.h:397
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
#define clib_error_free(e)
Definition: error.h:98
static uword * clib_bitmap_andnot(uword *ai, uword *bi)
Logical operator across two bitmaps.
void vlib_worker_thread_barrier_sync(vlib_main_t *vm)
Definition: threads.c:1163
uword ** bitmaps
Definition: cli.h:52
static u8 * format_vlib_cli_command_help(u8 *s, va_list *args)
Definition: cli.c:238
uword unformat_vlib_enable_disable(unformat_input_t *input, va_list *args)
Definition: format.c:116
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define clib_elf_section_data_next(a, extra)
Definition: elf_clib.h:57
static uword * vlib_cli_sub_command_match(vlib_cli_command_t *c, unformat_input_t *input)
Definition: cli.c:77
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:745
uword * parse_rule_index_by_name
Definition: cli.h:145
void( vlib_cli_output_function_t)(uword arg, u8 *buffer, uword buffer_bytes)
Definition: cli.h:131
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
uword * sub_command_index_by_name
Definition: cli.h:114
#define vec_cmp(v1, v2)
Compare two vectors (only applicable to vectors of signed numbers).
Definition: vec.h:880
u64 uword
Definition: types.h:112
#define MHEAP_FLAG_SMALL_OBJECT_CACHE
static u8 * format_vlib_cli_parse_rule_name(u8 *s, va_list *args)
Definition: cli.c:252
static uword clib_bitmap_count_set_bits(uword *ai)
Return the number of set bits in a bitmap.
Definition: bitmap.h:441
struct vlib_cli_command_t * next_cli_command
Definition: cli.h:127
unsigned short u16
Definition: types.h:57
#define hash_create_vec(elts, key_bytes, value_bytes)
Definition: hash.h:644
i64 word
Definition: types.h:111
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static u8 * format_vlib_cli_path(u8 *s, va_list *args)
Definition: cli.c:259
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:920
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:335
void ** parse_rule_data
Definition: cli.h:148
word fformat(FILE *f, char *fmt,...)
Definition: format.c:452
#define hash_get_mem(h, key)
Definition: hash.h:268
vlib_cli_command_t * cli_command_registrations
Definition: cli.h:151
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1195
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
void mheap_validate(void *v)
Definition: mheap.c:1344
#define vec_foreach(var, vec)
Vector iterator.
static clib_error_t * show_cpu(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:638
vlib_cli_parse_position_t * sub_command_positions
Definition: cli.h:118
static clib_error_t * enable_disable_memory_trace(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:671
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
vlib_cli_output_function_t * output_function
Definition: node.h:542
static clib_error_t * show_memory_usage(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:599
void clib_mem_trace(int enable)
Definition: mem_mheap.c:154
char * short_help
Definition: cli.h:98
format_function_t format_cpu_model_name
Definition: cpu.h:103
static uword * clib_bitmap_and(uword *ai, uword *bi)
Logical operator across two bitmaps.
void vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:539
static uword unformat_vlib_cli_sub_command(unformat_input_t *i, va_list *args)
Definition: cli.c:193
u32 rule_index
Definition: cli.h:66
static int vlib_cli_cmp_rule(void *a1, void *a2)
Definition: cli.c:317
void vlib_unix_error_report(vlib_main_t *, clib_error_t *)
Definition: cli.c:533