Initial commit of vpp code.
[vpp.git] / vlib / vlib / cli.c
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 *
68 vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
69 {
70   int i, n;
71   uword * match = 0;
72   vlib_cli_parse_position_t * p;
73
74   unformat_skip_white_space (input);
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':
90         case UNFORMAT_END_OF_INPUT:
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             {
96               p = vec_elt_at_index (c->sub_command_positions, i);
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
114       p = vec_elt_at_index (c->sub_command_positions, i);
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 }. */
136 static uword unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
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 *
170 get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
171 {
172   vlib_cli_sub_command_t * s = vec_elt_at_index (parent->sub_commands, si);
173   return vec_elt_at_index (cm->commands, s->index);
174 }
175
176 static uword unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
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;
186     vlib_cli_parse_rule_t * r;
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 *
280 all_subs (vlib_cli_main_t * cm,
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);
285   vlib_cli_sub_command_t * sc;
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 clib_error_t *
300 vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
301                                 vlib_cli_main_t * cm,
302                                 unformat_input_t * input,
303                                 uword parent_command_index)
304 {
305   vlib_cli_command_t * parent, * c;
306   clib_error_t * error = 0;
307   unformat_input_t sub_input;
308   u8 * string;
309   uword is_main_dispatch = cm == &vm->cli_main;
310
311   parent = vec_elt_at_index (cm->commands, parent_command_index);
312   if (is_main_dispatch && unformat (input, "help"))
313     {
314       uword help_at_end_of_line, i;
315
316       help_at_end_of_line = unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
317       while (1)
318         {
319           c = parent;
320           if (unformat_user (input, unformat_vlib_cli_sub_command, vm, c, &parent))
321             ;
322
323           else if (! unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
324             goto unknown;
325
326           else
327             break;
328         }
329       
330       /* help SUB-COMMAND => long format help.
331          "help" at end of line: show all commands. */
332       if (! help_at_end_of_line)
333         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c, /* is_long */ 1);
334
335       else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
336         vlib_cli_output (vm, "%v: no sub-commands", c->path);
337
338       else
339         {
340           vlib_cli_sub_command_t * sc;
341           vlib_cli_sub_rule_t * sr, * subs;
342
343           subs = vec_dup (c->sub_rules);
344
345           /* Add in rules if any. */
346           vec_foreach (sc, c->sub_commands)
347             {
348               vec_add2 (subs, sr, 1);
349               sr->name = sc->name;
350               sr->command_index = sc->index;
351               sr->rule_index = ~0;
352             }
353
354           vec_sort (subs, c1, c2, vec_cmp (c1->name, c2->name));
355
356           for (i = 0; i < vec_len (subs); i++) 
357             {
358               vlib_cli_command_t * d;
359               vlib_cli_parse_rule_t * r;
360
361               d = vec_elt_at_index (cm->commands, subs[i].command_index);
362               r = subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules, subs[i].rule_index) : 0;
363
364               if (r)
365                 vlib_cli_output
366                   (vm, "  %-30U %U",
367                    format_vlib_cli_parse_rule_name, r,
368                    format_vlib_cli_command_help, d, /* is_long */ 0);
369               else
370                 vlib_cli_output
371                   (vm, "  %-30v %U",
372                    subs[i].name,
373                    format_vlib_cli_command_help, d, /* is_long */ 0);
374             }
375
376           vec_free (subs);
377         }
378     }
379   
380   else if (is_main_dispatch && (unformat (input, "choices") || unformat (input, "?")))
381     {
382       vlib_cli_command_t * sub, * subs;
383
384       subs = all_subs (cm, 0, parent_command_index);
385       vec_sort (subs, c1, c2, vec_cmp (c1->path, c2->path));
386       vec_foreach (sub, subs)
387         vlib_cli_output (vm, "  %-40U %U",
388                          format_vlib_cli_path, sub->path,
389                          format_vlib_cli_command_help, sub, /* is_long */ 0);
390       vec_free (subs);
391     }
392
393   else if (unformat (input, "comment %v", &string))
394     {
395       vec_free (string);
396     }
397   
398   else if (unformat (input, "uncomment %U",
399                      unformat_vlib_cli_sub_input, &sub_input))
400     {
401       error = vlib_cli_dispatch_sub_commands (vm, cm, &sub_input, parent_command_index);
402       unformat_free (&sub_input);
403     }
404   
405   else if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
406     {
407       unformat_input_t * si;
408       uword has_sub_commands = vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
409       
410       si = input;
411       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
412         si = &sub_input;
413       
414       if (has_sub_commands)
415         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
416
417       if (has_sub_commands && ! error)
418         /* Found valid sub-command. */;
419
420       else if (c->function)
421         {
422           clib_error_t * c_error;
423
424           /* Skip white space for benefit of called function. */
425           unformat_skip_white_space (si);
426
427           if (unformat (si, "?"))
428             {
429               vlib_cli_output (vm, "  %-40U %U",
430                                format_vlib_cli_path, c->path,
431                                format_vlib_cli_command_help, c, /* is_long */ 0);
432             }
433           else
434             {
435               if (!c->is_mp_safe)
436                 vlib_worker_thread_barrier_sync(vm);
437
438               c_error = c->function (vm, si, c);
439
440               if (!c->is_mp_safe)
441                 vlib_worker_thread_barrier_release(vm);
442
443               if (c_error)
444                 {
445                   error = clib_error_return (0, "%v: %v", c->path, c_error->what);
446                   clib_error_free (c_error);
447                   /* Free sub input. */
448                   if (si != input)
449                     unformat_free (si);
450
451                   return error;
452                 }
453             }
454
455           /* Free any previous error. */
456           clib_error_free (error);
457         }
458
459       else if (! error)
460         error = clib_error_return (0, "%v: no sub-commands", c->path);
461
462       /* Free sub input. */
463       if (si != input)
464         unformat_free (si);
465     }
466
467   else
468     goto unknown;
469
470   return error;
471
472  unknown:
473   if (parent->path)
474     return clib_error_return (0, "%v: unknown input `%U'", parent->path, format_unformat_error, input);
475   else
476     return clib_error_return (0, "unknown input `%U'", format_unformat_error, input);
477 }
478
479
480 void vlib_unix_error_report (vlib_main_t *, clib_error_t *) 
481     __attribute__ ((weak));
482
483 void vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error) { }
484
485 /* Process CLI input. */
486 void vlib_cli_input (vlib_main_t * vm,
487                      unformat_input_t * input,
488                      vlib_cli_output_function_t * function,
489                      uword function_arg)
490 {
491   vlib_cli_main_t * cm = &vm->cli_main;
492   clib_error_t * error;
493   vlib_cli_output_function_t * save_function;
494   uword save_function_arg;
495
496   save_function = cm->output_function;
497   save_function_arg = cm->output_function_arg;
498
499   cm->output_function = function;
500   cm->output_function_arg = function_arg;
501
502   do {
503     vec_reset_length (cm->parse_rule_data);
504     error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */ 0);
505   } while (! error && ! unformat (input, "%U", unformat_eof));
506
507   if (error)
508     {
509       vlib_cli_output (vm, "%v", error->what);
510       vlib_unix_error_report (vm, error);
511       clib_error_free (error);
512     }
513
514   cm->output_function = save_function;
515   cm->output_function_arg = save_function_arg;
516 }
517
518 /* Output to current CLI connection. */
519 void vlib_cli_output (vlib_main_t * vm, char * fmt, ...)
520 {
521   vlib_cli_main_t * cm = &vm->cli_main;
522   va_list va;
523   u8 * s;
524
525   va_start (va, fmt);
526   s = va_format (0, fmt, &va);
527   va_end (va);
528
529   /* Terminate with \n if not present. */
530   if (vec_len (s) > 0 && s[vec_len (s)-1] != '\n')
531     vec_add1 (s, '\n');
532
533   if (! cm->output_function)
534     fformat (stdout, "%v", s);
535   else
536     cm->output_function (cm->output_function_arg, s, vec_len (s));
537
538   vec_free (s);
539 }
540
541 static clib_error_t *
542 show_memory_usage (vlib_main_t * vm,
543                    unformat_input_t * input,
544                    vlib_cli_command_t * cmd)
545 {
546   int verbose = 0;
547   clib_error_t * error;
548   u32 index = 0;
549
550   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
551     {
552       if (unformat (input, "verbose")) 
553         verbose = 1;
554       else {
555         error = clib_error_return (0, "unknown input `%U'", 
556                                    format_unformat_error, input);
557         return error;
558       }
559   }
560
561   foreach_vlib_main (
562   ({
563       vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
564       vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
565       index++;
566   }));
567   return 0;
568 }
569
570 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
571   .path = "show memory",
572   .short_help = "Show current memory usage",
573   .function = show_memory_usage,
574 };
575
576 static clib_error_t *
577 enable_disable_memory_trace (vlib_main_t * vm,
578                              unformat_input_t * input,
579                              vlib_cli_command_t * cmd)
580 {
581   clib_error_t * error = 0;
582   int enable;
583
584   if (! unformat_user (input, unformat_vlib_enable_disable, &enable))
585     {
586       error = clib_error_return (0, "expecting enable/on or disable/off");
587       goto done;
588     }
589
590   clib_mem_trace (enable);
591
592  done:
593   return error;
594 }
595
596 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
597   .path = "memory-trace",
598   .short_help = "Enable/disable memory allocation trace",
599   .function = enable_disable_memory_trace,
600 };
601
602
603 static clib_error_t *
604 test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
605                         vlib_cli_command_t * cmd)
606 {
607     clib_error_t * error = 0;
608     void * heap;
609     mheap_t *mheap;
610
611     if (unformat(input, "on")) {
612         foreach_vlib_main({
613           heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
614           mheap = mheap_header(heap);
615           mheap->flags |= MHEAP_FLAG_VALIDATE;
616           // Turn off small object cache because it delays detection of errors
617           mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
618         });
619
620     } else if (unformat(input, "off")) {
621         foreach_vlib_main({
622           heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
623           mheap = mheap_header(heap);
624           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
625           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
626         });
627
628     } else if (unformat(input, "now")) {
629         foreach_vlib_main({
630           heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
631           mheap = mheap_header(heap);
632           mheap_validate(heap);
633         });
634         vlib_cli_output(vm, "heap validation complete");
635
636     } else {
637         return clib_error_return(0, "unknown input `%U'",
638                                   format_unformat_error, input);
639     }
640
641     return error;
642 }
643
644 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
645     .path = "test heap-validate",
646     .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
647     .function = test_heap_validate,
648 };
649
650
651 static uword vlib_cli_normalize_path (char * input, char ** result)
652 {
653   char * i = input;
654   char * s = 0;
655   uword l = 0;
656   uword index_of_last_space = ~0;
657
658   while (*i != 0)
659     {
660       u8 c = *i++;
661       /* Multiple white space -> single space. */
662       switch (c)
663         {
664         case ' ':
665         case '\t':
666         case '\n':
667         case '\r':
668           if (l > 0 && s[l-1] != ' ')
669             {
670               vec_add1 (s, ' ');
671               l++;
672             }
673           break;
674
675         default:
676           if (l > 0 && s[l-1] == ' ')
677             index_of_last_space = vec_len (s);
678           vec_add1 (s, c);
679           l++;
680           break;
681         }
682     }
683
684   /* Remove any extra space at end. */
685   if (l > 0 && s[l-1] == ' ')
686     _vec_len (s) -= 1;
687
688   *result = s;
689   return index_of_last_space;
690 }
691
692 always_inline uword
693 parent_path_len (char * path)
694 {
695   word i;
696   for (i = vec_len (path) - 1; i >= 0; i--)
697     {
698       if (path[i] == ' ')
699         return i;
700     }
701   return ~0;
702 }
703
704 static void add_sub_command (vlib_cli_main_t * cm,
705                              uword parent_index,
706                              uword child_index)
707 {
708   vlib_cli_command_t * p, * c;
709   vlib_cli_sub_command_t * sub_c;
710   u8 * sub_name;
711   word i, l;
712
713   p = vec_elt_at_index (cm->commands, parent_index);
714   c = vec_elt_at_index (cm->commands, child_index);
715
716   l = parent_path_len (c->path);
717   if (l == ~0)
718     sub_name = vec_dup ((u8 *) c->path);
719   else
720     {
721       ASSERT (l + 1 < vec_len (c->path));
722       sub_name = 0;
723       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
724     }
725
726   if (sub_name[0] == '%')
727     {
728       uword * q;
729       vlib_cli_sub_rule_t * sr;
730
731       /* Remove %. */
732       vec_delete (sub_name, 1, 0);
733
734       if (! p->sub_rule_index_by_name)
735         p->sub_rule_index_by_name
736           = hash_create_vec (/* initial length */ 32,
737                              sizeof (sub_name[0]),
738                              sizeof (uword));
739       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
740       if (q)
741         {
742           sr = vec_elt_at_index (p->sub_rules, q[0]);
743           ASSERT (sr->command_index == child_index);
744           return;
745         }
746
747       q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
748       if (! q)
749         clib_error ("reference to unknown rule `%%%v' in path `%v'",
750                     sub_name, c->path);
751
752       hash_set_mem (p->sub_rule_index_by_name, sub_name, vec_len (p->sub_rules));
753       vec_add2 (p->sub_rules, sr, 1);
754       sr->name = sub_name;
755       sr->rule_index = q[0];
756       sr->command_index = child_index;
757       return;
758     }
759
760   if (! p->sub_command_index_by_name)
761     p->sub_command_index_by_name
762       = hash_create_vec (/* initial length */ 32,
763                          sizeof (c->path[0]),
764                          sizeof (uword));
765
766   /* Check if sub-command has already been created. */
767   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
768     {
769       vec_free (sub_name);
770       return;
771     }
772
773   vec_add2 (p->sub_commands, sub_c, 1);
774   sub_c->index = child_index;
775   sub_c->name = sub_name;
776   hash_set_mem (p->sub_command_index_by_name, sub_c->name, sub_c - p->sub_commands);
777
778   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
779   for (i = 0; i < vec_len (sub_c->name); i++)
780     {
781       int n;
782       vlib_cli_parse_position_t * pos;
783
784       pos = vec_elt_at_index (p->sub_command_positions, i);
785
786       if (! pos->bitmaps)
787         pos->min_char = sub_c->name[i];
788
789       n = sub_c->name[i] - pos->min_char;
790       if (n < 0)
791         {
792           pos->min_char = sub_c->name[i];
793           vec_insert (pos->bitmaps, -n, 0);
794           n = 0;
795         }
796
797       vec_validate (pos->bitmaps, n);
798       pos->bitmaps[n] = clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
799     }
800 }
801
802 static void
803 vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
804 {
805   uword p_len, pi, * p;
806   char * p_path;
807   vlib_cli_command_t * c, * parent;
808
809   /* Root command (index 0) should have already been added. */
810   ASSERT (vec_len (cm->commands) > 0);
811
812   c = vec_elt_at_index (cm->commands, ci);
813   p_len = parent_path_len (c->path);
814
815   /* No space?  Parent is root command. */ 
816   if (p_len == ~0)
817     {
818       add_sub_command (cm, 0, ci);
819       return;
820     }
821
822   p_path = 0;
823   vec_add (p_path, c->path, p_len);
824
825   p = hash_get_mem (cm->command_index_by_path, p_path);
826
827   /* Parent exists? */
828   if (! p)
829     {
830       /* Parent does not exist; create it. */
831       vec_add2 (cm->commands, parent, 1);
832       parent->path = p_path;
833       hash_set_mem (cm->command_index_by_path, parent->path, parent - cm->commands);
834       pi = parent - cm->commands;
835     }
836   else
837     {
838       pi = p[0];
839       vec_free (p_path);
840     }
841
842   add_sub_command (cm, pi, ci);
843
844   /* Create parent's parent. */
845   if (! p)
846     vlib_cli_make_parent (cm, pi);
847 }
848
849 always_inline uword
850 vlib_cli_command_is_empty (vlib_cli_command_t * c)
851 {
852   return (c->long_help == 0
853           && c->short_help == 0
854           && c->function == 0);
855 }
856
857 clib_error_t * vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
858 {
859   vlib_cli_main_t * cm = &vm->cli_main;
860   clib_error_t * error = 0;
861   uword ci, * p;
862   char * normalized_path;
863
864   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
865     return error;
866
867   (void) vlib_cli_normalize_path (c->path, &normalized_path);
868
869   if (! cm->command_index_by_path)
870     cm->command_index_by_path = hash_create_vec (/* initial length */ 32,
871                                                  sizeof (c->path[0]),
872                                                  sizeof (uword));
873
874   /* See if command already exists with given path. */
875   p = hash_get_mem (cm->command_index_by_path, normalized_path);
876   if (p)
877     {
878       vlib_cli_command_t * d;
879
880       ci = p[0];
881       d = vec_elt_at_index (cm->commands, ci);
882
883       /* If existing command was created via vlib_cli_make_parent
884          replaced it with callers data. */
885       if (vlib_cli_command_is_empty (d))
886         {
887           vlib_cli_command_t save = d[0];
888
889           ASSERT (! vlib_cli_command_is_empty (c));
890
891           /* Copy callers fields. */
892           d[0] = c[0];
893
894           /* Save internal fields. */
895           d->path = save.path;
896           d->sub_commands = save.sub_commands;
897           d->sub_command_index_by_name = save.sub_command_index_by_name;
898           d->sub_command_positions = save.sub_command_positions;
899           d->sub_rules = save.sub_rules;
900         }
901       else
902         error = clib_error_return (0, "duplicate command name with path %v", normalized_path);
903
904       vec_free (normalized_path);
905       if (error)
906         return error;
907     }
908   else
909     {
910       /* Command does not exist: create it. */
911
912       /* Add root command (index 0). */
913       if (vec_len (cm->commands) == 0)
914         {
915           /* Create command with index 0; path is empty string. */
916           vec_resize (cm->commands, 1);
917         }
918
919       ci = vec_len (cm->commands);
920       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
921       vec_add1 (cm->commands, c[0]);
922
923       c = vec_elt_at_index (cm->commands, ci);
924       c->path = normalized_path;
925
926       /* Don't inherit from registration. */
927       c->sub_commands = 0;
928       c->sub_command_index_by_name = 0;
929       c->sub_command_positions = 0;
930     }
931
932   vlib_cli_make_parent (cm, ci);
933   return 0;
934 }
935
936 clib_error_t *
937 vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
938 {
939   vlib_cli_main_t * cm = &vm->cli_main;
940   vlib_cli_parse_rule_t * r;
941   clib_error_t * error = 0;
942   u8 * r_name;
943   uword * p;
944
945   if (! cm->parse_rule_index_by_name)
946     cm->parse_rule_index_by_name = hash_create_vec (/* initial length */ 32,
947                                                     sizeof (r->name[0]),
948                                                     sizeof (uword));
949
950   /* Make vector copy of name. */
951   r_name = format (0, "%s", r_reg->name);
952
953   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
954     {
955       vec_free (r_name);
956       return clib_error_return (0, "duplicate parse rule name `%s'", r_reg->name);
957     }
958
959   vec_add2 (cm->parse_rules, r, 1);
960   r[0] = r_reg[0];
961   r->name = (char *) r_name;
962   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
963
964   return error;
965 }
966
967 #if 0
968 /* $$$ turn back on again someday, maybe */
969 static clib_error_t *
970 vlib_cli_register_parse_rules (vlib_main_t * vm,
971                                vlib_cli_parse_rule_t * lo,
972                                vlib_cli_parse_rule_t * hi)
973
974     __attribute__((unused))
975 {
976   clib_error_t * error = 0;
977   vlib_cli_parse_rule_t * r;
978
979   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
980     {
981       if (! r->name || strlen (r->name) == 0)
982         {
983           error = clib_error_return (0, "parse rule with no name");
984           goto done;
985         }
986
987       error = vlib_cli_register_parse_rule (vm, r);
988       if (error)
989         goto done;
990     }
991
992  done:
993   return error;
994 }
995 #endif
996
997 static clib_error_t * vlib_cli_init (vlib_main_t * vm)
998 {
999   vlib_cli_main_t * cm = &vm->cli_main;
1000   clib_error_t * error = 0;
1001   vlib_cli_command_t * cmd;
1002
1003   cmd = cm->cli_command_registrations;
1004
1005   while (cmd)
1006     {
1007       error = vlib_cli_register (vm, cmd);
1008       if (error)
1009         return error;
1010       cmd = cmd->next_cli_command;
1011     }
1012   return error;
1013 }
1014
1015 VLIB_INIT_FUNCTION (vlib_cli_init);