/* Generic script APIs */
-int _frrscript_call(struct frrscript *fs)
+int _frrscript_call_lua(struct lua_function_state *lfs, int nargs)
{
- int ret = lua_pcall(fs->L, 0, 0, 0);
+ int ret;
+ ret = lua_pcall(lfs->L, nargs, 1, 0);
switch (ret) {
case LUA_OK:
break;
case LUA_ERRRUN:
- zlog_err("Script '%s' runtime error: %s", fs->name,
- lua_tostring(fs->L, -1));
+ zlog_err("Lua hook call '%s' : runtime error: %s", lfs->name,
+ lua_tostring(lfs->L, -1));
break;
case LUA_ERRMEM:
- zlog_err("Script '%s' memory error: %s", fs->name,
- lua_tostring(fs->L, -1));
+ zlog_err("Lua hook call '%s' : memory error: %s", lfs->name,
+ lua_tostring(lfs->L, -1));
break;
case LUA_ERRERR:
- zlog_err("Script '%s' error handler error: %s", fs->name,
- lua_tostring(fs->L, -1));
+ zlog_err("Lua hook call '%s' : error handler error: %s",
+ lfs->name, lua_tostring(lfs->L, -1));
break;
case LUA_ERRGCMM:
- zlog_err("Script '%s' garbage collector error: %s", fs->name,
- lua_tostring(fs->L, -1));
+ zlog_err("Lua hook call '%s' : garbage collector error: %s",
+ lfs->name, lua_tostring(lfs->L, -1));
break;
default:
- zlog_err("Script '%s' unknown error: %s", fs->name,
- lua_tostring(fs->L, -1));
+ zlog_err("Lua hook call '%s' : unknown error: %s", lfs->name,
+ lua_tostring(lfs->L, -1));
break;
}
if (ret != LUA_OK) {
- lua_pop(fs->L, 1);
+ lua_pop(lfs->L, 1);
goto done;
}
+ if (lua_gettop(lfs->L) != 1) {
+ zlog_err(
+ "Lua hook call '%s': Lua function should return only 1 result",
+ lfs->name);
+ ret = 1;
+ goto done;
+ }
+
+ if (lua_istable(lfs->L, 1) != 1) {
+ zlog_err(
+ "Lua hook call '%s': Lua function should return a Lua table",
+ lfs->name);
+ ret = 1;
+ }
+
done:
/* LUA_OK is 0, so we can just return lua_pcall's result directly */
return ret;
*/
void frrscript_init(const char *scriptdir);
-#define ENCODE_ARGS(name, value) \
- do { \
- ENCODE_ARGS_WITH_STATE(L, value); \
- lua_setglobal(L, name); \
- } while (0)
+#define ENCODE_ARGS(name, value) ENCODE_ARGS_WITH_STATE(lfs->L, value)
#define DECODE_ARGS(name, value) \
do { \
- lua_getglobal(L, name); \
- DECODE_ARGS_WITH_STATE(L, value); \
+ lua_getfield(lfs->L, 1, name); \
+ DECODE_ARGS_WITH_STATE(lfs->L, value); \
} while (0)
/*
* Returns:
* 0 if the script ran successfully, nonzero otherwise.
*/
-int _frrscript_call(struct frrscript *fs);
+int _frrscript_call_lua(struct lua_function_state *lfs, int nargs);
/*
* Wrapper for call script. Maps values passed in to their encoder
* Returns:
* 0 if the script ran successfully, nonzero otherwise.
*/
-#define frrscript_call(fs, ...) \
- ({ \
- lua_State *L = fs->L; \
- MAP_LISTS(ENCODE_ARGS, ##__VA_ARGS__); \
- int ret = _frrscript_call(fs); \
- if (ret == 0) { \
- MAP_LISTS(DECODE_ARGS, ##__VA_ARGS__); \
- } \
- ret; \
+
+#define frrscript_call(fs, f, ...) \
+ ({ \
+ struct lua_function_state lookup = {.name = f}; \
+ struct lua_function_state *lfs; \
+ lfs = hash_lookup(fs->lua_function_hash, &lookup); \
+ lfs == NULL ? ({ \
+ zlog_err( \
+ "Lua script call: tried to call '%s' in '%s' which was not loaded", \
+ f, fs->name); \
+ 1; \
+ }) \
+ : ({ \
+ MAP_LISTS(ENCODE_ARGS, ##__VA_ARGS__); \
+ _frrscript_call_lua(lfs, PP_NARG(__VA_ARGS__)); \
+ }) != 0 \
+ ? ({ \
+ zlog_err( \
+ "Lua script call: '%s' in '%s' returned non-zero exit code", \
+ f, fs->name); \
+ 1; \
+ }) \
+ : ({ \
+ MAP_LISTS(DECODE_ARGS, ##__VA_ARGS__); \
+ 0; \
+ }); \
})
/*