]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Lua filtering able to reject and accept
authorJan Maria Matejka <mq@ucw.cz>
Fri, 12 Jan 2018 14:13:06 +0000 (15:13 +0100)
committerJan Maria Matejka <mq@ucw.cz>
Tue, 23 Jan 2018 14:17:01 +0000 (15:17 +0100)
filter/config.Y
filter/filter.c
filter/filter.h
lua/common.c
lua/filter.c
lua/lua.h
nest/config.Y

index cd5a5b33dedc60ad80a17660770729d5ba132976..6bba042d0a379da7484e3039085b29eb0c49c74b 100644 (file)
@@ -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;
index 62917b7baf3ddab23deb5db98a534bed634b2ebd..5a6a4447fa64ccd52910f8bc152be261e63b629c 100644 (file)
@@ -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:
index 4ee1776f38f2e4bb81a23f2e6553ab0478d5d0b3..ee77906b4c62c441e0f509deb3f8fc3903a28dd3 100644 (file)
@@ -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
index d9467967dc0ec09a8d1319c34a4b9e6c43a2b122..fad2f85767020f7c98a9d3cff6a27a6abceb3cd4 100644 (file)
@@ -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) {
index aae549ab1518622d74aa1fbbcb899c4a1324bdf5..9d12fb1660b3870733b43fce0d64a727c4bfdeb5 100644 (file)
@@ -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);
index d2c522b909a304eb13d2ce60a6ddeac2388c601b..39582e2ee10d55c77e3316fdc372f8b95b332d8c 100644 (file)
--- a/lua/lua.h
+++ b/lua/lua.h
@@ -2,5 +2,10 @@
 
 #include <lua.h>
 
-void luaB_push_bird(lua_State *L);
+typedef struct lua_bird_state {
+  int exception;
+} lua_bird_state;
+
+lua_bird_state *luaB_init(lua_State *L, struct linpool *lp);
 void luaB_push_route(lua_State *L, rte *e);
+
index 6f8a49ae0c47dca04704b142a26dc4c94843ba44..58d50c6ee944171c4782e19615a5b7b36390c017 100644 (file)
@@ -262,14 +262,7 @@ rtable:
 
 imexport:
    FILTER filter { $$ = $2; }
- | 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_call
  | where_filter
  | ALL { $$ = FILTER_ACCEPT; }
  | NONE { $$ = FILTER_REJECT; }