Trivial: Clean up some typos.
[vpp.git] / src / vlib / node_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  * node_cli.c: node CLI
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vlib/vlib.h>
41 #include <vlib/threads.h>
42
43 static int
44 node_cmp (void *a1, void *a2)
45 {
46   vlib_node_t **n1 = a1;
47   vlib_node_t **n2 = a2;
48
49   return vec_cmp (n1[0]->name, n2[0]->name);
50 }
51
52 static clib_error_t *
53 show_node_graph (vlib_main_t * vm,
54                  unformat_input_t * input, vlib_cli_command_t * cmd)
55 {
56   vlib_node_main_t *nm = &vm->node_main;
57   vlib_node_t *n;
58   u32 node_index;
59
60   vlib_cli_output (vm, "%U\n", format_vlib_node_graph, nm, 0);
61
62   if (unformat (input, "%U", unformat_vlib_node, vm, &node_index))
63     {
64       n = vlib_get_node (vm, node_index);
65       vlib_cli_output (vm, "%U\n", format_vlib_node_graph, nm, n);
66     }
67   else
68     {
69       vlib_node_t **nodes = vec_dup (nm->nodes);
70       uword i;
71
72       vec_sort_with_function (nodes, node_cmp);
73
74       for (i = 0; i < vec_len (nodes); i++)
75         vlib_cli_output (vm, "%U\n\n", format_vlib_node_graph, nm, nodes[i]);
76
77       vec_free (nodes);
78     }
79
80   return 0;
81 }
82
83 /* *INDENT-OFF* */
84 VLIB_CLI_COMMAND (show_node_graph_command, static) = {
85   .path = "show vlib graph",
86   .short_help = "Show packet processing node graph",
87   .function = show_node_graph,
88 };
89 /* *INDENT-ON* */
90
91 static u8 *
92 format_vlib_node_state (u8 * s, va_list * va)
93 {
94   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
95   vlib_node_t *n = va_arg (*va, vlib_node_t *);
96   char *state;
97
98   state = "active";
99   if (n->type == VLIB_NODE_TYPE_PROCESS)
100     {
101       vlib_process_t *p = vlib_get_process_from_node (vm, n);
102
103       switch (p->flags & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
104                           | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT))
105         {
106         default:
107           if (!(p->flags & VLIB_PROCESS_IS_RUNNING))
108             state = "done";
109           break;
110
111         case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK:
112           state = "time wait";
113           break;
114
115         case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT:
116           state = "event wait";
117           break;
118
119         case (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK):
120           state =
121             "any wait";
122           break;
123         }
124     }
125   else if (n->type != VLIB_NODE_TYPE_INTERNAL)
126     {
127       state = "polling";
128       if (n->state == VLIB_NODE_STATE_DISABLED)
129         state = "disabled";
130       else if (n->state == VLIB_NODE_STATE_INTERRUPT)
131         state = "interrupt wait";
132     }
133
134   return format (s, "%s", state);
135 }
136
137 static u8 *
138 format_vlib_node_stats (u8 * s, va_list * va)
139 {
140   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
141   vlib_node_t *n = va_arg (*va, vlib_node_t *);
142   int max = va_arg (*va, int);
143   f64 v;
144   u8 *ns;
145   u8 *misc_info = 0;
146   u64 c, p, l, d;
147   f64 x;
148   f64 maxc, maxcn;
149   u32 maxn;
150   u32 indent;
151
152   if (!n)
153     {
154       if (max)
155         return format (s,
156                        "%=30s%=17s%=16s%=16s%=16s%=16s",
157                        "Name", "Max Node Clocks", "Vectors at Max",
158                        "Max Clocks", "Avg Clocks", "Avg Vectors/Call");
159       else
160         return format (s,
161                        "%=30s%=12s%=16s%=16s%=16s%=16s%=16s",
162                        "Name", "State", "Calls", "Vectors", "Suspends",
163                        "Clocks", "Vectors/Call");
164     }
165
166   indent = format_get_indent (s);
167
168   l = n->stats_total.clocks - n->stats_last_clear.clocks;
169   c = n->stats_total.calls - n->stats_last_clear.calls;
170   p = n->stats_total.vectors - n->stats_last_clear.vectors;
171   d = n->stats_total.suspends - n->stats_last_clear.suspends;
172   maxc = (f64) n->stats_total.max_clock;
173   maxn = n->stats_total.max_clock_n;
174   if (n->stats_total.max_clock_n)
175     maxcn = (f64) n->stats_total.max_clock / (f64) maxn;
176   else
177     maxcn = 0.0;
178
179   /* Clocks per packet, per call or per suspend. */
180   x = 0;
181   if (p > 0)
182     x = (f64) l / (f64) p;
183   else if (c > 0)
184     x = (f64) l / (f64) c;
185   else if (d > 0)
186     x = (f64) l / (f64) d;
187
188   if (c > 0)
189     v = (double) p / (double) c;
190   else
191     v = 0;
192
193   if (n->type == VLIB_NODE_TYPE_PROCESS)
194     {
195       vlib_process_t *p = vlib_get_process_from_node (vm, n);
196
197       /* Show processes with events pending.  This helps spot bugs where events are not
198          being handled. */
199       if (!clib_bitmap_is_zero (p->non_empty_event_type_bitmap))
200         misc_info = format (misc_info, "events pending, ");
201     }
202   ns = n->name;
203
204   if (max)
205     s = format (s, "%-30v%=17.2e%=16d%=16.2e%=16.2e%=16.2e",
206                 ns, maxc, maxn, maxcn, x, v);
207   else
208     s = format (s, "%-30v%=12U%16Ld%16Ld%16Ld%16.2e%16.2f", ns,
209                 format_vlib_node_state, vm, n, c, p, d, x, v);
210
211   if (ns != n->name)
212     vec_free (ns);
213
214   if (misc_info)
215     {
216       s = format (s, "\n%U%v", format_white_space, indent + 4, misc_info);
217       vec_free (misc_info);
218     }
219
220   return s;
221 }
222
223 static clib_error_t *
224 show_node_runtime (vlib_main_t * vm,
225                    unformat_input_t * input, vlib_cli_command_t * cmd)
226 {
227   vlib_node_main_t *nm = &vm->node_main;
228   vlib_node_t *n;
229   f64 time_now;
230   u32 node_index;
231   vlib_node_t ***node_dups = 0;
232   f64 *vectors_per_main_loop = 0;
233   f64 *last_vector_length_per_node = 0;
234
235   time_now = vlib_time_now (vm);
236
237   if (unformat (input, "%U", unformat_vlib_node, vm, &node_index))
238     {
239       n = vlib_get_node (vm, node_index);
240       vlib_node_sync_stats (vm, n);
241       vlib_cli_output (vm, "%U\n", format_vlib_node_stats, vm, 0, 0);
242       vlib_cli_output (vm, "%U\n", format_vlib_node_stats, vm, n, 0);
243     }
244   else
245     {
246       vlib_node_t **nodes;
247       uword i, j;
248       f64 dt;
249       u64 n_input, n_output, n_drop, n_punt;
250       u64 n_internal_vectors, n_internal_calls;
251       u64 n_clocks, l, v, c, d;
252       int brief = 1;
253       int max = 0;
254       vlib_main_t **stat_vms = 0, *stat_vm;
255
256       /* Suppress nodes with zero calls since last clear */
257       if (unformat (input, "brief") || unformat (input, "b"))
258         brief = 1;
259       if (unformat (input, "verbose") || unformat (input, "v"))
260         brief = 0;
261       if (unformat (input, "max") || unformat (input, "m"))
262         max = 1;
263
264       for (i = 0; i < vec_len (vlib_mains); i++)
265         {
266           stat_vm = vlib_mains[i];
267           if (stat_vm)
268             vec_add1 (stat_vms, stat_vm);
269         }
270
271       /*
272        * Barrier sync across stats scraping.
273        * Otherwise, the counts will be grossly inaccurate.
274        */
275       vlib_worker_thread_barrier_sync (vm);
276
277       for (j = 0; j < vec_len (stat_vms); j++)
278         {
279           stat_vm = stat_vms[j];
280           nm = &stat_vm->node_main;
281
282           for (i = 0; i < vec_len (nm->nodes); i++)
283             {
284               n = nm->nodes[i];
285               vlib_node_sync_stats (stat_vm, n);
286             }
287
288           nodes = vec_dup (nm->nodes);
289
290           vec_add1 (node_dups, nodes);
291           vec_add1 (vectors_per_main_loop,
292                     vlib_last_vectors_per_main_loop_as_f64 (stat_vm));
293           vec_add1 (last_vector_length_per_node,
294                     vlib_last_vector_length_per_node (stat_vm));
295         }
296       vlib_worker_thread_barrier_release (vm);
297
298
299       for (j = 0; j < vec_len (stat_vms); j++)
300         {
301           stat_vm = stat_vms[j];
302           nodes = node_dups[j];
303
304           vec_sort_with_function (nodes, node_cmp);
305
306           n_input = n_output = n_drop = n_punt = n_clocks = 0;
307           n_internal_vectors = n_internal_calls = 0;
308           for (i = 0; i < vec_len (nodes); i++)
309             {
310               n = nodes[i];
311
312               l = n->stats_total.clocks - n->stats_last_clear.clocks;
313               n_clocks += l;
314
315               v = n->stats_total.vectors - n->stats_last_clear.vectors;
316               c = n->stats_total.calls - n->stats_last_clear.calls;
317
318               switch (n->type)
319                 {
320                 default:
321                   continue;
322
323                 case VLIB_NODE_TYPE_INTERNAL:
324                   n_output += (n->flags & VLIB_NODE_FLAG_IS_OUTPUT) ? v : 0;
325                   n_drop += (n->flags & VLIB_NODE_FLAG_IS_DROP) ? v : 0;
326                   n_punt += (n->flags & VLIB_NODE_FLAG_IS_PUNT) ? v : 0;
327                   if (!(n->flags & VLIB_NODE_FLAG_IS_OUTPUT))
328                     {
329                       n_internal_vectors += v;
330                       n_internal_calls += c;
331                     }
332                   if (n->flags & VLIB_NODE_FLAG_IS_HANDOFF)
333                     n_input += v;
334                   break;
335
336                 case VLIB_NODE_TYPE_INPUT:
337                   n_input += v;
338                   break;
339                 }
340             }
341
342           if (vec_len (vlib_mains) > 1)
343             {
344               vlib_worker_thread_t *w = vlib_worker_threads + j;
345               if (j > 0)
346                 vlib_cli_output (vm, "---------------");
347
348               if (w->lcore_id > -1)
349                 vlib_cli_output (vm, "Thread %d %s (lcore %u)", j, w->name,
350                                  w->lcore_id);
351               else
352                 vlib_cli_output (vm, "Thread %d %s", j, w->name);
353             }
354
355           dt = time_now - nm->time_last_runtime_stats_clear;
356           vlib_cli_output
357             (vm,
358              "Time %.1f, average vectors/node %.2f, last %d main loops %.2f per node %.2f"
359              "\n  vector rates in %.4e, out %.4e, drop %.4e, punt %.4e",
360              dt,
361              (n_internal_calls > 0
362               ? (f64) n_internal_vectors / (f64) n_internal_calls
363               : 0),
364              1 << VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE,
365              vectors_per_main_loop[j],
366              last_vector_length_per_node[j],
367              (f64) n_input / dt,
368              (f64) n_output / dt, (f64) n_drop / dt, (f64) n_punt / dt);
369
370           vlib_cli_output (vm, "%U", format_vlib_node_stats, stat_vm, 0, max);
371           for (i = 0; i < vec_len (nodes); i++)
372             {
373               c =
374                 nodes[i]->stats_total.calls -
375                 nodes[i]->stats_last_clear.calls;
376               d =
377                 nodes[i]->stats_total.suspends -
378                 nodes[i]->stats_last_clear.suspends;
379               if (c || d || !brief)
380                 {
381                   vlib_cli_output (vm, "%U", format_vlib_node_stats, stat_vm,
382                                    nodes[i], max);
383                 }
384             }
385           vec_free (nodes);
386         }
387       vec_free (stat_vms);
388       vec_free (node_dups);
389       vec_free (vectors_per_main_loop);
390       vec_free (last_vector_length_per_node);
391     }
392
393   return 0;
394 }
395
396 /* *INDENT-OFF* */
397 VLIB_CLI_COMMAND (show_node_runtime_command, static) = {
398   .path = "show runtime",
399   .short_help = "Show packet processing runtime",
400   .function = show_node_runtime,
401   .is_mp_safe = 1,
402 };
403 /* *INDENT-ON* */
404
405 static clib_error_t *
406 clear_node_runtime (vlib_main_t * vm,
407                     unformat_input_t * input, vlib_cli_command_t * cmd)
408 {
409   vlib_node_main_t *nm;
410   vlib_node_t *n;
411   int i, j;
412   vlib_main_t **stat_vms = 0, *stat_vm;
413   vlib_node_runtime_t *r;
414
415   for (i = 0; i < vec_len (vlib_mains); i++)
416     {
417       stat_vm = vlib_mains[i];
418       if (stat_vm)
419         vec_add1 (stat_vms, stat_vm);
420     }
421
422   vlib_worker_thread_barrier_sync (vm);
423
424   for (j = 0; j < vec_len (stat_vms); j++)
425     {
426       stat_vm = stat_vms[j];
427       nm = &stat_vm->node_main;
428
429       for (i = 0; i < vec_len (nm->nodes); i++)
430         {
431           n = nm->nodes[i];
432           vlib_node_sync_stats (stat_vm, n);
433           n->stats_last_clear = n->stats_total;
434
435           r = vlib_node_get_runtime (stat_vm, n->index);
436           r->max_clock = 0;
437         }
438       /* Note: input/output rates computed using vlib_global_main */
439       nm->time_last_runtime_stats_clear = vlib_time_now (vm);
440     }
441
442   vlib_worker_thread_barrier_release (vm);
443
444   vec_free (stat_vms);
445
446   return 0;
447 }
448
449 /* *INDENT-OFF* */
450 VLIB_CLI_COMMAND (clear_node_runtime_command, static) = {
451   .path = "clear runtime",
452   .short_help = "Clear packet processing runtime statistics",
453   .function = clear_node_runtime,
454 };
455 /* *INDENT-ON* */
456
457 static clib_error_t *
458 show_node (vlib_main_t * vm, unformat_input_t * input,
459            vlib_cli_command_t * cmd)
460 {
461   unformat_input_t _line_input, *line_input = &_line_input;
462   vlib_node_main_t *nm = &vm->node_main;
463   vlib_node_t *n;
464   u8 *s = 0, *s2 = 0;
465   u32 i, node_index = ~0;
466   char *type_str;
467
468   if (!unformat_user (input, unformat_line_input, line_input))
469     return 0;
470
471   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
472     {
473       if (unformat (line_input, "%U", unformat_vlib_node, vm, &node_index))
474         ;
475       else if (unformat (line_input, "index %u", &node_index))
476         ;
477       else
478         return clib_error_return (0, "unknown input '%U'",
479                                   format_unformat_error, line_input);
480     }
481   unformat_free (line_input);
482
483   if (node_index >= vec_len (vm->node_main.nodes))
484     return clib_error_return (0, "please specify valid node");
485
486   n = vlib_get_node (vm, node_index);
487   vlib_node_sync_stats (vm, n);
488
489   switch (n->type)
490     {
491     case VLIB_NODE_TYPE_INTERNAL:
492       type_str = "internal";
493       break;
494     case VLIB_NODE_TYPE_INPUT:
495       type_str = "input";
496       break;
497     case VLIB_NODE_TYPE_PRE_INPUT:
498       type_str = "pre-input";
499       break;
500     case VLIB_NODE_TYPE_PROCESS:
501       type_str = "process";
502       break;
503     default:
504       type_str = "unknown";
505     }
506
507   if (n->sibling_of)
508     s = format (s, ", sibling-of %s", n->sibling_of);
509
510   vlib_cli_output (vm, "node %s, type %s, state %U, index %d%v\n",
511                    n->name, type_str, format_vlib_node_state, vm, n,
512                    n->index, s);
513   vec_reset_length (s);
514
515   if (n->node_fn_registrations)
516     {
517       vlib_node_fn_registration_t *fnr = n->node_fn_registrations;
518       while (fnr)
519         {
520           if (vec_len (s) == 0)
521             s = format (s, "\n    %-15s  %=8s  %6s",
522                         "Name", "Priority", "Active");
523           s = format (s, "\n    %-15s  %=8u  %=6s", fnr->name, fnr->priority,
524                       fnr->function == n->function ? "yes" : "");
525           fnr = fnr->next_registration;
526         }
527     }
528   else
529     s = format (s, "\n    default only");
530   vlib_cli_output (vm, "  node function variants:%v\n", s);
531   vec_reset_length (s);
532
533   for (i = 0; i < vec_len (n->next_nodes); i++)
534     {
535       vlib_node_t *pn;
536       if (n->next_nodes[i] == VLIB_INVALID_NODE_INDEX)
537         continue;
538
539       pn = vec_elt (nm->nodes, n->next_nodes[i]);
540
541       if (vec_len (s) == 0)
542         s = format (s, "\n    %10s  %10s  %=30s %8s",
543                     "next-index", "node-index", "Node", "Vectors");
544
545       s = format (s, "\n    %=10u  %=10u  %-30v %=8llu", i, n->next_nodes[i],
546                   pn->name, vec_elt (n->n_vectors_by_next_node, i));
547     }
548
549   if (vec_len (s) == 0)
550     s = format (s, "\n    none");
551   vlib_cli_output (vm, "\n  next nodes:%v\n", s);
552   vec_reset_length (s);
553
554   if (n->type == VLIB_NODE_TYPE_INTERNAL)
555     {
556       int j = 0;
557       /* *INDENT-OFF* */
558       clib_bitmap_foreach (i, n->prev_node_bitmap, ({
559             vlib_node_t *pn = vlib_get_node (vm, i);
560             if (j++ % 3 == 0)
561               s = format (s, "\n    ");
562             s2 = format (s2, "%v (%u)", pn->name, i);
563             s = format (s, "%-35v", s2);
564             vec_reset_length (s2);
565           }));
566       /* *INDENT-ON* */
567
568       if (vec_len (s) == 0)
569         s = format (s, "\n    none");
570       vlib_cli_output (vm, "\n  known previous nodes:%v\n", s);
571       vec_reset_length (s);
572     }
573
574   vec_free (s);
575   vec_free (s2);
576   return 0;
577 }
578
579 /* *INDENT-OFF* */
580 VLIB_CLI_COMMAND (show_node_command, static) = {
581   .path = "show node",
582   .short_help = "show node [index] <node-name | node-index>",
583   .function = show_node,
584 };
585
586 static clib_error_t *
587 set_node_fn(vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
588 {
589   unformat_input_t _line_input, *line_input = &_line_input;
590   u32 node_index;
591   vlib_node_t *n;
592   clib_error_t *err = 0;
593   vlib_node_fn_registration_t *fnr;
594   u8 *variant = 0;
595
596   if (!unformat_user (input, unformat_line_input, line_input))
597     return 0;
598
599   if (!unformat (line_input, "%U", unformat_vlib_node, vm, &node_index))
600     {
601       err = clib_error_return (0, "please specify valid node name");
602       goto done;
603     }
604
605   if (!unformat (line_input, "%s", &variant))
606     {
607       err = clib_error_return (0, "please specify node functional variant");
608       goto done;
609     }
610
611   n = vlib_get_node (vm, node_index);
612
613   if (n->node_fn_registrations == 0)
614     {
615       err = clib_error_return (0, "node doesn't have functional variants");
616       goto done;
617     }
618
619   fnr = n->node_fn_registrations;
620   vec_add1 (variant, 0);
621
622   while (fnr)
623     {
624       if (!strncmp (fnr->name, (char *) variant, vec_len (variant) - 1))
625         {
626           int i;
627
628           n->function = fnr->function;
629
630           for (i = 0; i < vec_len (vlib_mains); i++)
631             {
632               vlib_node_runtime_t *nrt;
633               nrt = vlib_node_get_runtime (vlib_mains[i], n->index);
634               nrt->function = fnr->function;
635             }
636           goto done;
637         }
638       fnr = fnr->next_registration;
639     }
640
641   err = clib_error_return (0, "node functional variant '%s' not found", variant);
642
643 done:
644   vec_free (variant);
645   unformat_free (line_input);
646   return err;
647 }
648
649 /* *INDENT-OFF* */
650 VLIB_CLI_COMMAND (set_node_fn_command, static) = {
651   .path = "set node function",
652   .short_help = "set node function <node-name> <variant-name>",
653   .function = set_node_fn,
654 };
655 /* *INDENT-ON* */
656
657 /* Dummy function to get us linked in. */
658 void
659 vlib_node_cli_reference (void)
660 {
661 }
662
663 /*
664  * fd.io coding-style-patch-verification: ON
665  *
666  * Local Variables:
667  * eval: (c-set-style "gnu")
668  * End:
669  */