Commit 0810bba8 authored by Jan Maria Matejka's avatar Jan Maria Matejka
Browse files

lua filter saving and reusing

parent c30c4bd3
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -524,6 +524,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;
@@ -542,6 +543,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();		/* ACCEPT */
     acc->code = P('p',',');
@@ -1060,12 +1062,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:
+23 −10
Original line number Diff line number Diff line
@@ -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->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);

  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) {
    /*
@@ -1883,5 +1885,16 @@ filter_same(struct filter *new, struct filter *old)
  if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
      new == FILTER_ACCEPT || new == FILTER_REJECT)
    return 0;
  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");
  }
}
+11 −2
Original line number Diff line number Diff line
@@ -71,8 +71,15 @@ struct f_val {
};

struct filter {
  enum filter_type {
    FILTER_INTERNAL = 1,
    FILTER_LUA = 2,
  } type;
  char *name;
  union {
    struct f_inst *root;
    struct lua_filter_chunk *lua_chunk;
  };
};

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);

/* 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
+105 −2
Original line number Diff line number Diff line
#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;
}
+6 −0
Original line number Diff line number Diff line
@@ -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;