LCOV - code coverage report
Current view: top level - vlib - node_cli.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 324 404 80.2 %
Date: 2023-10-26 01:39:38 Functions: 22 22 100.0 %

          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             :  */

Generated by: LCOV version 1.14