Avneesh - Can you expand a bit on why adding the ability to call random functions from the cli is better than just adding a 'test XXX' function as needed? Additionally how do you plan to allow the end user to pass in useful data to functions if the function you want to call takes a complex data structure? I'm pretty dubious about adding a cause a crash button even for developer builds, especially since adding a test XXX function is an easy task.
donald On Fri, Mar 11, 2016 at 3:21 PM, Avneesh Sachdev <[email protected]> wrote: > 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 >
_______________________________________________ Quagga-dev mailing list [email protected] https://lists.quagga.net/mailman/listinfo/quagga-dev
