X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=lib%2Ffrrscript.h;h=4db3e6f1b2260907a001196ee6877d4546df9d9c;hb=36e83b73de5f3ec1ea922c3b817db82c8ee6aedc;hp=8612c602f3ca317a2115186b54720f48bfec487d;hpb=af17728126b76468d70228dbaea9575bd1764a1e;p=mirror_frr.git diff --git a/lib/frrscript.h b/lib/frrscript.h index 8612c602f..4db3e6f1b 100644 --- a/lib/frrscript.h +++ b/lib/frrscript.h @@ -24,13 +24,52 @@ #ifdef HAVE_SCRIPTING #include +#include +#include #include "frrlua.h" -#include "../bgpd/bgp_script.h" +#include "bgpd/bgp_script.h" // for peer and attr encoders/decoders #ifdef __cplusplus extern "C" { #endif +/* Forward declarations */ +extern struct zebra_dplane_ctx ctx; +extern void lua_pushzebra_dplane_ctx(lua_State *L, + const struct zebra_dplane_ctx *ctx); +extern void lua_decode_zebra_dplane_ctx(lua_State *L, int idx, + struct zebra_dplane_ctx *ctx); + +/* + * Script name hash + */ +PREDECL_HASH(frrscript_names); + +struct frrscript_names_entry { + /* Name of a Lua hook call */ + char function_name[MAXPATHLEN]; + + /* Lua script in which to look for it */ + char script_name[MAXPATHLEN]; + + struct frrscript_names_item item; +}; + +extern struct frrscript_names_head frrscript_names_hash; + +int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1, + const struct frrscript_names_entry *snhe2); +uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe); + +DECLARE_HASH(frrscript_names, struct frrscript_names_entry, item, + frrscript_names_hash_cmp, frrscript_names_hash_key); + +int frrscript_names_add_function_name(const char *function_name); +void frrscript_names_destroy(void); +int frrscript_names_set_script_name(const char *function_name, + const char *script_name); +char *frrscript_names_get_script_name(const char *function_name); + typedef void (*encoder_func)(lua_State *, const void *); typedef void *(*decoder_func)(lua_State *, int); @@ -40,14 +79,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 +115,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_new(const char *scriptname); + +/* + * Load a function into frrscript, run callback if any */ -struct frrscript *frrscript_load(const char *name, - int (*load_cb)(struct frrscript *)); +int frrscript_load(struct frrscript *fs, const char *function_name, + int (*load_cb)(struct frrscript *)); /* - * Destroy FRR script. + * Delete Lua function states and frrscript */ -void frrscript_unload(struct frrscript *fs); +void frrscript_delete(struct frrscript *fs); /* * Register a Lua codec for a type. @@ -97,16 +161,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 +199,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, \ @@ -130,11 +210,17 @@ time_t * : lua_pushtimet, \ char * : lua_pushstring_wrapper, \ struct attr * : lua_pushattr, \ struct peer * : lua_pushpeer, \ -const struct prefix * : lua_pushprefix \ -)(L, value) +const struct prefix * : lua_pushprefix, \ +const struct ipaddr * : lua_pushipaddr, \ +const struct ethaddr * : lua_pushethaddr, \ +const struct nexthop_group * : lua_pushnexthop_group, \ +const struct nexthop * : lua_pushnexthop, \ +struct zebra_dplane_ctx * : lua_pushzebra_dplane_ctx \ +)((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, \ @@ -145,57 +231,102 @@ time_t * : lua_decode_timet, \ char * : lua_decode_stringp, \ struct attr * : lua_decode_attr, \ struct peer * : lua_decode_noop, \ -const struct prefix * : lua_decode_noop \ -)(L, -1, value) +const struct prefix * : lua_decode_noop, \ +const struct ipaddr * : lua_decode_noop, \ +const struct ethaddr * : lua_decode_noop, \ +const struct nexthop_group * : lua_decode_noop, \ +const struct nexthop * : lua_decode_noop, \ +struct zebra_dplane_ctx * : lua_decode_noop \ +)((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. + * + * The Lua function name (f) to run should have already been checked by + * frrscript_load. So this wrapper will: + * 1) Find the Lua function state, which contains the Lua state + * 2) Clear the Lua state (there may be leftovers items from previous call) + * 3) Push the Lua function (f) + * 4) Map frrscript_call arguments onto their encoder and decoders, push those + * 5) Call _frrscript_call_lua (Lua execution takes place) + * 6) Write back to frrscript_call arguments using their decoders + * + * This wrapper can be called multiple times (after one frrscript_load). * * 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; \ + }) \ + : ({ \ + lua_settop(lfs->L, 0); \ + lua_getglobal(lfs->L, f); \ + 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 }