Add 'show vlib graphviz' command 14/17014/4
authorBenoît Ganne <bganne@cisco.com>
Mon, 21 Jan 2019 16:41:25 +0000 (17:41 +0100)
committerDamjan Marion <dmarion@me.com>
Thu, 31 Jan 2019 22:08:54 +0000 (22:08 +0000)
Add a new command to dump vlib graph as graphviz/dot file

Change-Id: I43fc072cff8153ac500e5fbc6641a3705c2e995e
Signed-off-by: Benoît Ganne <bganne@cisco.com>
src/vlib/format.c
src/vlib/format_funcs.h
src/vlib/main.c
src/vlib/node_cli.c

index 79a4d68..ee730bd 100644 (file)
@@ -187,6 +187,30 @@ done:
   return p != 0;
 }
 
+/* Parse a filename to dump debug info */
+uword
+unformat_vlib_tmpfile (unformat_input_t * input, va_list * args)
+{
+  u8 **chroot_filename = va_arg (*args, u8 **);
+  u8 *filename;
+
+  if (!unformat (input, "%s", &filename))
+    return 0;
+
+  /* Brain-police user path input */
+  if (strstr ((char *) filename, "..") || index ((char *) filename, '/'))
+    {
+      vec_free (filename);
+      return 0;
+    }
+
+  *chroot_filename = format (0, "/tmp/%s%c", filename, 0);
+  vec_free (filename);
+
+  return 1;
+}
+
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index f60b894..30e919d 100644 (file)
@@ -59,6 +59,9 @@ uword unformat_vlib_number_by_name (unformat_input_t * input, va_list * args);
 /* Parse an int either %d or 0x%x. */
 uword unformat_vlib_number (unformat_input_t * input, va_list * args);
 
+/* Parse a filename to dump debug info */
+uword unformat_vlib_tmpfile (unformat_input_t * input, va_list * args);
+
 /* Flag to format_vlib_*_header functions to tell them not to recurse
    into the next layer's header.  For example, tells format_vlib_ethernet_header
    not to format ip header. */
index c0ab8e1..c5153ab 100644 (file)
@@ -2126,7 +2126,9 @@ pcap_dispatch_trace_command_internal (vlib_main_t * vm,
            }
          pm->n_packets_to_capture = max;
        }
-      else if (unformat (line_input, "file %s", &filename))
+      else
+       if (unformat
+           (line_input, "file %U", unformat_vlib_tmpfile, &filename))
        {
          if (vm->dispatch_pcap_enable)
            {
@@ -2135,21 +2137,6 @@ pcap_dispatch_trace_command_internal (vlib_main_t * vm,
              errorFlag = 1;
              break;
            }
-
-         /* Brain-police user path input */
-         if (strstr ((char *) filename, "..")
-             || index ((char *) filename, '/'))
-           {
-             vlib_cli_output (vm, "illegal characters in filename '%s'",
-                              filename);
-             vlib_cli_output (vm, "Hint: .. and / are not allowed.");
-             vec_free (filename);
-             errorFlag = 1;
-             break;
-           }
-
-         chroot_filename = format (0, "/tmp/%s%c", filename, 0);
-         vec_free (filename);
        }
       else if (unformat (line_input, "status"))
        {
index ad17c1d..c8e32b5 100644 (file)
@@ -37,6 +37,9 @@
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <vlib/vlib.h>
 #include <vlib/threads.h>
 
@@ -88,6 +91,81 @@ VLIB_CLI_COMMAND (show_node_graph_command, static) = {
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+show_node_graphviz (vlib_main_t * vm,
+                   unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  clib_error_t *error = 0;
+  vlib_node_main_t *nm = &vm->node_main;
+  u8 *chroot_filename = 0;
+  int fd;
+  vlib_node_t **nodes = 0;
+  uword i, j;
+
+  if (!unformat_user (input, unformat_vlib_tmpfile, &chroot_filename))
+    {
+      fd = -1;
+    }
+  else
+    {
+      fd =
+       open ((char *) chroot_filename, O_CREAT | O_TRUNC | O_WRONLY, 0664);
+    }
+
+#define format__(vm__, fd__, ...) \
+  if ((fd) < 0) \
+    { \
+      vlib_cli_output((vm__), ## __VA_ARGS__); \
+    } \
+  else \
+    { \
+      fdformat((fd__), ## __VA_ARGS__); \
+    }
+
+  format__ (vm, fd, "%s", "digraph {\n");
+
+  nodes = vec_dup (nm->nodes);
+  vec_sort_with_function (nodes, node_cmp);
+
+  for (i = 0; i < vec_len (nodes); i++)
+    {
+      for (j = 0; j < vec_len (nodes[i]->next_nodes); j++)
+       {
+         vlib_node_t *x;
+
+         if (nodes[i]->next_nodes[j] == VLIB_INVALID_NODE_INDEX)
+           continue;
+
+         x = vec_elt (nm->nodes, nodes[i]->next_nodes[j]);
+         format__ (vm, fd, "  \"%v\" -> \"%v\"\n", nodes[i]->name, x->name);
+       }
+    }
+
+  format__ (vm, fd, "%s", "}");
+
+  if (fd >= 0)
+    {
+      vlib_cli_output (vm,
+                      "vlib graph dumped into `%s'. Run eg. `fdp -Tsvg -O %s'.",
+                      chroot_filename, chroot_filename);
+    }
+
+  vec_free (nodes);
+  vec_free (chroot_filename);
+  vec_free (nodes);
+  if (fd >= 0)
+    close (fd);
+  return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_node_graphviz_command, static) = {
+  .path = "show vlib graphviz",
+  .short_help = "Dump packet processing node graph as a graphviz dotfile",
+  .function = show_node_graphviz,
+};
+/* *INDENT-ON* */
+
 static u8 *
 format_vlib_node_state (u8 * s, va_list * va)
 {