/* Internal filter state, to be allocated on stack when executing filters */
struct filter_state {
/* Stacks needed for execution */
- struct filter_stack *stack;
-
- /* The route we are processing. This may be NULL to indicate no route available. */
- struct rte **rte;
+ struct filter_stack {
+ /* Current filter stack depth */
- /* The old rta to be freed after filters are done. */
- struct rta *old_rta;
+ /* Value stack */
+ uint vcnt, vlen;
+ struct f_val *vstk;
- /* Cached pointer to ea_list */
- struct ea_list **eattrs;
+ /* Instruction stack for execution */
+ uint ecnt, elen;
+ struct filter_exec_stack *estk;
+ } stack;
- /* Linpool for adata allocation */
- struct linpool *pool;
+ /* The route we are processing. This may be NULL to indicate no route available. */
+ struct rte *rte;
+ /* Additional external values provided to the filter */
+ const struct f_val *val;
+
/* Buffer for log output */
- struct buffer buf;
+ log_buffer buf;
/* Filter execution flags */
int flags;
* TWOARGS macro to get both of them evaluated.
*/
static enum filter_return
- interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
+ interpret(struct filter_state *fs, const struct f_line *line, uint argc, const struct f_val *argv, struct f_val *val)
{
- /* No arguments allowed */
- ASSERT(line->args == 0);
+ /* Check of appropriate number of arguments */
+ ASSERT(line->args == argc);
/* Initialize the filter stack */
- struct filter_stack *fstk = fs->stack;
+ struct filter_stack *fstk = &fs->stack;
- fstk->vcnt = line->vars;
- memset(fstk->vstk, 0, sizeof(struct f_val) * line->vars);
+ /* Set the arguments and top-level variables */
+ fstk->vcnt = line->vars + line->args;
+ memcpy(fstk->vstk, argv, sizeof(struct f_val) * line->args);
+ memset(fstk->vstk + argc, 0, sizeof(struct f_val) * line->vars);
- /* The same as with the value stack. Not resetting the stack for performance reasons. */
+ /* The same as with the value stack. Not resetting the stack completely for performance reasons. */
fstk->ecnt = 1;
- fstk->estk[0].line = line;
- fstk->estk[0].pos = 0;
+ fstk->estk[0] = (struct filter_exec_stack) {
+ .line = line,
+ .pos = 0,
+ };
#define curline fstk->estk[fstk->ecnt-1]
#define prevline fstk->estk[fstk->ecnt-2]
if (filter == FILTER_REJECT)
return F_REJECT;
- return f_run_args(filter, rte, tmp_pool, 0, NULL, flags);
++ return f_run_args(filter, rte, 0, NULL, flags);
+ }
+
+ enum filter_return
-f_run_args(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, int flags)
++f_run_args(const struct filter *filter, struct rte *rte, uint argc, const struct f_val *argv, int flags)
+ {
- int rte_cow = ((*rte)->flags & REF_COW);
DBG( "Running filter `%s'...", filter->name );
/* Initialize the filter state */
.flags = flags,
};
- LOG_BUFFER_INIT(filter_state.buf);
+ f_stack_init(filter_state);
/* Run the interpreter itself */
- enum filter_return fret = interpret(&filter_state, filter->root, NULL);
+ enum filter_return fret = interpret(&filter_state, filter->root, argc, argv, NULL);
- if (filter_state.old_rta) {
- /*
- * Cached rta was modified and filter_state->rte contains now an uncached one,
- * sharing some part with the cached one. The cached rta should
- * be freed (if rte was originally COW, filter_state->old_rta is a clone
- * obtained during rte_cow()).
- *
- * This also implements the exception mentioned in f_run()
- * description. The reason for this is that rta reuses parts of
- * filter_state->old_rta, and these may be freed during rta_free(filter_state->old_rta).
- * This is not the problem if rte was COW, because original rte
- * also holds the same rta.
- */
- if (!rte_cow) {
- /* Cache the new attrs */
- (*filter_state.rte)->attrs = rta_lookup((*filter_state.rte)->attrs);
-
- /* Drop cached ea_list pointer */
- filter_state.eattrs = NULL;
- }
-
- /* Uncache the old attrs and drop the pointer as it is invalid now. */
- rta_free(filter_state.old_rta);
- filter_state.old_rta = NULL;
- }
-
/* Process the filter output, log it and return */
if (fret < F_ACCEPT) {
if (!(filter_state.flags & FF_SILENT))
*/
enum filter_return
- f_eval_rte(const struct f_line *expr, struct rte *rte)
-f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, struct f_val *pres)
++f_eval_rte(const struct f_line *expr, struct rte *rte, uint argc, const struct f_val *argv, struct f_val *pres)
{
filter_state = (struct filter_state) {
- .stack = &filter_stack,
.rte = rte,
- .pool = tmp_pool,
};
- LOG_BUFFER_INIT(filter_state.buf);
+ f_stack_init(filter_state);
- ASSERT(!rta_is_cached(rte->attrs));
-
- return interpret(&filter_state, expr, NULL);
+ return interpret(&filter_state, expr, argc, argv, pres);
}
/*
* @pres: here the output will be stored
*/
enum filter_return
-f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
+f_eval(const struct f_line *expr, struct f_val *pres)
{
- filter_state = (struct filter_state) {
- .stack = &filter_stack,
- .pool = tmp_pool,
- };
+ filter_state = (struct filter_state) {};
- LOG_BUFFER_INIT(filter_state.buf);
+ f_stack_init(filter_state);
- enum filter_return fret = interpret(&filter_state, expr, pres);
+ enum filter_return fret = interpret(&filter_state, expr, 0, NULL, pres);
return fret;
}
struct rte;
-enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
-enum filter_return f_run_args(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, int flags);
-enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, struct f_val *pres);
-enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
+enum filter_return f_run(const struct filter *filter, struct rte *rte, int flags);
- enum filter_return f_eval_rte(const struct f_line *expr, struct rte *rte);
++enum filter_return f_run_args(const struct filter *filter, struct rte *rte, uint argc, const struct f_val *argv, int flags);
++enum filter_return f_eval_rte(const struct f_line *expr, struct rte *rte, uint argc, const struct f_val *argv, struct f_val *pres);
+enum filter_return f_eval_buf(const struct f_line *expr, buffer *buf);
-struct f_val cf_eval(const struct f_inst *inst, int type);
-static inline uint cf_eval_int(const struct f_inst *inst) { return cf_eval(inst, T_INT).val.i; };
+struct f_val cf_eval_tmp(const struct f_inst *inst, int type);
+static inline struct f_val *cf_eval(const struct f_inst *inst, int type)
+{
+ struct f_val val = cf_eval_tmp(inst, type);
+ return lp_val_copy(cfg_mem, &val);
+}
+
+static inline uint cf_eval_int(const struct f_inst *inst) { return cf_eval_tmp(inst, T_INT).val.i; };
const char *filter_name(const struct filter *filter);
int filter_same(const struct filter *new, const struct filter *old);
return;
/* We skip rta_lookup() here */
- rte *e = rte_get_temp(a, src);
+ src = static_get_source(p, r->index);
+ rte e0 = { .attrs = ea, .src = src, .net = r->net, }, *e = &e0;
+ /* Evaluate the filter */
if (r->cmds)
- f_eval_rte(r->cmds, e);
- {
- /* Create a temporary table node */
- e->net = alloca(sizeof(net) + r->net->length);
- memset(e->net, 0, sizeof(net) + r->net->length);
- net_copy(e->net->n.addr, r->net);
++ f_eval_rte(r->cmds, e, 0, NULL, NULL);
- /* Evaluate the filter */
- f_eval_rte(r->cmds, &e, static_lp, 0, NULL, NULL);
-
- /* Remove the temporary node */
- e->net = NULL;
- }
+ rte_update(p->p.main_channel, r->net, e, src);
+ static_free_source(src, r->index);
- rte_update2(p->p.main_channel, r->net, e, src);
r->state = SRS_CLEAN;
-
- if (r->cmds)
- lp_flush(static_lp);
-
return;
withdraw: