mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-03 07:31:54 +00:00
lua filter saving and reusing
This commit is contained in:
parent
c30c4bd37f
commit
0810bba8b4
@ -524,6 +524,7 @@ declsn: one_decl { $$ = $1; }
|
|||||||
filter_body:
|
filter_body:
|
||||||
function_body {
|
function_body {
|
||||||
struct filter *f = cfg_alloc(sizeof(struct filter));
|
struct filter *f = cfg_alloc(sizeof(struct filter));
|
||||||
|
f->type = FILTER_INTERNAL;
|
||||||
f->name = NULL;
|
f->name = NULL;
|
||||||
f->root = $1;
|
f->root = $1;
|
||||||
$$ = f;
|
$$ = f;
|
||||||
@ -542,6 +543,7 @@ where_filter:
|
|||||||
WHERE term {
|
WHERE term {
|
||||||
/* Construct 'IF term THEN ACCEPT; REJECT;' */
|
/* Construct 'IF term THEN ACCEPT; REJECT;' */
|
||||||
struct filter *f = cfg_alloc(sizeof(struct filter));
|
struct filter *f = cfg_alloc(sizeof(struct filter));
|
||||||
|
f->type = FILTER_INTERNAL;
|
||||||
struct f_inst *i, *acc, *rej;
|
struct f_inst *i, *acc, *rej;
|
||||||
acc = f_new_inst(); /* ACCEPT */
|
acc = f_new_inst(); /* ACCEPT */
|
||||||
acc->code = P('p',',');
|
acc->code = P('p',',');
|
||||||
@ -1060,12 +1062,7 @@ cmd:
|
|||||||
|
|
||||||
lua_call:
|
lua_call:
|
||||||
LUA constant {
|
LUA constant {
|
||||||
$$ = cfg_alloc(sizeof(struct filter));
|
$$ = lua_new_filter($2);
|
||||||
$$->name = NULL;
|
|
||||||
$$->root = f_new_inst();
|
|
||||||
$$->root->code = P('L','C');
|
|
||||||
$$->root->a1.p = $2;
|
|
||||||
$$->root->next = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_cf_position:
|
get_cf_position:
|
||||||
|
@ -1575,14 +1575,6 @@ interpret(struct f_inst *what)
|
|||||||
CALL(bt_assert_hook, res.val.i, what);
|
CALL(bt_assert_hook, res.val.i, what);
|
||||||
break;
|
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:
|
default:
|
||||||
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
|
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
|
||||||
}
|
}
|
||||||
@ -1778,7 +1770,17 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
|
|||||||
|
|
||||||
LOG_BUFFER_INIT(f_buf);
|
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) {
|
if (f_old_rta) {
|
||||||
/*
|
/*
|
||||||
@ -1883,5 +1885,16 @@ filter_same(struct filter *new, struct filter *old)
|
|||||||
if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
|
if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
|
||||||
new == FILTER_ACCEPT || new == FILTER_REJECT)
|
new == FILTER_ACCEPT || new == FILTER_REJECT)
|
||||||
return 0;
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,15 @@ struct f_val {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct filter {
|
struct filter {
|
||||||
|
enum filter_type {
|
||||||
|
FILTER_INTERNAL = 1,
|
||||||
|
FILTER_LUA = 2,
|
||||||
|
} type;
|
||||||
char *name;
|
char *name;
|
||||||
struct f_inst *root;
|
union {
|
||||||
|
struct f_inst *root;
|
||||||
|
struct lua_filter_chunk *lua_chunk;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct f_inst *f_new_inst(void);
|
struct f_inst *f_new_inst(void);
|
||||||
@ -223,6 +230,8 @@ struct f_bt_test_suite {
|
|||||||
extern void (*bt_assert_hook)(int result, struct f_inst *assert);
|
extern void (*bt_assert_hook)(int result, struct f_inst *assert);
|
||||||
|
|
||||||
/* Lua */
|
/* 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
|
#endif
|
||||||
|
107
lua/filter.c
107
lua/filter.c
@ -1,4 +1,5 @@
|
|||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
|
#include "conf/conf.h"
|
||||||
#include "filter/filter.h"
|
#include "filter/filter.h"
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
@ -8,12 +9,85 @@
|
|||||||
|
|
||||||
/* Docs: http://pgl.yoyo.org/luai/i/luaL_dostring */
|
/* 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();
|
lua_State *L = luaL_newstate();
|
||||||
luaL_openlibs(L);
|
luaL_openlibs(L);
|
||||||
lua_bird_state *lbs = luaB_init(L, lp);
|
lua_bird_state *lbs = luaB_init(L, lp);
|
||||||
luaB_push_route(L, *e);
|
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;
|
struct f_val out = F_VAL_VOID;
|
||||||
if (le && lbs->exception) {
|
if (le && lbs->exception) {
|
||||||
out = F_VAL(T_RETURN, i, 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);
|
lua_close(L);
|
||||||
return out;
|
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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user