From f827cf11bed2212386bdf448466f715b2e07cb1e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 6 Mar 2019 00:11:40 +0100 Subject: [PATCH] ROA change notifications: simple variant This implementation will just automatically request channel reload/refeed when ROA change is detected. It may be sufficient for many uses; performance impact for big IXPs is unclear. --- filter/filter.c | 73 ++++++++++++++++++++++++++++++++++++--- filter/filter.h | 10 +++++- nest/notify.h | 88 +++++++++++++++++++++++++++++++++++++++++++++++ nest/proto.c | 68 +++++++++++++++++++++++++++++------- nest/protocol.h | 7 ++-- nest/route.h | 8 ++++- nest/rt-show.c | 6 ++-- nest/rt-table.c | 26 ++++++++++---- proto/mrt/mrt.c | 3 +- proto/pipe/pipe.c | 4 +-- proto/radv/radv.c | 2 +- sysdep/unix/krt.c | 4 +-- 12 files changed, 262 insertions(+), 37 deletions(-) create mode 100644 nest/notify.h diff --git a/filter/filter.c b/filter/filter.c index 37cf16a38..ec7e8997e 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -45,6 +45,7 @@ #include "nest/protocol.h" #include "nest/iface.h" #include "nest/attrs.h" +#include "nest/notify.h" #include "conf/conf.h" #include "filter/filter.h" @@ -52,6 +53,59 @@ void (*bt_assert_hook)(int result, struct f_inst *assert); +struct filter_roa_notifier { + resource r; + struct listener L; + struct rtable *roa_table; + struct filter_slot *slot; +}; + +static void filter_roa_notifier_hook(struct listener *L, void *data UNUSED) { + struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L); + frn->slot->reloader(frn->slot); +} + +static void filter_roa_notifier_unsubscribe(struct listener *L) { + struct filter_roa_notifier *frn = SKIP_BACK(struct filter_roa_notifier, L, L); + rfree(frn); +} + +static void filter_roa_notifier_free(resource *r) { + struct filter_roa_notifier *frn = (void *) r; + unsubscribe(&(frn->L)); +} + +static struct resclass filter_roa_notifier_class = { + .name = "Filter ROA Notifier", + .size = sizeof(struct filter_roa_notifier), + .free = filter_roa_notifier_free, + .dump = NULL, + .lookup = NULL, + .memsize = NULL, +}; + +static void filter_roa_notifier_subscribe(struct rtable *roa_table, struct filter_slot *slot, const net_addr *n UNUSED, u32 as UNUSED) { + struct listener *oldL; + node *x; + WALK_LIST2(oldL, x, slot->notifiers, receiver_node) + if (oldL->hook == filter_roa_notifier_hook) + { + struct filter_roa_notifier *old = SKIP_BACK(struct filter_roa_notifier, L, oldL); + if ((old->roa_table == roa_table) && (old->slot == slot)) + return; /* Old notifier found for the same event. */ + } + + struct filter_roa_notifier *frn = ralloc(slot->p, &filter_roa_notifier_class); + frn->L = (struct listener) { + .hook = filter_roa_notifier_hook, + .unsub = filter_roa_notifier_unsubscribe, + }; + frn->roa_table = roa_table; + frn->slot = slot; + + subscribe(&(frn->L), &(roa_table->listeners), &(slot->notifiers)); +} + static struct adata undef_adata; /* adata of length 0 used for undefined */ /* Special undef value for paths and clists */ @@ -542,6 +596,7 @@ static struct ea_list **f_eattrs; static struct linpool *f_pool; static struct buffer f_buf; static int f_flags; +static struct filter_slot *f_slot; static inline void f_cache_eattrs(void) { @@ -1555,7 +1610,12 @@ interpret(struct f_inst *what) if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6)) res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */ else + { + if (f_slot) + filter_roa_notifier_subscribe(table, f_slot, v1.val.net, as); + res.val.i = net_roa_check(table, v1.val.net, as); + } break; @@ -1754,12 +1814,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) * modified in place, old cached rta is possibly freed. */ int -f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags) +f_run(struct filter_slot *filter_slot, struct rte **rte, struct linpool *tmp_pool, int flags) { - if (filter == FILTER_ACCEPT) + if (filter_slot->filter == FILTER_ACCEPT) return F_ACCEPT; - if (filter == FILTER_REJECT) + if (filter_slot->filter == FILTER_REJECT) return F_REJECT; int rte_cow = ((*rte)->flags & REF_COW); @@ -1770,10 +1830,11 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla f_old_rta = NULL; f_pool = tmp_pool; f_flags = flags; + f_slot = filter_slot; LOG_BUFFER_INIT(f_buf); - struct f_val res = interpret(filter->root); + struct f_val res = interpret(filter_slot->filter->root); if (f_old_rta) { /* @@ -1797,7 +1858,7 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla if (res.type != T_RETURN) { if (!(f_flags & FF_SILENT)) - log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); + log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter_slot->filter->name); return F_ERROR; } DBG( "done (%u)\n", res.val.i ); @@ -1815,6 +1876,7 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) f_old_rta = NULL; f_pool = tmp_pool; f_flags = 0; + f_slot = NULL; LOG_BUFFER_INIT(f_buf); @@ -1831,6 +1893,7 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool) f_eattrs = NULL; f_rte = NULL; f_pool = tmp_pool; + f_slot = NULL; LOG_BUFFER_INIT(f_buf); diff --git a/filter/filter.h b/filter/filter.h index a8c332878..2f0fa735c 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -149,6 +149,13 @@ struct filter { struct f_inst *root; }; +struct filter_slot { + struct filter *filter; + void (*reloader)(struct filter_slot *); + pool *p; + list notifiers; +}; + struct f_inst *f_new_inst(enum f_instruction_code fi_code); struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da); struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa); @@ -175,7 +182,7 @@ void trie_format(struct f_trie *t, buffer *buf); struct ea_list; struct rte; -int f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); +int f_run(struct filter_slot *filter_slot, struct rte **rte, struct linpool *tmp_pool, int flags); struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); uint f_eval_int(struct f_inst *expr); @@ -286,6 +293,7 @@ struct f_trie #define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); #define FF_SILENT 2 /* Silent filter execution */ +#define FF_TEMP 4 /* Result of this filter is dropped */ /* Custom route attributes */ struct custom_attribute { diff --git a/nest/notify.h b/nest/notify.h new file mode 100644 index 000000000..9ae736d0e --- /dev/null +++ b/nest/notify.h @@ -0,0 +1,88 @@ +/* + * BIRD Internet Routing Daemon -- Notificators and Listeners + * + * (c) 2019 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_NOTIFY_H_ +#define _BIRD_NOTIFY_H_ + +#include "lib/lists.h" + +struct listener { + node sender_node; + node receiver_node; + + void (*hook)(struct listener *who, void *data); + void (*dump)(struct listener *who); + void (*unsub)(struct listener *who); +}; + +static inline void subscribe(struct listener *who, list *sender, list *receiver) +{ + ASSERT(!NODE_VALID(&(who->sender_node))); + ASSERT(!NODE_VALID(&(who->receiver_node))); + + add_tail(sender, &(who->sender_node)); + add_tail(receiver, &(who->receiver_node)); +} + +static inline void unsubscribe(struct listener *who) +{ + /* Allow multiple unsubscribe */ + if (!NODE_VALID(&(who->sender_node)) + && !NODE_VALID(&(who->receiver_node))) + return; + + ASSERT(NODE_VALID(&(who->sender_node)) + && NODE_VALID(&(who->receiver_node))); + + rem_node(&(who->sender_node)); + rem_node(&(who->receiver_node)); + + who->sender_node = who->receiver_node = (node) {}; + CALL(who->unsub, who); +} + +static inline void unsubscribe_all(list *receiver) +{ + struct listener *n; + node *x, *y; + WALK_LIST2_DELSAFE(n, x, y, *receiver, receiver_node) + unsubscribe(n); +} + +static inline void notify(list *sender, void *data) +{ + struct listener *n; + node *x, *y; + WALK_LIST2_DELSAFE(n, x, y, *sender, sender_node) + n->hook(n, data); +} + +static inline void listeners_dump(list *sender, list *receiver) +{ + ASSERT((!sender) || (!receiver)); + ASSERT(sender || receiver); + + struct listener *n; + node *x; + if (sender) + WALK_LIST2(n, x, *sender, sender_node) { + debug("\t\tNotifier: hook %p", n->hook); + CALL(n->dump, n); + debug("\n"); + } + + if (receiver) + WALK_LIST2(n, x, *receiver, receiver_node) { + debug("\t\tNotifier: hook %p", n->hook); + CALL(n->dump, n); + debug("\n"); + } +} + + +#endif diff --git a/nest/proto.c b/nest/proto.c index d4a333d07..123f3eed8 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -125,6 +125,16 @@ proto_find_channel_by_name(struct proto *p, const char *n) return NULL; } +static void channel_filter_slot_reimport(struct filter_slot *fs) +{ + return channel_request_reload(SKIP_BACK(struct channel, in_filter, fs)); +} + +static void channel_filter_slot_reexport(struct filter_slot *fs) +{ + return channel_request_feeding(SKIP_BACK(struct channel, out_filter, fs)); +} + /** * proto_add_channel - connect protocol to a routing table * @p: protocol instance @@ -150,8 +160,16 @@ proto_add_channel(struct proto *p, struct channel_config *cf) c->proto = p; c->table = cf->table->table; - c->in_filter = cf->in_filter; - c->out_filter = cf->out_filter; + c->in_filter.filter = cf->in_filter; + c->in_filter.reloader = channel_filter_slot_reimport; + c->in_filter.p = p->pool; + init_list(&c->in_filter.notifiers); + + c->out_filter.filter = cf->out_filter; + c->out_filter.reloader = channel_filter_slot_reexport; + c->out_filter.p = p->pool; + init_list(&c->out_filter.notifiers); + c->rx_limit = cf->rx_limit; c->in_limit = cf->in_limit; c->out_limit = cf->out_limit; @@ -397,6 +415,13 @@ channel_set_state(struct channel *c, uint state) c->channel_state = state; c->last_state_change = current_time(); + /* No filter notifier shall remain after transitioning from CS_UP state. */ + if (cs == CS_UP) + { + unsubscribe_all(&(c->in_filter.notifiers)); + unsubscribe_all(&(c->out_filter.notifiers)); + } + switch (state) { case CS_START: @@ -492,7 +517,7 @@ channel_reloadable(struct channel *c) return c->proto->reload_routes && c->reloadable; } -static void +void channel_request_reload(struct channel *c) { ASSERT(c->channel_state == CS_UP); @@ -592,8 +617,8 @@ channel_reconfigure(struct channel *c, struct channel_config *cf) return 0; /* Note that filter_same() requires arguments in (new, old) order */ - int import_changed = !filter_same(cf->in_filter, c->in_filter); - int export_changed = !filter_same(cf->out_filter, c->out_filter); + int import_changed = !filter_same(cf->in_filter, c->in_filter.filter); + int export_changed = !filter_same(cf->out_filter, c->out_filter.filter); if (c->preference != cf->preference) import_changed = 1; @@ -602,8 +627,15 @@ channel_reconfigure(struct channel *c, struct channel_config *cf) export_changed = 1; /* Reconfigure channel fields */ - c->in_filter = cf->in_filter; - c->out_filter = cf->out_filter; + c->in_filter.filter = cf->in_filter; + c->out_filter.filter = cf->out_filter; + + if (import_changed) + unsubscribe_all(&(c->in_filter.notifiers)); + + if (export_changed) + unsubscribe_all(&(c->out_filter.notifiers)); + c->rx_limit = cf->rx_limit; c->in_limit = cf->in_limit; c->out_limit = cf->out_limit; @@ -1301,10 +1333,20 @@ protos_dump_all(void) WALK_LIST(c, p->channels) { debug("\tTABLE %s\n", c->table->name); - if (c->in_filter) - debug("\tInput filter: %s\n", filter_name(c->in_filter)); - if (c->out_filter) - debug("\tOutput filter: %s\n", filter_name(c->out_filter)); + if (c->in_filter.filter) + debug("\tInput filter: %s\n", filter_name(c->in_filter.filter)); + if (!EMPTY_LIST(c->in_filter.notifiers)) + { + debug("\tInput filter notifiers:\n"); + listeners_dump(NULL, &(c->in_filter.notifiers)); + } + if (c->out_filter.filter) + debug("\tOutput filter: %s\n", filter_name(c->out_filter.filter)); + if (!EMPTY_LIST(c->out_filter.notifiers)) + { + debug("\tOutput filter notifiers:\n"); + listeners_dump(NULL, &(c->out_filter.notifiers)); + } } if (p->proto->dump && (p->proto_state != PS_DOWN)) @@ -1731,8 +1773,8 @@ channel_show_info(struct channel *c) cli_msg(-1006, " State: %s", c_states[c->channel_state]); cli_msg(-1006, " Table: %s", c->table->name); cli_msg(-1006, " Preference: %d", c->preference); - cli_msg(-1006, " Input filter: %s", filter_name(c->in_filter)); - cli_msg(-1006, " Output filter: %s", filter_name(c->out_filter)); + cli_msg(-1006, " Input filter: %s", filter_name(c->in_filter.filter)); + cli_msg(-1006, " Output filter: %s", filter_name(c->out_filter.filter)); if (graceful_restart_state == GRS_ACTIVE) cli_msg(-1006, " GR recovery: %s%s", diff --git a/nest/protocol.h b/nest/protocol.h index 6c04071b5..23dae3db3 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -12,6 +12,8 @@ #include "lib/lists.h" #include "lib/resource.h" #include "lib/event.h" +#include "filter/filter.h" +#include "nest/notify.h" #include "nest/route.h" #include "conf/conf.h" @@ -511,8 +513,8 @@ struct channel { struct proto *proto; struct rtable *table; - struct filter *in_filter; /* Input filter */ - struct filter *out_filter; /* Output filter */ + struct filter_slot in_filter; /* Input filter */ + struct filter_slot out_filter; /* Output filter */ struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */ struct channel_limit in_limit; /* Input limit */ struct channel_limit out_limit; /* Output limit */ @@ -620,6 +622,7 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP) static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); } void channel_request_feeding(struct channel *c); +void channel_request_reload(struct channel *c); void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); int channel_reconfigure(struct channel *c, struct channel_config *cf); diff --git a/nest/route.h b/nest/route.h index 8dfbb3762..00747b6c5 100644 --- a/nest/route.h +++ b/nest/route.h @@ -19,6 +19,7 @@ struct proto; struct rte_src; struct symbol; struct filter; +struct filter_slot; struct cli; /* @@ -148,6 +149,7 @@ typedef struct rtable { struct fib fib; char *name; /* Name of this table */ list channels; /* List of attached channels (struct channel) */ + list listeners; /* List of attached listeners (struct listener) */ uint addr_type; /* Type of address data stored in table (NET_*) */ int pipe_busy; /* Pipe loop detection */ int use_count; /* Number of protocols using this table */ @@ -297,7 +299,7 @@ rte *rte_find(net *net, struct rte_src *src); rte *rte_get_temp(struct rta *); void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src); /* rte_update() moved to protocol.h to avoid dependency conflicts */ -int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter); +int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter_slot *filter_slot); rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent); void rt_refresh_begin(rtable *t, struct channel *c); void rt_refresh_end(rtable *t, struct channel *c); @@ -318,6 +320,10 @@ void rt_reload_channel_abort(struct channel *c); void rt_prune_sync(rtable *t, int all); struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); +struct rt_notify { + struct network *net; + rte *new, *old, *new_best, *old_best, *before_old; +}; /* Default limit for ECMP next hops, defined in sysdep code */ extern const int rt_default_ecmp; diff --git a/nest/rt-show.c b/nest/rt-show.c index c7bcdf2f6..0e6b15f64 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -149,7 +149,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) * command may change the export filter and do not update routes. */ int do_export = (ic > 0) || - (f_run(ec->out_filter, &e, c->show_pool, FF_SILENT) <= F_ACCEPT); + (f_run(&(ec->out_filter), &e, c->show_pool, FF_SILENT | FF_TEMP) <= F_ACCEPT); + if (do_export != (d->export_mode == RSEM_EXPORT)) goto skip; @@ -162,7 +163,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (d->show_protocol && (d->show_protocol != e->attrs->src->proto)) goto skip; - if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT) + struct filter_slot fs = { .filter = d->filter }; + if (f_run(&fs, &e, c->show_pool, FF_TEMP) > F_ACCEPT) goto skip; if (d->stats < 2) diff --git a/nest/rt-table.c b/nest/rt-table.c index 6bf07a091..0646ece32 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -397,7 +397,7 @@ static rte * export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent) { struct proto *p = c->proto; - struct filter *filter = c->out_filter; + struct filter *filter = c->out_filter.filter; struct proto_stats *stats = &c->stats; rte *rt; int v; @@ -426,7 +426,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si rte_make_tmp_attrs(&rt, pool); v = filter && ((filter == FILTER_REJECT) || - (f_run(filter, &rt, pool, + (f_run(&(c->out_filter), &rt, pool, (silent ? FF_SILENT : 0)) > F_ACCEPT)); if (v) { @@ -941,6 +941,17 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, else rt_notify_basic(c, net, new, old, 0); } + + struct rt_notify rtn = { + .net = net, + .new = new, + .old = old, + .new_best = new_best, + .old_best = old_best, + .before_old = before_old, + }; + + notify(&(tab->listeners), &rtn); } static inline int @@ -1364,7 +1375,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) { struct proto *p = c->proto; struct proto_stats *stats = &c->stats; - struct filter *filter = c->in_filter; + struct filter *filter = c->in_filter.filter; rte *dummy = NULL; net *nn; @@ -1409,7 +1420,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) if (filter && (filter != FILTER_REJECT)) { ea_list *oldea = new->attrs->eattrs; - int fr = f_run(filter, &new, rte_update_pool, 0); + int fr = f_run(&(c->in_filter), &new, rte_update_pool, 0); if (fr > F_ACCEPT) { stats->imp_updates_filtered++; @@ -1503,9 +1514,9 @@ rte_modify(rte *old) rte_update_unlock(); } -/* Check rtable for best route to given net whether it would be exported do p */ +/* One time check rtable for best route to given net whether it would be exported do p */ int -rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) +rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter_slot *filter_slot) { net *n = net_find(t, a); rte *rt = n ? n->routes : NULL; @@ -1520,7 +1531,7 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) if (v == RIC_PROCESS) { rte_make_tmp_attrs(&rt, rte_update_pool); - v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT); + v = (f_run(filter_slot, &rt, rte_update_pool, FF_SILENT | FF_TEMP) <= F_ACCEPT); } /* Discard temporary rte */ @@ -1727,6 +1738,7 @@ rt_setup(pool *p, rtable *t, struct rtable_config *cf) t->addr_type = cf->addr_type; fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL); init_list(&t->channels); + init_list(&t->listeners); t->rt_event = ev_new_init(p, rt_event, t); t->gc_time = current_time(); diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index 95014958a..5769a44bf 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -498,7 +498,8 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) rte_make_tmp_attrs(&rt, s->linpool); - if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT) + struct filter_slot fs = { .filter = s->filter }; + if (f_run(&(fs), &rt, s->linpool, FF_TEMP) <= F_ACCEPT) mrt_rib_table_entry(s, rt); if (rt != rt0) diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index efb992cab..c1f6a59a0 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -266,8 +266,8 @@ pipe_show_proto_info(struct proto *P) cli_msg(-1006, " Peer table: %s", p->sec->table->name); cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]); cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]); - cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter)); - cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter)); + cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter.filter)); + cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter.filter)); channel_show_limit(&p->pri->in_limit, "Import limit:"); channel_show_limit(&p->sec->in_limit, "Export limit:"); diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 990b60249..d5b6c758f 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -560,7 +560,7 @@ radv_check_active(struct radv_proto *p) return 1; struct channel *c = p->p.main_channel; - return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter); + return rt_examine(c->table, &cf->trigger, &p->p, &(c->out_filter)); } static void diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index ded5dfe45..bf9274550 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -562,7 +562,7 @@ static struct rte * krt_export_net(struct krt_proto *p, net *net, rte **rt_free) { struct channel *c = p->p.main_channel; - struct filter *filter = c->out_filter; + struct filter *filter = c->out_filter.filter; rte *rt; if (c->ra_mode == RA_MERGED) @@ -584,7 +584,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free) if (filter == FILTER_ACCEPT) goto accept; - if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT) + if (f_run(&(c->out_filter), &rt, krt_filter_lp, FF_SILENT | FF_TEMP) > F_ACCEPT) goto reject; -- 2.47.2