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