summaryrefslogtreecommitdiff
path: root/lib/frrscript.h
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@users.noreply.github.com>2021-08-02 13:51:35 +0000
committerGitHub <noreply@github.com>2021-08-02 13:51:35 +0000
commit41d3d77496fb43df16c55c2c5834cdc3048f43d0 (patch)
tree0ee0dcfb67330c179bb27e26eb0dd83d431468c9 /lib/frrscript.h
parent08bbca7511959e1944f0d002dfcc71f51fcb777e (diff)
parentc5f9744c33df5a9d335691d73fbeb1ad8d0e58d4 (diff)
Merge pull request #8982 from dlqs/lua-func-stack
Diffstat (limited to 'lib/frrscript.h')
-rw-r--r--lib/frrscript.h154
1 files changed, 112 insertions, 42 deletions
diff --git a/lib/frrscript.h b/lib/frrscript.h
index 8612c602f3..540676c099 100644
--- a/lib/frrscript.h
+++ b/lib/frrscript.h
@@ -25,7 +25,7 @@
#include <lua.h>
#include "frrlua.h"
-#include "../bgpd/bgp_script.h"
+#include "bgpd/bgp_script.h" // for peer and attr encoders/decoders
#ifdef __cplusplus
extern "C" {
@@ -40,14 +40,30 @@ struct frrscript_codec {
decoder_func decoder;
};
+struct lua_function_state {
+ const char *name;
+ lua_State *L;
+};
+
struct frrscript {
/* Script name */
char *name;
- /* Lua state */
- struct lua_State *L;
+ /* Hash of Lua function name to Lua function state */
+ struct hash *lua_function_hash;
};
+
+/*
+ * Hash related functions for lua_function_hash
+ */
+
+void *lua_function_alloc(void *arg);
+
+unsigned int lua_function_hash_key(const void *data);
+
+bool lua_function_hash_cmp(const void *d1, const void *d2);
+
struct frrscript_env {
/* Value type */
const char *typename;
@@ -60,15 +76,24 @@ struct frrscript_env {
};
/*
- * Create new FRR script.
+ * Create new struct frrscript for a Lua script.
+ * This will hold the states for the Lua functions in this script.
+ *
+ * scriptname
+ * Name of the Lua script file, without the .lua
*/
-struct frrscript *frrscript_load(const char *name,
- int (*load_cb)(struct frrscript *));
+struct frrscript *frrscript_new(const char *scriptname);
/*
- * Destroy FRR script.
+ * Load a function into frrscript, run callback if any
*/
-void frrscript_unload(struct frrscript *fs);
+int frrscript_load(struct frrscript *fs, const char *function_name,
+ int (*load_cb)(struct frrscript *));
+
+/*
+ * Delete Lua function states and frrscript
+ */
+void frrscript_delete(struct frrscript *fs);
/*
* Register a Lua codec for a type.
@@ -97,16 +122,31 @@ void frrscript_register_type_codecs(struct frrscript_codec *codecs);
*/
void frrscript_init(const char *scriptdir);
-#define ENCODE_ARGS(name, value) \
- do { \
- ENCODE_ARGS_WITH_STATE(L, value); \
- lua_setglobal(L, name); \
- } while (0)
+/*
+ * This macro is mapped to every (name, value) in frrscript_call,
+ * so this in turn maps them onto their encoders
+ */
+#define ENCODE_ARGS(name, value) ENCODE_ARGS_WITH_STATE(lfs->L, (value))
+/*
+ * This macro is also mapped to every (name, value) in frrscript_call, but
+ * not every value can be mapped to its decoder - only those that appear
+ * in the returned table will. To find out if they appear in the returned
+ * table, first pop the value and check if its nil. Only call the decoder
+ * if non-nil.
+ *
+ * At the end, the only thing left on the stack should be the
+ * returned table.
+ */
#define DECODE_ARGS(name, value) \
do { \
- lua_getglobal(L, name); \
- DECODE_ARGS_WITH_STATE(L, value); \
+ lua_getfield(lfs->L, 1, (name)); \
+ if (lua_isnil(lfs->L, 2)) { \
+ lua_pop(lfs->L, 1); \
+ } else { \
+ DECODE_ARGS_WITH_STATE(lfs->L, (value)); \
+ } \
+ assert(lua_gettop(lfs->L) == 1); \
} while (0)
/*
@@ -120,6 +160,7 @@ void frrscript_init(const char *scriptdir);
*/
#define ENCODE_ARGS_WITH_STATE(L, value) \
_Generic((value), \
+int : lua_pushinteger, \
long long * : lua_pushintegerp, \
struct prefix * : lua_pushprefix, \
struct interface * : lua_pushinterface, \
@@ -131,10 +172,11 @@ char * : lua_pushstring_wrapper, \
struct attr * : lua_pushattr, \
struct peer * : lua_pushpeer, \
const struct prefix * : lua_pushprefix \
-)(L, value)
+)((L), (value))
#define DECODE_ARGS_WITH_STATE(L, value) \
_Generic((value), \
+int : lua_decode_integer_noop, \
long long * : lua_decode_integerp, \
struct prefix * : lua_decode_prefix, \
struct interface * : lua_decode_interface, \
@@ -146,56 +188,84 @@ char * : lua_decode_stringp, \
struct attr * : lua_decode_attr, \
struct peer * : lua_decode_noop, \
const struct prefix * : lua_decode_noop \
-)(L, -1, value)
+)((L), -1, (value))
/*
- * Call script.
+ * Call Lua function state (abstraction for a single Lua function)
*
- * fs
- * The script to call; this is obtained from frrscript_load().
+ * lfs
+ * The Lua function to call; this should have been loaded in by
+ * frrscript_load(). nargs Number of arguments the function accepts
*
* 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
- * and decoder types.
+ * Wrapper for calling Lua function state. Maps values passed in to their
+ * encoder and decoder types.
*
* fs
- * The script to call; this is obtained from frrscript_load().
+ * The struct frrscript in which the Lua fuction was loaded into
+ * f
+ * Name of the Lua function.
*
* 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( \
+ "frrscript: '%s.lua': '%s': tried to call this function but it was not loaded", \
+ (fs)->name, (f)); \
+ 1; \
+ }) \
+ : ({ \
+ MAP_LISTS(ENCODE_ARGS, ##__VA_ARGS__); \
+ _frrscript_call_lua( \
+ lfs, PP_NARG(__VA_ARGS__)); \
+ }) != 0 \
+ ? ({ \
+ zlog_err( \
+ "frrscript: '%s.lua': '%s': this function called but returned non-zero exit code. No variables modified.", \
+ (fs)->name, (f)); \
+ 1; \
+ }) \
+ : ({ \
+ MAP_LISTS(DECODE_ARGS, \
+ ##__VA_ARGS__); \
+ 0; \
+ }); \
})
/*
- * Get result from finished script.
+ * Get result from finished function
*
* fs
* The script. This script must have been run already.
- *
- * result
- * The result to extract from the script.
- * This reuses the frrscript_env type, but only the typename and name fields
- * need to be set. The value is returned directly.
+ * function_name
+ * Name of the Lua function.
+ * name
+ * Name of the result.
+ * This will be used as a string key to retrieve from the table that the
+ * Lua function returns.
+ * The name here should *not* appear in frrscript_call.
+ * lua_to
+ * Function pointer to a lua_to decoder function.
+ * This function should allocate and decode a value from the Lua state.
*
* Returns:
- * The script result of the specified name and type, or NULL.
+ * A pointer to the decoded value from the Lua state, or NULL if no such
+ * value.
*/
-void *frrscript_get_result(struct frrscript *fs,
- const struct frrscript_env *result);
+void *frrscript_get_result(struct frrscript *fs, const char *function_name,
+ const char *name,
+ void *(*lua_to)(lua_State *L, int idx));
#ifdef __cplusplus
}