diff --git a/lib/command.c b/lib/command.c index 87110157f6..99f86ec680 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2279,6 +2279,22 @@ done: return CMD_SUCCESS; } +#ifdef DEV_BUILD +DEFUN(script, + script_cmd, + "script SCRIPT", + "Test command - execute a script\n" + "Script name (same as filename in /etc/frr/scripts/\n") +{ + struct frrscript *fs = frrscript_load(argv[2]->arg, NULL); + int ret = frrscript_call(fs, 42); + + vty_out(vty, "Script result: %d\n", ret); + + return CMD_SUCCESS; +} +#endif + /* Set config filename. Called from vty.c */ void host_config_set(const char *filename) { diff --git a/lib/frrlua.c b/lib/frrlua.c index 15fda79201..57288e6676 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -26,6 +26,9 @@ #include "frrlua.h" #include "log.h" #include "buffer.h" +#include "frrscript.h" + +/* Lua stuff */ /* * FRR convenience functions. diff --git a/lib/frrlua.h b/lib/frrlua.h index bc017b6441..37e8e8635b 100644 --- a/lib/frrlua.h +++ b/lib/frrlua.h @@ -26,6 +26,7 @@ #include "lauxlib.h" #include "prefix.h" +#include "frrscript.h" #ifdef __cplusplus extern "C" { diff --git a/lib/frrscript.c b/lib/frrscript.c new file mode 100644 index 0000000000..9b27ca7459 --- /dev/null +++ b/lib/frrscript.c @@ -0,0 +1,133 @@ +/* Scripting foo + * Copyright (C) 2020 NVIDIA Corporation + * Quentin Young + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "frrscript.h" +#include "memory.h" +#include "hash.h" +#include "log.h" + +#include "frrlua.h" + +/* Type encoders */ + +struct encoder { + char *typename; + int (*encoder)(struct lua_State *, const void *); +}; + +struct hash *encoder_hash; + +static unsigned int encoder_hash_key(const void *data) +{ + const struct encoder *e = data; + + return string_hash_make(e->typename); +} + +static bool encoder_hash_cmp(const void *d1, const void *d2) +{ + return !strcmp(d1, d2); +} + +static void *encoder_alloc(void *arg) +{ + struct encoder *tmp = arg; + + struct encoder *e = XCALLOC(MTYPE_TMP, sizeof(struct encoder)); + e->typename = XSTRDUP(MTYPE_TMP, tmp->typename); + + return e; +} + +#if 0 +static void encoder_free(struct encoder *e) +{ + XFREE(MTYPE_TMP, e->typename); + XFREE(MTYPE_TMP, e); +} +#endif + +/* Generic script APIs */ + +int frrscript_lua_call(struct frrscript *fs, ...) +{ + /* Process arguments according to argspec in fs */ + /* ... */ + + int ret = lua_pcall(fs->L, 0, 0, 0); + + /* Process stack result according to argspec in fs */ + /* ... */ + + /* LUA_OK is 0, so we can just return lua_pcall's result directly */ + return ret; +} + +void frrscript_register_type_encoder(const char *typename, + int (*encoder)(lua_State *L, void *)) +{ + struct encoder e = { + .typename = (char *) typename, + .encoder = NULL + }; + + if (hash_lookup(encoder_hash, &e)) { + zlog_backtrace(LOG_ERR); + assert(!"Type encoder double-registered."); + } + + hash_get(encoder_hash, &e, encoder_alloc); +} + + +struct frrscript *frrscript_load(const char *name, + int (*load_cb)(struct frrscript *)) +{ + struct frrscript *fs = XCALLOC(MTYPE_TMP, sizeof(struct frrscript)); + + fs->name = XSTRDUP(MTYPE_TMP, name); + fs->L = luaL_newstate(); + + char fname[MAXPATHLEN]; + snprintf(fname, sizeof(fname), FRRSCRIPT_PATH "/%s.lua", fs->name); + + if (luaL_loadfile(fs->L, fname) != LUA_OK) + goto fail; + + if (load_cb && (*load_cb)(fs) != 0) + goto fail; + + return fs; +fail: + frrscript_unload(fs); + return NULL; +} + +void frrscript_unload(struct frrscript *fs) +{ + XFREE(MTYPE_TMP, fs->name); + XFREE(MTYPE_TMP, fs); +} + +void frrscript_init() +{ + encoder_hash = hash_create(encoder_hash_key, encoder_hash_cmp, "Lua type encoders"); +} diff --git a/lib/frrscript.h b/lib/frrscript.h new file mode 100644 index 0000000000..2988d90aa8 --- /dev/null +++ b/lib/frrscript.h @@ -0,0 +1,84 @@ +/* Scripting foo + * Copyright (C) 2020 NVIDIA Corporation + * Quentin Young + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __FRRSCRIPT_H__ +#define __FRRSCRIPT_H__ + +#include "frrlua.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FRRSCRIPT_PATH "/etc/frr/scripts" + +struct frrscript { + /* Script name */ + char *name; + + /* Lua state */ + struct lua_State *L; +}; + + +/* + * Create new FRR script. + */ +struct frrscript *frrscript_load(const char *name, + int (*load_cb)(struct frrscript *)); + +/* + * Destroy FRR script. + */ +void frrscript_unload(struct frrscript *fs); + +/* + * Register a Lua encoder for a type. + * + * tname + * Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will. + * + * encoder + * Function pointer to encoder function. Encoder function should push a Lua + * table representing the passed argument - which will have the C type + * associated with the chosen 'tname' to the provided stack. + * + */ +void frrscript_register_type_encoder(const char *tname, + int (*encoder)(lua_State *, void *)); + +/* + * Initialize scripting subsystem. Call this before anything else. + */ +void frrscript_init(void); + +/* + * Forward decl for frrscript_lua_call + */ +int frrscript_lua_call(struct frrscript *fs, ...); + +/* + * Call FRR script. + */ +#define frrscript_call(fs, ...) frrscript_lua_call((fs), __VA_ARGS__) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FRRSCRIPT_H__ */ diff --git a/lib/subdir.am b/lib/subdir.am index 038282a99b..c5e32a56d9 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -26,6 +26,7 @@ lib_libfrr_la_SOURCES = \ lib/filter_nb.c \ lib/frrcu.c \ lib/frrlua.c \ + lib/frrscript.c \ lib/frr_pthread.c \ lib/frrstr.c \ lib/getopt.c \ @@ -184,6 +185,7 @@ pkginclude_HEADERS += \ lib/filter.h \ lib/freebsd-queue.h \ lib/frrlua.h \ + lib/frrscript.h \ lib/frr_pthread.h \ lib/frratomic.h \ lib/frrcu.h \