This functionality is only compiled into a developer build, It allows
test functions to be invoked by name from the vtysh as follows.

Changes:

  * vtysh/vtysh.c

    Handle the 'invoke <component> function <function-name> [args]' command.
    Forward it the client with the given name.

  * lib/vty_invoke.c

    Code that handles an 'invoke function' command inside a vtysh
    client process (e;g., a routing protocol daemon). It invokes the
    named function, and prints out some stats about the execution
    time.

  * lib/thread.h

    Extern timeval_elapsed().

  * lib/vty.[ch]

    - vty_init():

      Install element for 'invoke' command handler. This sets up the
      handler that runs inside of a vtysh client.

  * lib/Makefile.am

    Also compile vty_invoke.c.

  * configure.ac

    Include '-rdynamic -ldl' in LDFLAGS for a development build. These
    options allow dlsym() to work for functions inside a quagga
    program.

Signed-off-by: Avneesh Sachdev <[email protected]>
---
 configure.ac     |   4 ++
 lib/Makefile.am  |   2 +-
 lib/thread.h     |   3 ++
 lib/vty.c        |   4 ++
 lib/vty_invoke.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/vty_invoke.h |  30 ++++++++++++++
 vtysh/vtysh.c    |  78 ++++++++++++++++++++++++++++++++++++
 7 files changed, 240 insertions(+), 1 deletion(-)
 create mode 100644 lib/vty_invoke.c
 create mode 100644 lib/vty_invoke.h

diff --git a/configure.ac b/configure.ac
index ae2e527..60a9118 100755
--- a/configure.ac
+++ b/configure.ac
@@ -331,6 +331,10 @@ fi
 
 if test "x${enable_dev_build}" = "xyes"; then
    AC_DEFINE(DEV_BUILD,,Build for development)
+
+   # Link with -ldl so that the developer build can use dlsym and
+   # company.
+   LDFLAGS="${LDFLAGS} -rdynamic -ldl"
 fi
 AM_CONDITIONAL([DEV_BUILD], [test "x$enable_dev_build" = "xyes"])
 
diff --git a/lib/Makefile.am b/lib/Makefile.am
index ac51fc6..17dc575 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -13,7 +13,7 @@ libzebra_la_SOURCES = \
        sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
        filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
        zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c 
privs.c \
-       sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c
+       sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c vty_invoke.c
 
 BUILT_SOURCES = memtypes.h route_types.h gitversion.h
 
diff --git a/lib/thread.h b/lib/thread.h
index 5bc756c..215ac5d 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -229,6 +229,9 @@ extern time_t quagga_time (time_t *);
 extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
                                          unsigned long *cpu_time_elapsed);
 
+/* Returns elapsed time in microseconds */
+extern unsigned long timeval_elapsed (struct timeval a, struct timeval b);
+
 /* Global variable containing a recent result from gettimeofday.  This can
    be used instead of calling gettimeofday if a recent value is sufficient.
    This is guaranteed to be refreshed before a thread is called. */
diff --git a/lib/vty.c b/lib/vty.c
index 8befcb0..657ed97 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -40,6 +40,8 @@
 #include <arpa/telnet.h>
 #include <termios.h>
 
+#include "vty_invoke.h"
+
 /* Vty events */
 enum event 
 {
@@ -3073,6 +3075,8 @@ vty_init (struct thread_master *master_thread)
   install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
   install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
 #endif /* HAVE_IPV6 */
+
+  vty_invoke_init ();
 }
 
 void
diff --git a/lib/vty_invoke.c b/lib/vty_invoke.c
new file mode 100644
index 0000000..3c43568
--- /dev/null
+++ b/lib/vty_invoke.c
@@ -0,0 +1,120 @@
+/*
+ * vty_invoke.c
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <[email protected]>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/*
+ * Support for invoking functions by name from a vty shell.
+ *
+ * This code is only compiled into a developer build, and allows
+ * functions that follow certain signatures to be invoked by name from
+ * the vtysh.
+ */
+
+#include <zebra.h>
+
+#include <dlfcn.h>
+
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+
+#include "vty_invoke.h"
+
+typedef int (*vty_invoke_func_t) (int argc, const char **argv);
+
+#ifdef DEV_BUILD
+
+DEFUN (invoke_function,
+       invoke_function_cmd,
+       "invoke function NAME [ARG1] [ARG2] [ARG3] [ARG4] [ARG5] [ARG6]",
+       "Invoke\n"
+       "Invoke a function\n"
+       "Name of function to invoke\n"
+       "First argument\n"
+       "Second argument\n"
+       "Third argument\n"
+       "Fourth argument\n"
+       "Fifth argument\n"
+       "Sixth argument\n")
+{
+  int i;
+  const char *func_name;
+  vty_invoke_func_t func;
+  RUSAGE_T before, after;
+  ulong elapsed;
+
+  assert (argc >= 1);
+
+  func_name = argv[0];
+
+  func = dlsym (NULL, func_name);
+  if (!func)
+    {
+      vty_out (vty, "Can't find function %s", func_name);
+      return CMD_WARNING;
+    }
+
+  vty_out (vty, "Invoking %s(", func_name);
+
+  for (i = 1; i < argc; i++)
+    {
+      vty_out (vty, "%s%s", i == 1 ? "" : ", ", argv[i]);
+    }
+  vty_out (vty, ")\n");
+
+  GETRUSAGE (&before);
+  i = func (argc - 1, argv + 1);
+  GETRUSAGE (&after);
+
+  vty_out (vty, "Return value: %d\n\n", i);
+
+  elapsed = timeval_elapsed (after.real, before.real);
+  vty_out (vty, "%-20s %9lu ms\n", "Real time:", elapsed / 1000);
+
+#ifdef HAVE_RUSAGE
+  {
+    elapsed = timeval_elapsed (after.cpu.ru_utime, before.cpu.ru_utime);
+
+    vty_out (vty, "%-20s %9lu ms\n", "User time:", elapsed / 1000);
+
+    elapsed = timeval_elapsed (after.cpu.ru_stime, before.cpu.ru_stime);
+    vty_out (vty, "%-20s %9lu ms\n", "System time:", elapsed / 1000);
+  }
+#endif
+
+  return CMD_SUCCESS;
+}
+
+#endif /* DEV_BUILD */
+
+/*
+ * vty_invoke_init
+ */
+void
+vty_invoke_init (void)
+{
+#ifdef DEV_BUILD
+  install_element (ENABLE_NODE, &invoke_function_cmd);
+#endif
+}
diff --git a/lib/vty_invoke.h b/lib/vty_invoke.h
new file mode 100644
index 0000000..a2364a2
--- /dev/null
+++ b/lib/vty_invoke.h
@@ -0,0 +1,30 @@
+/*
+ * vty_invoke.h
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <[email protected]>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef _VTY_INVOKE_H
+#define _VTY_INVOKE_H
+
+extern void vty_invoke_init (void);
+
+#endif /* _VTY_INVOKE_H */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index b55c671..b0f96d9 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2149,6 +2149,80 @@ DEFUN (vtysh_start_zsh,
   return CMD_SUCCESS;
 }
 
+#ifdef DEV_BUILD
+
+/*
+ * 'invoke' command
+ *
+ * Command that allows user to invoke functions from the cli shell in
+ * development build.
+ */
+DEFUN (invoke_function,
+       invoke_function_cmd,
+       "invoke COMPONENT function NAME [ARG1] [ARG2] [ARG3] [ARG4] [ARG5] 
[ARG6]",
+       "Invoke\n"
+       "Component name in which to invoke function\n"
+       "Invoke a function\n"
+       "Name of function to invoke\n"
+       "First argument\n"
+       "Second argument\n"
+       "Third argument\n"
+       "Fourth argument\n"
+       "Fifth argument\n"
+       "Sixth argument\n")
+{
+  unsigned int u;
+  char line[1000];
+  char *cur, *end;
+  int ret, i;
+  const char *component_name;
+  struct vtysh_client *client;
+
+  cur = line;
+  end = cur + sizeof (line);
+
+  cur += snprintf (cur, end - cur, "invoke function ");
+
+  /*
+   * Build command string, skipping over the component name.
+   */
+  for (i = 1; i < argc; i++)
+    {
+      ret = snprintf (cur, end - cur, "%s ", argv[i]);
+      if (ret < 0 || ret == (end - cur))
+       {
+         vty_out (vty, "Command string is too long");
+         return CMD_WARNING;
+       }
+      cur += ret;
+    }
+
+  component_name = argv[0];
+
+  for (u = 0; u < array_size (vtysh_client); u++)
+    {
+      client = &vtysh_client[u];
+      if (strcmp (client->name, component_name))
+       {
+         continue;
+       }
+      if (client->fd < 0)
+       {
+         fprintf (stdout, "Not connected to component %s\n", component_name);
+         return CMD_WARNING;
+       }
+
+      ret = vtysh_client_execute (client, line, stdout);
+      fprintf (stdout, "\n");
+      return ret;
+    }
+
+  fprintf (stdout, "Could not find component %s\n", component_name);
+  return CMD_WARNING;
+}
+
+#endif /* DEV_BUILD */
+
 static void
 vtysh_install_default (enum node_type node)
 {
@@ -2530,4 +2604,8 @@ vtysh_init_vty (void)
   install_element (CONFIG_NODE, &vtysh_enable_password_text_cmd);
   install_element (CONFIG_NODE, &no_vtysh_enable_password_cmd);
 
+#ifdef DEV_BUILD
+  install_element (ENABLE_NODE, &invoke_function_cmd);
+#endif
+
 }
-- 
1.9.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to