mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 15:43:55 +00:00
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 <qlyoung@nvidia.com>
This commit is contained in:
parent
923431ef80
commit
3b002f1916
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "frrscript.h"
|
#include "frrscript.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
@ -73,13 +74,64 @@ static void encoder_free(struct encoder *e)
|
|||||||
|
|
||||||
int frrscript_lua_call(struct frrscript *fs, ...)
|
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 */
|
/* LUA_OK is 0, so we can just return lua_pcall's result directly */
|
||||||
return ret;
|
return ret;
|
||||||
@ -129,5 +181,12 @@ void frrscript_unload(struct frrscript *fs)
|
|||||||
|
|
||||||
void frrscript_init()
|
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);
|
||||||
}
|
}
|
||||||
|
@ -75,9 +75,40 @@ int frrscript_lua_call(struct frrscript *fs, ...);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Call FRR script.
|
* 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__)
|
#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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
Loading…
Reference in New Issue
Block a user