Line data Source code
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 <sys/types.h>
41 : #include <sys/stat.h>
42 : #include <fcntl.h>
43 : #include <vlib/vlib.h>
44 : #include <vlib/threads.h>
45 : #include <vlib/stats/stats.h>
46 : #include <math.h>
47 :
48 : static int
49 10931100 : node_cmp (void *a1, void *a2)
50 : {
51 10931100 : vlib_node_t **n1 = a1;
52 10931100 : vlib_node_t **n2 = a2;
53 :
54 41973900 : return vec_cmp (n1[0]->name, n2[0]->name);
55 : }
56 :
57 : static clib_error_t *
58 143 : show_node_graph (vlib_main_t * vm,
59 : unformat_input_t * input, vlib_cli_command_t * cmd)
60 : {
61 143 : vlib_node_main_t *nm = &vm->node_main;
62 : vlib_node_t *n;
63 : u32 node_index;
64 :
65 143 : vlib_cli_output (vm, "%U\n", format_vlib_node_graph, nm, 0);
66 :
67 143 : if (unformat (input, "%U", unformat_vlib_node, vm, &node_index))
68 : {
69 142 : n = vlib_get_node (vm, node_index);
70 142 : vlib_cli_output (vm, "%U\n", format_vlib_node_graph, nm, n);
71 : }
72 : else
73 : {
74 1 : vlib_node_t **nodes = vec_dup (nm->nodes);
75 : uword i;
76 :
77 1 : vec_sort_with_function (nodes, node_cmp);
78 :
79 724 : for (i = 0; i < vec_len (nodes); i++)
80 723 : vlib_cli_output (vm, "%U\n\n", format_vlib_node_graph, nm, nodes[i]);
81 :
82 1 : vec_free (nodes);
83 : }
84 :
85 143 : return 0;
86 : }
87 :
88 : /* *INDENT-OFF* */
89 285289 : VLIB_CLI_COMMAND (show_node_graph_command, static) = {
90 : .path = "show vlib graph",
91 : .short_help = "Show packet processing node graph",
92 : .function = show_node_graph,
93 : };
94 : /* *INDENT-ON* */
95 :
96 : static clib_error_t *
97 2 : show_node_graphviz (vlib_main_t * vm,
98 : unformat_input_t * input, vlib_cli_command_t * cmd)
99 : {
100 2 : clib_error_t *error = 0;
101 2 : vlib_node_main_t *nm = &vm->node_main;
102 2 : vlib_node_t **nodes = nm->nodes;
103 2 : u8 *chroot_filename = 0;
104 : int fd;
105 2 : uword *active = 0;
106 : u32 i, j;
107 2 : unformat_input_t _line_input, *line_input = &_line_input;
108 2 : u8 filter = 0, calls_filter = 0, vectors_filter = 0, both = 0;
109 :
110 2 : fd = -1;
111 : /* Get a line of input. */
112 2 : if (unformat_user (input, unformat_line_input, line_input))
113 : {
114 1 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
115 : {
116 1 : if (unformat (line_input, "filter"))
117 0 : filter = 1;
118 1 : else if (unformat (line_input, "calls") && filter)
119 0 : calls_filter = 1;
120 1 : else if (unformat (line_input, "vectors") && filter)
121 0 : vectors_filter = 1;
122 1 : else if (unformat (line_input, "file %U", unformat_vlib_tmpfile,
123 : &chroot_filename))
124 : {
125 0 : fd = open ((char *) chroot_filename,
126 : O_CREAT | O_TRUNC | O_WRONLY, 0664);
127 : }
128 : else
129 1 : return clib_error_return (0, "unknown input `%U'",
130 : format_unformat_error, input);
131 : }
132 0 : unformat_free (line_input);
133 : }
134 :
135 : /*both is set to true if calls_filter and vectors_filter are, or neither */
136 1 : both = filter & (!(calls_filter ^ vectors_filter));
137 :
138 : #define format__(vm__, fd__, ...) \
139 : if ((fd) < 0) \
140 : { \
141 : vlib_cli_output((vm__), ## __VA_ARGS__); \
142 : } \
143 : else \
144 : { \
145 : fdformat((fd__), ## __VA_ARGS__); \
146 : }
147 :
148 1 : format__ (vm, fd, "%s", "digraph {\n");
149 :
150 1 : clib_bitmap_alloc (active, vec_len (nodes));
151 1 : clib_bitmap_set_region (active, 0, 1, vec_len (nodes));
152 1 : if (filter)
153 : {
154 : /*Adding the legend to the dot file*/
155 0 : format__ (vm, fd, "%s",
156 : " rankdir=\"LR\"\n nodesep=2\n subgraph cluster_legend {\n "
157 : " label=\"Legend\"\n style=\"solid\"\n labelloc = b\n "
158 : " subgraph cluster_colors {\n label=\"Packets/Call\"\n "
159 : " style=\"solid\"\n labelloc = b\n");
160 0 : format__ (vm, fd, "%s",
161 : " 0 [label=\"No packet\", fixedsize=true shape=circle "
162 : "width=2 fontsize=17]\n"
163 : " 1 [label=\"1-32\", fillcolor=1 style=filled "
164 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
165 : "fontsize=17]\n"
166 : " 2 [label=\"33-64\", fillcolor=2 style=filled "
167 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
168 : "fontsize=17]\n"
169 : " 3 [label=\"65-96\", fillcolor=3 style=filled "
170 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
171 : "fontsize=17]\n"
172 : " 4 [label=\"97-128\", fillcolor=4 style=filled "
173 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
174 : "fontsize=17]\n"
175 : " 5 [label=\"129-160\", fillcolor=5 style=filled "
176 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
177 : "fontsize=17]\n"
178 : " 6 [label=\"161-192\", fillcolor=6 style=filled "
179 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
180 : "fontsize=17]\n"
181 : " 7 [label=\"193-224\", fillcolor=7 style=filled "
182 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
183 : "fontsize=17]\n"
184 : " 8 [label=\"224+\", fillcolor=8 style=filled "
185 : "colorscheme=ylorrd8 fixedsize=true shape=circle width=2 "
186 : "fontsize=17]\n");
187 0 : format__ (vm, fd, "%s",
188 : " 0 -> 1 -> 2 -> 3 -> 4 [style=\"invis\",weight =100]\n "
189 : " 5 -> 6 -> 7 -> 8 [style=\"invis\",weight =100]\n }\n "
190 : " subgraph cluster_size {\n label=\"Cycles/Packet\"\n "
191 : " style=\"solid\"\n labelloc = b\n");
192 0 : format__ (
193 : vm, fd, "%s",
194 : " a[label=\"0\",fixedsize=true shape=circle width=1] \n"
195 : " b[label=\"10\",fixedsize=true shape=circle width=2 "
196 : "fontsize=17]\n"
197 : " c[label=\"100\",fixedsize=true shape=circle width=3 "
198 : "fontsize=20]\n"
199 : " d[label=\"1000\",fixedsize=true shape=circle width=4 "
200 : "fontsize=23]\n"
201 : " a -> b -> c -> d [style=\"invis\",weight =100]\n }\n }\n");
202 :
203 0 : vlib_worker_thread_barrier_sync (vm);
204 0 : for (j = 0; j < vec_len (nm->nodes); j++)
205 : {
206 : vlib_node_t *n;
207 0 : n = nm->nodes[j];
208 0 : vlib_node_sync_stats (vm, n);
209 : }
210 :
211 : /* Updating the stats for multithreaded use cases.
212 : * We need to dup the nodes to sum the stats from all threads.*/
213 0 : nodes = vec_dup (nm->nodes);
214 0 : for (i = 1; i < vlib_get_n_threads (); i++)
215 : {
216 : vlib_node_main_t *nm_clone;
217 : vlib_main_t *vm_clone;
218 : vlib_node_runtime_t *rt;
219 : vlib_node_t *n;
220 :
221 0 : vm_clone = vlib_get_main_by_index (i);
222 0 : nm_clone = &vm_clone->node_main;
223 :
224 0 : for (j = 0; j < vec_len (nm_clone->nodes); j++)
225 : {
226 0 : n = nm_clone->nodes[j];
227 :
228 0 : rt = vlib_node_get_runtime (vm_clone, n->index);
229 : /* Sync the stats directly in the duplicated node.*/
230 0 : vlib_node_runtime_sync_stats_node (nodes[j], rt, 0, 0, 0);
231 : }
232 : }
233 0 : vlib_worker_thread_barrier_release (vm);
234 :
235 0 : for (i = 0; i < vec_len (nodes); i++)
236 : {
237 : u64 p, c, l;
238 0 : c = nodes[i]->stats_total.calls - nodes[i]->stats_last_clear.calls;
239 0 : p =
240 0 : nodes[i]->stats_total.vectors - nodes[i]->stats_last_clear.vectors;
241 0 : l = nodes[i]->stats_total.clocks - nodes[i]->stats_last_clear.clocks;
242 :
243 0 : if ((both && c > 0 && p > 0) || (calls_filter && c > 0) ||
244 0 : (vectors_filter && p > 0))
245 : {
246 0 : format__ (vm, fd, " \"%v\" [shape=circle", nodes[i]->name);
247 : /*Changing the size and the font of nodes that receive packets*/
248 0 : if (p > 0)
249 : {
250 0 : f64 x = (f64) l / (f64) p;
251 0 : f64 size_ratio = (1 + log10 (x + 1));
252 0 : format__ (vm, fd, " width=%.2f fontsize=%.2f fixedsize=true",
253 : size_ratio, 11 + 3 * size_ratio);
254 : /*Coloring nodes that are indeed called*/
255 0 : if (c > 0)
256 : {
257 0 : u64 color = ((p - 1) / (32 * c)) + 1;
258 0 : color = clib_min (color, 8);
259 0 : format__ (
260 : vm, fd,
261 : " fillcolor=%u style=filled colorscheme=ylorrd8",
262 : color);
263 : }
264 : }
265 0 : format__ (vm, fd, "]\n");
266 : }
267 : else
268 : {
269 0 : clib_bitmap_set (active, i, 0);
270 : }
271 : }
272 : }
273 :
274 724 : clib_bitmap_foreach (i, active)
275 : {
276 2994 : for (j = 0; j < vec_len (nodes[i]->next_nodes); j++)
277 : {
278 2271 : if (nodes[i]->next_nodes[j] == VLIB_INVALID_NODE_INDEX)
279 0 : continue;
280 :
281 2271 : if (!filter || clib_bitmap_get (active, nodes[i]->next_nodes[j]))
282 : {
283 2271 : format__ (vm, fd, " \"%v\" -> \"%v\"\n", nodes[i]->name,
284 : nodes[nodes[i]->next_nodes[j]]->name);
285 : }
286 : }
287 : }
288 :
289 1 : format__ (vm, fd, "}\n");
290 :
291 1 : if (fd >= 0)
292 : {
293 : /*Dumping all the nodes saturates dot capacities to render a directed
294 : * graph. In this case, prefer using he fdp command to generate an
295 : * undirected graph. */
296 0 : const char *soft = filter ? "dot" : "fdp";
297 0 : vlib_cli_output (
298 : vm, "vlib graph dumped into `%s'. Run eg. `%s -Tsvg -O %s'.",
299 : chroot_filename, soft, chroot_filename);
300 : }
301 :
302 1 : clib_bitmap_free (active);
303 1 : vec_free (chroot_filename);
304 1 : if (filter)
305 0 : vec_free (nodes);
306 1 : if (fd >= 0)
307 0 : close (fd);
308 1 : return error;
309 : }
310 :
311 : /*?
312 : * Dump dot files data to draw a graph of all the nodes.
313 : * If the argument 'filter' is provided, only the active nodes (since the last
314 : * "clear run" command) are selected and they are scaled and colored according
315 : * to their utilization. You can choose to filter nodes that are called,
316 : * nodes that receive vectors or both (default).
317 : * The 'file' option allows to save data in a temp file.
318 : *
319 : * @cliexpar
320 : * @clistart
321 : * show vlib graphviz
322 : * show vlib graphviz filter file tmpfile
323 : * show vlib graphviz filter calls file tmpfile
324 : * @cliend
325 : * @cliexcmd{show vlib graphviz [filter][calls][vectors][file <filename>]}
326 : ?*/
327 : /* *INDENT-OFF* */
328 285289 : VLIB_CLI_COMMAND (show_node_graphviz_command, static) = {
329 : .path = "show vlib graphviz",
330 : .short_help = "Dump packet processing node graph as a graphviz dotfile",
331 : .function = show_node_graphviz,
332 : .is_mp_safe = 1,
333 : };
334 : /* *INDENT-ON* */
335 :
336 : static u8 *
337 125442 : format_vlib_node_state (u8 * s, va_list * va)
338 : {
339 125442 : vlib_main_t *vm = va_arg (*va, vlib_main_t *);
340 125442 : vlib_node_t *n = va_arg (*va, vlib_node_t *);
341 : char *state;
342 :
343 125442 : state = "active";
344 125442 : if (n->type == VLIB_NODE_TYPE_PROCESS)
345 : {
346 71003 : vlib_process_t *p = vlib_get_process_from_node (vm, n);
347 :
348 71003 : switch (p->flags & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
349 : | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT))
350 : {
351 2970 : default:
352 2970 : if (!(p->flags & VLIB_PROCESS_IS_RUNNING))
353 1393 : state = "done";
354 2970 : break;
355 :
356 1764 : case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK:
357 1764 : state = "time wait";
358 1764 : break;
359 :
360 31257 : case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT:
361 31257 : state = "event wait";
362 31257 : break;
363 :
364 35012 : case (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK):
365 35012 : state =
366 : "any wait";
367 35012 : break;
368 : }
369 : }
370 54439 : else if (n->type != VLIB_NODE_TYPE_INTERNAL)
371 : {
372 5188 : state = "polling";
373 5188 : if (n->state == VLIB_NODE_STATE_DISABLED)
374 2054 : state = "disabled";
375 3134 : else if (n->state == VLIB_NODE_STATE_INTERRUPT)
376 1131 : state = "interrupt wait";
377 : }
378 :
379 125442 : return format (s, "%s", state);
380 : }
381 :
382 : static u8 *
383 127401 : format_vlib_node_stats (u8 * s, va_list * va)
384 : {
385 127401 : vlib_main_t *vm = va_arg (*va, vlib_main_t *);
386 127401 : vlib_node_t *n = va_arg (*va, vlib_node_t *);
387 127401 : int max = va_arg (*va, int);
388 : f64 v;
389 : u8 *ns;
390 127401 : u8 *misc_info = 0;
391 : u64 c, p, l, d;
392 : f64 x;
393 : f64 maxc, maxcn;
394 : u32 maxn;
395 : u32 indent;
396 :
397 127401 : if (!n)
398 : {
399 1966 : if (max)
400 0 : s = format (s,
401 : "%=30s%=17s%=16s%=16s%=16s%=16s",
402 : "Name", "Max Node Clocks", "Vectors at Max",
403 : "Max Clocks", "Avg Clocks", "Avg Vectors/Call");
404 : else
405 1966 : s = format (s,
406 : "%=30s%=12s%=16s%=16s%=16s%=16s%=16s",
407 : "Name", "State", "Calls", "Vectors", "Suspends",
408 : "Clocks", "Vectors/Call");
409 1966 : return s;
410 : }
411 :
412 125435 : indent = format_get_indent (s);
413 :
414 125435 : l = n->stats_total.clocks - n->stats_last_clear.clocks;
415 125435 : c = n->stats_total.calls - n->stats_last_clear.calls;
416 125435 : p = n->stats_total.vectors - n->stats_last_clear.vectors;
417 125435 : d = n->stats_total.suspends - n->stats_last_clear.suspends;
418 125435 : maxc = (f64) n->stats_total.max_clock;
419 125435 : maxn = n->stats_total.max_clock_n;
420 125435 : if (n->stats_total.max_clock_n)
421 46233 : maxcn = (f64) n->stats_total.max_clock / (f64) maxn;
422 : else
423 79202 : maxcn = 0.0;
424 :
425 : /* Clocks per packet, per call or per suspend. */
426 125435 : x = 0;
427 125435 : if (p > 0)
428 51066 : x = (f64) l / (f64) p;
429 74369 : else if (c > 0)
430 4759 : x = (f64) l / (f64) c;
431 69610 : else if (d > 0)
432 69609 : x = (f64) l / (f64) d;
433 :
434 125435 : if (c > 0)
435 55825 : v = (double) p / (double) c;
436 : else
437 69610 : v = 0;
438 :
439 125435 : if (n->type == VLIB_NODE_TYPE_PROCESS)
440 : {
441 71002 : vlib_process_t *p = vlib_get_process_from_node (vm, n);
442 :
443 : /* Show processes with events pending. This helps spot bugs where events are not
444 : being handled. */
445 71002 : if (!clib_bitmap_is_zero (p->non_empty_event_type_bitmap))
446 0 : misc_info = format (misc_info, "events pending, ");
447 : }
448 125435 : ns = n->name;
449 :
450 125435 : if (max)
451 0 : s = format (s, "%-30v%=17.2e%=16d%=16.2e%=16.2e%=16.2e",
452 : ns, maxc, maxn, maxcn, x, v);
453 : else
454 125435 : s = format (s, "%-30v%=12U%16Ld%16Ld%16Ld%16.2e%16.2f", ns,
455 : format_vlib_node_state, vm, n, c, p, d, x, v);
456 :
457 125435 : if (ns != n->name)
458 0 : vec_free (ns);
459 :
460 125435 : if (misc_info)
461 : {
462 0 : s = format (s, "\n%U%v", format_white_space, indent + 4, misc_info);
463 0 : vec_free (misc_info);
464 : }
465 :
466 125435 : return s;
467 : }
468 :
469 : static clib_error_t *
470 1579 : show_node_runtime (vlib_main_t * vm,
471 : unformat_input_t * input, vlib_cli_command_t * cmd)
472 : {
473 1579 : vlib_node_main_t *nm = &vm->node_main;
474 : vlib_node_t *n;
475 : f64 time_now;
476 : u32 node_index;
477 1579 : vlib_node_t ***node_dups = 0;
478 1579 : f64 *internal_node_vector_rates = 0;
479 :
480 1579 : time_now = vlib_time_now (vm);
481 :
482 1579 : if (unformat (input, "%U", unformat_vlib_node, vm, &node_index))
483 : {
484 1 : n = vlib_get_node (vm, node_index);
485 1 : vlib_node_sync_stats (vm, n);
486 1 : vlib_cli_output (vm, "%U\n", format_vlib_node_stats, vm, 0, 0);
487 1 : vlib_cli_output (vm, "%U\n", format_vlib_node_stats, vm, n, 0);
488 : }
489 : else
490 : {
491 : vlib_node_t **nodes;
492 : uword i, j;
493 : f64 dt;
494 : u64 n_input, n_output, n_drop, n_punt;
495 : u64 n_clocks, l, v, c, d;
496 1578 : int brief = 1;
497 1578 : int summary = 0;
498 1578 : int max = 0;
499 1578 : vlib_main_t **stat_vms = 0, *stat_vm;
500 :
501 : /* Suppress nodes with zero calls since last clear */
502 1578 : if (unformat (input, "brief") || unformat (input, "b"))
503 1 : brief = 1;
504 1578 : if (unformat (input, "verbose") || unformat (input, "v"))
505 1 : brief = 0;
506 1578 : if (unformat (input, "max") || unformat (input, "m"))
507 1 : max = 1;
508 1578 : if (unformat (input, "summary") || unformat (input, "sum")
509 1577 : || unformat (input, "su"))
510 1 : summary = 1;
511 :
512 3545 : for (i = 0; i < vlib_get_n_threads (); i++)
513 : {
514 1967 : stat_vm = vlib_get_main_by_index (i);
515 1967 : if (stat_vm)
516 1967 : vec_add1 (stat_vms, stat_vm);
517 : }
518 :
519 : /*
520 : * Barrier sync across stats scraping.
521 : * Otherwise, the counts will be grossly inaccurate.
522 : */
523 1578 : vlib_worker_thread_barrier_sync (vm);
524 :
525 3545 : for (j = 0; j < vec_len (stat_vms); j++)
526 : {
527 1967 : stat_vm = stat_vms[j];
528 1967 : nm = &stat_vm->node_main;
529 :
530 1431140 : for (i = 0; i < vec_len (nm->nodes); i++)
531 : {
532 1429170 : n = nm->nodes[i];
533 1429170 : vlib_node_sync_stats (stat_vm, n);
534 : }
535 :
536 1967 : nodes = vec_dup (nm->nodes);
537 :
538 1967 : vec_add1 (node_dups, nodes);
539 1967 : vec_add1 (internal_node_vector_rates,
540 : vlib_internal_node_vector_rate (stat_vm));
541 : }
542 1578 : vlib_worker_thread_barrier_release (vm);
543 :
544 :
545 3545 : for (j = 0; j < vec_len (stat_vms); j++)
546 : {
547 1967 : stat_vm = stat_vms[j];
548 1967 : nodes = node_dups[j];
549 :
550 1967 : vec_sort_with_function (nodes, node_cmp);
551 :
552 1967 : n_input = n_output = n_drop = n_punt = n_clocks = 0;
553 1431140 : for (i = 0; i < vec_len (nodes); i++)
554 : {
555 1429170 : n = nodes[i];
556 :
557 1429170 : l = n->stats_total.clocks - n->stats_last_clear.clocks;
558 1429170 : n_clocks += l;
559 :
560 1429170 : v = n->stats_total.vectors - n->stats_last_clear.vectors;
561 :
562 1429170 : switch (n->type)
563 : {
564 100359 : default:
565 100359 : continue;
566 :
567 1273740 : case VLIB_NODE_TYPE_INTERNAL:
568 1273740 : n_output += (n->flags & VLIB_NODE_FLAG_IS_OUTPUT) ? v : 0;
569 1273740 : n_drop += (n->flags & VLIB_NODE_FLAG_IS_DROP) ? v : 0;
570 1273740 : n_punt += (n->flags & VLIB_NODE_FLAG_IS_PUNT) ? v : 0;
571 1273740 : if (n->flags & VLIB_NODE_FLAG_IS_HANDOFF)
572 0 : n_input += v;
573 1273740 : break;
574 :
575 55076 : case VLIB_NODE_TYPE_INPUT:
576 55076 : n_input += v;
577 55076 : break;
578 : }
579 : }
580 :
581 1967 : if (vlib_get_n_threads () > 1)
582 : {
583 525 : vlib_worker_thread_t *w = vlib_worker_threads + j;
584 525 : if (j > 0)
585 389 : vlib_cli_output (vm, "---------------");
586 :
587 525 : if (w->cpu_id > -1)
588 525 : vlib_cli_output (vm, "Thread %d %s (lcore %u)", j, w->name,
589 : w->cpu_id);
590 : else
591 0 : vlib_cli_output (vm, "Thread %d %s", j, w->name);
592 : }
593 :
594 1967 : dt = time_now - nm->time_last_runtime_stats_clear;
595 1967 : vlib_cli_output (
596 : vm,
597 : "Time %.1f, %f sec internal node vector rate %.2f loops/sec %.2f\n"
598 : " vector rates in %.4e, out %.4e, drop %.4e, punt %.4e",
599 : dt, vlib_stats_get_segment_update_rate (),
600 1967 : internal_node_vector_rates[j], stat_vm->loops_per_second,
601 1967 : (f64) n_input / dt, (f64) n_output / dt, (f64) n_drop / dt,
602 1967 : (f64) n_punt / dt);
603 :
604 1967 : if (summary == 0)
605 : {
606 1965 : vlib_cli_output (vm, "%U", format_vlib_node_stats, stat_vm,
607 : 0, max);
608 1429690 : for (i = 0; i < vec_len (nodes); i++)
609 : {
610 1427720 : c =
611 1427720 : nodes[i]->stats_total.calls -
612 1427720 : nodes[i]->stats_last_clear.calls;
613 1427720 : d =
614 1427720 : nodes[i]->stats_total.suspends -
615 1427720 : nodes[i]->stats_last_clear.suspends;
616 1427720 : if (c || d || !brief)
617 : {
618 125434 : vlib_cli_output (vm, "%U", format_vlib_node_stats,
619 125434 : stat_vm, nodes[i], max);
620 : }
621 : }
622 : }
623 1967 : vec_free (nodes);
624 : }
625 1578 : vec_free (stat_vms);
626 1578 : vec_free (node_dups);
627 1578 : vec_free (internal_node_vector_rates);
628 : }
629 :
630 1579 : return 0;
631 : }
632 :
633 : /* *INDENT-OFF* */
634 285289 : VLIB_CLI_COMMAND (show_node_runtime_command, static) = {
635 : .path = "show runtime",
636 : .short_help = "Show packet processing runtime",
637 : .function = show_node_runtime,
638 : .is_mp_safe = 1,
639 : };
640 : /* *INDENT-ON* */
641 :
642 : static clib_error_t *
643 1 : clear_node_runtime (vlib_main_t * vm,
644 : unformat_input_t * input, vlib_cli_command_t * cmd)
645 : {
646 : vlib_node_main_t *nm;
647 : vlib_node_t *n;
648 : int i, j;
649 1 : vlib_main_t **stat_vms = 0, *stat_vm;
650 : vlib_node_runtime_t *r;
651 :
652 3 : for (i = 0; i < vlib_get_n_threads (); i++)
653 : {
654 2 : stat_vm = vlib_get_main_by_index (i);
655 2 : if (stat_vm)
656 2 : vec_add1 (stat_vms, stat_vm);
657 : }
658 :
659 1 : vlib_worker_thread_barrier_sync (vm);
660 :
661 3 : for (j = 0; j < vec_len (stat_vms); j++)
662 : {
663 2 : stat_vm = stat_vms[j];
664 2 : nm = &stat_vm->node_main;
665 :
666 1448 : for (i = 0; i < vec_len (nm->nodes); i++)
667 : {
668 1446 : n = nm->nodes[i];
669 1446 : vlib_node_sync_stats (stat_vm, n);
670 1446 : n->stats_last_clear = n->stats_total;
671 :
672 1446 : r = vlib_node_get_runtime (stat_vm, n->index);
673 1446 : r->max_clock = 0;
674 : }
675 : /* Note: input/output rates computed using vlib_global_main */
676 2 : nm->time_last_runtime_stats_clear = vlib_time_now (vm);
677 : }
678 :
679 1 : vlib_stats_set_timestamp (STAT_COUNTER_LAST_STATS_CLEAR,
680 : vm->node_main.time_last_runtime_stats_clear);
681 1 : vlib_worker_thread_barrier_release (vm);
682 :
683 1 : vec_free (stat_vms);
684 :
685 1 : return 0;
686 : }
687 :
688 : /* *INDENT-OFF* */
689 285289 : VLIB_CLI_COMMAND (clear_node_runtime_command, static) = {
690 : .path = "clear runtime",
691 : .short_help = "Clear packet processing runtime statistics",
692 : .function = clear_node_runtime,
693 : };
694 : /* *INDENT-ON* */
695 :
696 : static clib_error_t *
697 7 : show_node (vlib_main_t * vm, unformat_input_t * input,
698 : vlib_cli_command_t * cmd)
699 : {
700 7 : unformat_input_t _line_input, *line_input = &_line_input;
701 7 : clib_error_t *error = 0;
702 7 : vlib_node_main_t *nm = &vm->node_main;
703 : vlib_node_t *n;
704 7 : u8 *s = 0, *s2 = 0;
705 7 : u32 i, node_index = ~0, verbose = 0;
706 : char *type_str;
707 7 : u8 valid_node_name = 0;
708 : u64 cl, ca, v;
709 :
710 7 : if (!unformat_user (input, unformat_line_input, line_input))
711 0 : return 0;
712 :
713 14 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
714 : {
715 7 : if (unformat (line_input, "index %u", &node_index))
716 : ;
717 6 : else if (unformat (line_input, "verbose"))
718 0 : verbose = 1;
719 : else
720 6 : if (unformat (line_input, "%U", unformat_vlib_node, vm, &node_index))
721 6 : valid_node_name = 1;
722 0 : else if (!valid_node_name)
723 0 : error = clib_error_return (0, "unknown node name: '%U'",
724 : format_unformat_error, line_input);
725 : else
726 0 : error = clib_error_return (0, "unknown input '%U'",
727 : format_unformat_error, line_input);
728 :
729 7 : if (error)
730 0 : break;
731 : }
732 :
733 7 : unformat_free (line_input);
734 :
735 7 : if (error)
736 0 : return error;
737 :
738 7 : if (node_index >= vec_len (vm->node_main.nodes))
739 0 : return clib_error_return (0, "please specify valid node");
740 :
741 7 : n = vlib_get_node (vm, node_index);
742 7 : vlib_node_sync_stats (vm, n);
743 :
744 7 : switch (n->type)
745 : {
746 5 : case VLIB_NODE_TYPE_INTERNAL:
747 5 : type_str = "internal";
748 5 : break;
749 1 : case VLIB_NODE_TYPE_INPUT:
750 1 : type_str = "input";
751 1 : break;
752 0 : case VLIB_NODE_TYPE_PRE_INPUT:
753 0 : type_str = "pre-input";
754 0 : break;
755 1 : case VLIB_NODE_TYPE_PROCESS:
756 1 : type_str = "process";
757 1 : break;
758 0 : default:
759 0 : type_str = "unknown";
760 : }
761 :
762 7 : if (n->sibling_of)
763 1 : s = format (s, ", sibling-of %s", n->sibling_of);
764 :
765 7 : vlib_cli_output (vm, "node %v, type %s, state %U, index %d%v\n",
766 : n->name, type_str, format_vlib_node_state, vm, n,
767 : n->index, s);
768 7 : vec_reset_length (s);
769 :
770 7 : if (n->node_fn_registrations)
771 : {
772 5 : vlib_node_fn_registration_t *fnr = n->node_fn_registrations;
773 : vlib_node_fn_variant_t *v;
774 25 : while (fnr)
775 : {
776 20 : v = vec_elt_at_index (vm->node_main.variants, fnr->march_variant);
777 20 : if (vec_len (s) == 0)
778 5 : s = format (s, "\n %-15s %=8s %6s %s", "Name", "Priority",
779 : "Active", "Description");
780 20 : s = format (s, "\n %-15s %8d %=6s %s", v->suffix, v->priority,
781 20 : fnr->function == n->function ? "yes" : "", v->desc);
782 20 : fnr = fnr->next_registration;
783 : }
784 : }
785 : else
786 2 : s = format (s, "\n default only");
787 7 : vlib_cli_output (vm, " node function variants:%v\n", s);
788 7 : vec_reset_length (s);
789 :
790 61 : for (i = 0; i < vec_len (n->next_nodes); i++)
791 : {
792 : vlib_node_t *pn;
793 54 : if (n->next_nodes[i] == VLIB_INVALID_NODE_INDEX)
794 0 : continue;
795 :
796 54 : pn = vec_elt (nm->nodes, n->next_nodes[i]);
797 :
798 54 : if (vec_len (s) == 0)
799 6 : s = format (s, "\n %10s %10s %=30s %8s",
800 : "next-index", "node-index", "Node", "Vectors");
801 :
802 54 : s = format (s, "\n %=10u %=10u %=30v %=8llu", i, n->next_nodes[i],
803 54 : pn->name, vec_elt (n->n_vectors_by_next_node, i));
804 : }
805 :
806 7 : if (vec_len (s) == 0)
807 1 : s = format (s, "\n none");
808 7 : vlib_cli_output (vm, "\n next nodes:%v\n", s);
809 7 : vec_reset_length (s);
810 :
811 7 : if (n->type == VLIB_NODE_TYPE_INTERNAL)
812 : {
813 5 : int j = 0;
814 : /* *INDENT-OFF* */
815 194 : clib_bitmap_foreach (i, n->prev_node_bitmap) {
816 189 : vlib_node_t *pn = vlib_get_node (vm, i);
817 189 : if (j++ % 3 == 0)
818 63 : s = format (s, "\n ");
819 189 : s2 = format (s2, "%v (%u)", pn->name, i);
820 189 : s = format (s, "%-35v", s2);
821 189 : vec_reset_length (s2);
822 : }
823 : /* *INDENT-ON* */
824 :
825 5 : if (vec_len (s) == 0)
826 0 : s = format (s, "\n none");
827 5 : vlib_cli_output (vm, "\n known previous nodes:%v\n", s);
828 5 : vec_reset_length (s);
829 5 : vec_free (s2);
830 : }
831 :
832 7 : if (!verbose)
833 7 : goto done;
834 :
835 0 : s = format (s, "\n%8s %=12s %=12s %=12s %=12s %=12s\n", "Thread", "Calls",
836 : "Clocks", "Vectors", "Max Clock", "Max Vectors");
837 0 : for (i = 0; i < vlib_get_n_threads (); i++)
838 : {
839 0 : n = vlib_get_node (vlib_get_main_by_index (i), node_index);
840 0 : vlib_node_sync_stats (vlib_get_main_by_index (i), n);
841 :
842 0 : cl = n->stats_total.clocks - n->stats_last_clear.clocks;
843 0 : ca = n->stats_total.calls - n->stats_last_clear.calls;
844 0 : v = n->stats_total.vectors - n->stats_last_clear.vectors;
845 :
846 0 : s = format (s, "%=8u %=12lu %=12lu %=12lu %=12u %=12u\n", i, ca, cl, v,
847 : n->stats_total.max_clock, n->stats_total.max_clock_n);
848 : }
849 :
850 0 : vlib_cli_output (vm, "%v", s);
851 :
852 7 : done:
853 :
854 7 : vec_free (s);
855 7 : return 0;
856 : }
857 :
858 : /* *INDENT-OFF* */
859 285289 : VLIB_CLI_COMMAND (show_node_command, static) = {
860 : .path = "show node",
861 : .short_help = "show node [index] <node-name | node-index>",
862 : .function = show_node,
863 : };
864 :
865 : static clib_error_t *
866 6 : set_node_fn(vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
867 : {
868 6 : unformat_input_t _line_input, *line_input = &_line_input;
869 : u32 node_index, march_variant;
870 : vlib_node_t *n;
871 6 : clib_error_t *err = 0;
872 :
873 6 : if (!unformat_user (input, unformat_line_input, line_input))
874 1 : return 0;
875 :
876 5 : if (!unformat (line_input, "%U", unformat_vlib_node, vm, &node_index))
877 : {
878 1 : err = clib_error_return (0, "please specify valid node name");
879 1 : goto done;
880 : }
881 :
882 4 : if (!unformat (line_input, "%U", unformat_vlib_node_variant, &march_variant))
883 : {
884 2 : err = clib_error_return (0, "please specify node function variant");
885 2 : goto done;
886 : }
887 :
888 2 : n = vlib_get_node (vm, node_index);
889 :
890 2 : if (n->node_fn_registrations == 0)
891 : {
892 1 : err = clib_error_return (0, "node doesn't have function variants");
893 1 : goto done;
894 : }
895 :
896 1 : if (vlib_node_set_march_variant (vm, node_index, march_variant))
897 : {
898 : vlib_node_fn_variant_t *v;
899 0 : v = vec_elt_at_index (vm->node_main.variants, march_variant);
900 0 : err = clib_error_return (0, "node function variant '%s' not found",
901 : v->suffix);
902 0 : goto done;
903 : }
904 :
905 :
906 1 : done:
907 5 : unformat_free (line_input);
908 5 : return err;
909 : }
910 :
911 : /* *INDENT-OFF* */
912 285289 : VLIB_CLI_COMMAND (set_node_fn_command, static) = {
913 : .path = "set node function",
914 : .short_help = "set node function <node-name> <variant-name>",
915 : .function = set_node_fn,
916 : };
917 : /* *INDENT-ON* */
918 :
919 : /* Dummy function to get us linked in. */
920 : void
921 575 : vlib_node_cli_reference (void)
922 : {
923 575 : }
924 :
925 : /*
926 : * fd.io coding-style-patch-verification: ON
927 : *
928 : * Local Variables:
929 : * eval: (c-set-style "gnu")
930 : * End:
931 : */
|