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