Commit c30c4bd3 authored by Jan Maria Matejka's avatar Jan Maria Matejka
Browse files

Lua filtering able to reject and accept

parent 76a71823
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -413,7 +413,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc ELSE

%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
%type <f> filter filter_body where_filter
%type <f> filter filter_body where_filter lua_call
%type <i> type break_command ec_kind
%type <i32> cnum
%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
@@ -1058,6 +1058,16 @@ cmd:
 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
 ;

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

get_cf_position:
{
  $$ = cf_text;
+1 −2
Original line number Diff line number Diff line
@@ -1580,8 +1580,7 @@ interpret(struct f_inst *what)
    if (v1.type != T_STRING)
      runtime("Lua code should be a string argument");

    res.type = T_RETURN;
    res.val.i = filter_lua_chunk(v1.val.s, f_rte, f_old_rta, f_tmp_attrs, f_pool);
    res = filter_lua_chunk(v1.val.s, f_rte, f_old_rta, f_tmp_attrs, f_pool);
    break;

  default:
+3 −1
Original line number Diff line number Diff line
@@ -206,6 +206,8 @@ struct f_trie
};

#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));
#define F_VAL(_type, where, value) ((struct f_val) { .type = (_type), .val.where = (value) })
#define F_VAL_VOID ((struct f_val) { .type = T_VOID })

#define FF_FORCE_TMPATTR 1		/* Force all attributes to be temporary */

@@ -221,6 +223,6 @@ struct f_bt_test_suite {
extern void (*bt_assert_hook)(int result, struct f_inst *assert);

/* Lua */
int filter_lua_chunk(const char *chunk, struct rte **e, struct rta *a, struct ea_list **ea, struct linpool *lp);
struct f_val filter_lua_chunk(const char *chunk, struct rte **e, struct rta *a, struct ea_list **ea, struct linpool *lp);

#endif
+46 −1
Original line number Diff line number Diff line
@@ -64,6 +64,12 @@ static int luaB_trace(lua_State *L) {
#define lua_settablecfunction(L, idx, val)  lua_sett(L, idx, val, cfunction)
#define lua_settableinteger(L, idx, val)    lua_sett(L, idx, val, integer)
#define lua_settableip4(L, idx, val)	    lua_sett(L, idx, val, ip4)
#define lua_settablelightuserdata(L, idx, val)  lua_sett(L, idx, val, lightuserdata)

#define lua_setglobalcfunction(L, n, val)   do { \
  lua_pushcfunction(L, val); \
  lua_setglobal(L, n); \
} while (0)

static int luaB_generic_concat(lua_State *L) {
  int n = lua_gettop(L);
@@ -125,7 +131,34 @@ static void lua_puship4(lua_State *L, ip4_addr a) {
  lua_setmetatable(L, -2);
}

void luaB_push_bird(lua_State *L) {
static lua_bird_state *luaB_getinternalstate(lua_State *L) {
  lua_getglobal(L, "bird");
  lua_pushstring(L, "_internal_state");
  lua_gettable(L, -2);
  if (!lua_isuserdata(L, -1))
    luaL_error(L, "fatal: bird internal state not found, type %d", lua_type(L, -1));

  lua_bird_state *lbs = lua_touserdata(L, -1);
  lua_pop(L, 2); /* Pop the user data and then the table. The string is consumed by gettable(). */
  return lbs;
}

static int luaB_global_exception(lua_State *L, int value) {
  int n = lua_gettop(L);
  if (n > 1)
    log(L_WARN "Called exception with too many arguments.");

  lua_bird_state *lbs = luaB_getinternalstate(L);
  lbs->exception = value;

  lua_error(L);
  return 0;
}

static inline int luaB_accept(lua_State *L) { return luaB_global_exception(L, F_ACCEPT); }
static inline int luaB_reject(lua_State *L) { return luaB_global_exception(L, F_REJECT); }

lua_bird_state *luaB_init(lua_State *L, struct linpool *lp) {
  lua_newtable(L);

  lua_settablecfunction(L, "err", luaB_err);
@@ -133,9 +166,21 @@ void luaB_push_bird(lua_State *L) {
  lua_settablecfunction(L, "info", luaB_info);
  lua_settablecfunction(L, "trace", luaB_trace);

  lua_bird_state *lbs = lp_allocz(lp, sizeof(lua_bird_state));

  lua_settablelightuserdata(L, "_internal_state", lbs);

  lua_settableip4(L, "router_id", config->router_id);

  lua_setglobal(L, "bird");

  lua_pushcfunction(L, luaB_accept);
  lua_setglobal(L, "accept");

  lua_pushcfunction(L, luaB_reject);
  lua_setglobal(L, "reject");

  return lbs;
}

void luaB_push_route(lua_State *L, struct rte *e) {
+13 −9
Original line number Diff line number Diff line
@@ -6,21 +6,25 @@
#include <lualib.h>
#include <lauxlib.h>

int filter_lua_chunk(const char *chunk, struct rte **e, struct rta *a, struct ea_list **ea, struct linpool *lp) {
/* 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) {
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);
  luaB_push_bird(L);
  lua_bird_state *lbs = luaB_init(L, lp);
  luaB_push_route(L, *e);
  int le = luaL_dostring(L, chunk);
  int out;
  if (le) {
    log(L_WARN "bad lua: %s", lua_tostring(L, -1));
    out = F_ERROR;
  struct f_val out = F_VAL_VOID;
  if (le && lbs->exception) {
    out = F_VAL(T_RETURN, i, lbs->exception);
  } else if (le) {
    log(L_ERR "bad lua: %s", lua_tostring(L, -1));
    out = F_VAL(T_RETURN, i, F_ERROR);
  } else if (lua_isnumber(L, -1)) {
    out = lua_tonumber(L, -1);
    out = F_VAL(T_INT, i, lua_tonumber(L, -1));
  } else {
    log(L_WARN "lua return value is not a number: %s", lua_tostring(L, -1));
    out = F_ERROR;
    log(L_WARN "lua return value is not a number (unimplemented): %s", lua_tostring(L, -1));
    out = F_VAL(T_RETURN, i, F_ERROR);
  }

  lua_close(L);
Loading