diff options
author | Jan Maria Matejka <mq@ucw.cz> | 2018-01-23 15:11:08 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2019-02-22 23:12:41 +0100 |
commit | 0c16ef1b616179ed0a652f162f7e9035104a992d (patch) | |
tree | 62b13d3dc05b74aabece6033a587de9be0c3401e | |
parent | ff54220ad5240e7a1975f8e8a8adbc754cf84841 (diff) |
lua filter saving and reusing
-rw-r--r-- | filter/config.Y | 9 | ||||
-rw-r--r-- | filter/filter.c | 33 | ||||
-rw-r--r-- | filter/filter.h | 13 | ||||
-rw-r--r-- | lua/filter.c | 107 | ||||
-rw-r--r-- | lua/lua.h | 6 |
5 files changed, 148 insertions, 20 deletions
diff --git a/filter/config.Y b/filter/config.Y index 51e7a8cc..3c4d8db6 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -543,6 +543,7 @@ declsn: one_decl { $$ = $1; } filter_body: function_body { struct filter *f = cfg_alloc(sizeof(struct filter)); + f->type = FILTER_INTERNAL; f->name = NULL; f->root = $1; $$ = f; @@ -561,6 +562,7 @@ where_filter: WHERE term { /* Construct 'IF term THEN ACCEPT; REJECT;' */ struct filter *f = cfg_alloc(sizeof(struct filter)); + f->type = FILTER_INTERNAL; struct f_inst *i, *acc, *rej; acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */ acc->a1.p = NULL; @@ -1066,12 +1068,7 @@ cmd: lua_call: LUA constant { - $$ = cfg_alloc(sizeof(struct filter)); - $$->name = NULL; - $$->root = f_new_inst(); - $$->root->code = P('L','C'); - $$->root->a1.p = $2; - $$->root->next = NULL; + $$ = lua_new_filter($2); } get_cf_position: diff --git a/filter/filter.c b/filter/filter.c index a13d5cc8..632b4dbf 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -1575,14 +1575,6 @@ interpret(struct f_inst *what) CALL(bt_assert_hook, res.val.i, what); break; - case P('L','C'): /* Lua include */ - ONEARG; - if (v1.type != T_STRING) - runtime("Lua code should be a string argument"); - - res = filter_lua_chunk(v1.val.s, f_rte, f_old_rta, f_tmp_attrs, f_pool); - break; - default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff); }} @@ -1781,7 +1773,17 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla LOG_BUFFER_INIT(f_buf); - struct f_val res = interpret(filter->root); + struct f_val res; + switch (filter->type) { + case FILTER_INTERNAL: + res = interpret(filter->root); + break; + case FILTER_LUA: + res = lua_interpret(filter->lua_chunk, rte, &f_old_rta, tmp_attrs, tmp_pool, flags); + break; + default: + bug("filter type not set"); + } if (f_old_rta) { /* @@ -1875,5 +1877,16 @@ filter_same(struct filter *new, struct filter *old) if (old == FILTER_ACCEPT || old == FILTER_REJECT || new == FILTER_ACCEPT || new == FILTER_REJECT) return 0; - return i_same(new->root, old->root); + if (new->type != old->type) + return 0; + switch(new->type) { + case FILTER_INTERNAL: + return i_same(new->root, old->root); + break; + case FILTER_LUA: + return lua_filter_same(new->lua_chunk, old->lua_chunk); + break; + default: + bug("Unknown filter type"); + } } diff --git a/filter/filter.h b/filter/filter.h index c08f8a48..b49c4c43 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -145,8 +145,15 @@ struct f_static_attr { }; struct filter { + enum filter_type { + FILTER_INTERNAL = 1, + FILTER_LUA = 2, + } type; char *name; - struct f_inst *root; + union { + struct f_inst *root; + struct lua_filter_chunk *lua_chunk; + }; }; struct f_inst *f_new_inst(enum f_instruction_code fi_code); @@ -310,6 +317,8 @@ struct f_bt_test_suite { extern void (*bt_assert_hook)(int result, struct f_inst *assert); /* Lua */ -struct f_val filter_lua_chunk(const char *chunk, struct rte **e, struct rta *a, struct ea_list **ea, struct linpool *lp); +struct filter * lua_new_filter(struct f_inst *inst); +struct f_val lua_interpret(struct lua_filter_chunk *chunk, struct rte **e, struct rta **a, struct ea_list **ea, struct linpool *lp, int flags); +int lua_filter_same(struct lua_filter_chunk *new, struct lua_filter_chunk *old); #endif diff --git a/lua/filter.c b/lua/filter.c index 9d12fb16..fa005354 100644 --- a/lua/filter.c +++ b/lua/filter.c @@ -1,4 +1,5 @@ #include "nest/bird.h" +#include "conf/conf.h" #include "filter/filter.h" #include "lua.h" @@ -8,12 +9,85 @@ /* Docs: http://pgl.yoyo.org/luai/i/luaL_dostring */ -struct f_val filter_lua_chunk(const char *chunk, struct rte **e, struct rta *a, struct ea_list **ea, struct linpool *lp) { +struct lua_new_filter_writer_data { + struct lua_filter_chunk *first, *last; +}; + +static int lua_new_filter_writer(lua_State *L UNUSED, const void *p, size_t sz, void *ud) { + struct lua_new_filter_writer_data *d = ud; + struct lua_filter_chunk *cur = cfg_allocz(sizeof(struct lua_filter_chunk)); + + cur->size = sz; + cur->chunk = cfg_alloc(sz); + memcpy(cur->chunk, p, sz); + + if (d->last) + d->last = d->last->next = cur; + else + d->last = d->first = cur; + + return 0; +} + +struct filter * lua_new_filter(struct f_inst *inst) { + struct filter *f = cfg_alloc(sizeof(struct filter)); + f->name = NULL; + f->type = FILTER_LUA; + + struct f_val string = f_eval(inst, cfg_mem); + if (string.type != T_STRING) { + cf_error("Lua filter must be a string"); + return NULL; + } + + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + int loadres = luaL_loadstring(L, string.val.s); + switch (loadres) { + case LUA_ERRMEM: + lua_close(L); + cf_error("Memory allocation error occured when loading lua chunk"); + return NULL; + case LUA_ERRSYNTAX: + { + const char *e = lua_tostring(L, -1); + char *ec = cfg_alloc(strlen(e) + 1); + strcpy(ec, e); + lua_close(L); + cf_error("Lua syntax error: %s", ec); + return NULL; + } + case 0: /* Everything OK */ + break; + } + + struct lua_new_filter_writer_data lnfwd = {}; + lua_dump(L, lua_new_filter_writer, &lnfwd, 0); /* No error to handle */ + lua_close(L); + + f->lua_chunk = lnfwd.first; + return f; +} + +static const char *lua_interpret_reader(lua_State *L UNUSED, void *ud, size_t *sz) { + struct lua_filter_chunk **cptr = ud; + if ((*cptr) == NULL) + return NULL; + + *sz = (*cptr)->size; + void *out = (*cptr)->chunk; + *cptr = (*cptr)->next; + return out; +} + +struct f_val lua_interpret(struct lua_filter_chunk *chunk, struct rte **e, struct rta **a, struct ea_list **ea, struct linpool *lp, int flags) { lua_State *L = luaL_newstate(); luaL_openlibs(L); lua_bird_state *lbs = luaB_init(L, lp); luaB_push_route(L, *e); - int le = luaL_dostring(L, chunk); + struct lua_filter_chunk **rptr = &chunk; + lua_load(L, lua_interpret_reader, rptr, "", "b"); + int le = lua_pcall(L, 0, LUA_MULTRET, 0); struct f_val out = F_VAL_VOID; if (le && lbs->exception) { out = F_VAL(T_RETURN, i, lbs->exception); @@ -30,3 +104,32 @@ struct f_val filter_lua_chunk(const char *chunk, struct rte **e, struct rta *a, lua_close(L); return out; } + +int lua_filter_same(struct lua_filter_chunk *new, struct lua_filter_chunk *old) { + size_t npos = 0, opos = 0; + while (new && old) { + size_t nrem = new->size - npos; + size_t orem = old->size - opos; + size_t rem = MIN(nrem, orem); + if (memcmp(new->chunk + npos, old->chunk + opos, rem)) + return 0; + + npos += rem; + opos += rem; + + if (npos == new->size) { + new = new->next; + npos = 0; + } + + if (opos == old->size) { + old = old->next; + opos = 0; + } + } + + if (!new && !old) + return 1; + else + return 0; +} @@ -2,6 +2,12 @@ #include <lua.h> +struct lua_filter_chunk { + size_t size; + void *chunk; + struct lua_filter_chunk *next; +}; + typedef struct lua_bird_state { int exception; } lua_bird_state; |