summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/config.Y12
-rw-r--r--filter/filter.c3
-rw-r--r--filter/filter.h4
-rw-r--r--lua/common.c47
-rw-r--r--lua/filter.c22
-rw-r--r--lua/lua.h7
-rw-r--r--nest/config.Y9
7 files changed, 81 insertions, 23 deletions
diff --git a/filter/config.Y b/filter/config.Y
index c1e74531..51e7a8cc 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -426,7 +426,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
%type <fda> dynamic_attr
%type <fsa> static_attr
-%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
@@ -1064,6 +1064,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;
diff --git a/filter/filter.c b/filter/filter.c
index 7f3979f3..a13d5cc8 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -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:
diff --git a/filter/filter.h b/filter/filter.h
index a4eb2913..c08f8a48 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -284,6 +284,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_SILENT 2 /* Silent filter execution */
@@ -308,6 +310,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
diff --git a/lua/common.c b/lua/common.c
index d9467967..fad2f857 100644
--- a/lua/common.c
+++ b/lua/common.c
@@ -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) {
diff --git a/lua/filter.c b/lua/filter.c
index aae549ab..9d12fb16 100644
--- a/lua/filter.c
+++ b/lua/filter.c
@@ -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);
diff --git a/lua/lua.h b/lua/lua.h
index d2c522b9..39582e2e 100644
--- 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);
+
diff --git a/nest/config.Y b/nest/config.Y
index f87ed2df..3242f96e 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -263,14 +263,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; }