From 3b002f19166ca8933c42ebf8f5a7b7794acd53bf Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Sun, 29 Nov 2020 02:00:26 -0500 Subject: [PATCH] lib: allow passing arguments to scripts - Add ability to pass arguments when calling a script - Add macros to define arguments and results Signed-off-by: Quentin Young --- lib/frrscript.c | 71 ++++++++++++++++++++++++++++++++++++++++++++----- lib/frrscript.h | 31 +++++++++++++++++++++ 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/lib/frrscript.c b/lib/frrscript.c index e7390a8d94..e523fcb475 100644 --- a/lib/frrscript.c +++ b/lib/frrscript.c @@ -18,6 +18,7 @@ */ #include +#include #include "frrscript.h" #include "memory.h" @@ -73,13 +74,64 @@ static void encoder_free(struct encoder *e) int frrscript_lua_call(struct frrscript *fs, ...) { - /* Process arguments according to argspec in fs */ - /* ... */ + va_list vl; + va_start(vl, fs); - int ret = lua_pcall(fs->L, 0, 0, 0); + int nargs = va_arg(vl, int); + assert(nargs % 3 == 0); - /* Process stack result according to argspec in fs */ - /* ... */ + zlog_debug("%s: Script '%s' called with # args: %d", __func__, fs->name, + nargs); + + struct encoder e = {}; + void *arg; + const char *bindname; + + /* Encode script arguments */ + for (int i = 0; i < nargs; i += 3) { + bindname = va_arg(vl, const char *); + e.typename = va_arg(vl, char *); + arg = va_arg(vl, void *); + + zlog_debug("Script argument | Bind name: %s | Type: %s", + bindname, e.typename); + + struct encoder *enc = hash_lookup(encoder_hash, &e); + assert(enc + && "No encoder for type; rerun with debug logs to see more"); + enc->encoder(fs->L, arg); + + lua_setglobal(fs->L, bindname); + } + + int nresults = va_arg(vl, int); + zlog_debug("Expected script results: %d", nresults); + + int ret = lua_pcall(fs->L, 0, nresults, 0); + + switch (ret) { + case LUA_ERRRUN: + zlog_err("Script '%s' runtime error", fs->name); + break; + case LUA_ERRMEM: + zlog_err("Script '%s' memory error", fs->name); + break; + case LUA_ERRERR: + zlog_err("Script '%s' error handler error", fs->name); + break; + case LUA_ERRGCMM: + zlog_err("Script '%s' garbage collector error", fs->name); + break; + default: + zlog_err("Script '%s' unknown error", fs->name); + break; + } + + /* After script returns, decode results */ + for (int i = 0; i < nresults; i++) { + const char *resultname = va_arg(vl, const char *); + fprintf(stderr, "result: %s\n", resultname); + } /* LUA_OK is 0, so we can just return lua_pcall's result directly */ return ret; @@ -129,5 +181,12 @@ void frrscript_unload(struct frrscript *fs) void frrscript_init() { - encoder_hash = hash_create(encoder_hash_key, encoder_hash_cmp, "Lua type encoders"); + encoder_hash = hash_create(encoder_hash_key, encoder_hash_cmp, + "Lua type encoders"); + + /* Register core library types */ + frrscript_register_type_encoder("prefix", + (encoder_func)frrlua_newtable_prefix); + frrscript_register_type_encoder( + "interface", (encoder_func)frrlua_newtable_interface); } diff --git a/lib/frrscript.h b/lib/frrscript.h index 6891200def..39eebe6e46 100644 --- a/lib/frrscript.h +++ b/lib/frrscript.h @@ -75,9 +75,40 @@ int frrscript_lua_call(struct frrscript *fs, ...); /* * Call FRR script. + * + * Call it like this: + * + * frrscript_call(fs, FRRSCRIPT_ARGS("cool_prefix", "prefix", p), + * FRRSCRIPT_RESULTS("result1", "result2")) */ #define frrscript_call(fs, ...) frrscript_lua_call((fs), __VA_ARGS__) +/* + * Macro that defines the arguments to a script. + * + * For each argument you want to pass to a script, pass *three* arguments to + * this function. The first should be name of the variable to bind the argument + * to in the script's environment. The second should be the type, as registered + * by frrscript_register_type_encoder(). The third should be the argument + * itself. + * + * This macro itself should be used as the second argument to frrscript_call(). + */ +#define FRRSCRIPT_ARGS(...) PP_NARG(__VA_ARGS__), ##__VA_ARGS__ + +/* + * Macro that defines the results from a script. + * + * Similar to FRRSCRIPT_ARGS, except this defines the results from a script. + * + * The first argument should be the name to bind the first result to and will + * be used after the script finishes to get that particular result value. + * + * This macro itself should be used as the third argument to frrscript_call(). + * It may not be omitted. + */ +#define FRRSCRIPT_RESULTS(...) PP_NARG(__VA_ARGS__), ##__VA_ARGS__ + #ifdef __cplusplus } #endif /* __cplusplus */ -- 2.39.5