diff --git a/nest/proto.c b/nest/proto.c index 9eebb110..76739556 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -51,6 +51,7 @@ static char *proto_state_name(struct proto *p); static void channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf); static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf); static void channel_reset_limit(struct channel *c, struct limit *l, int dir); +static int channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n); static void channel_feed_end(struct channel *c); static void channel_stop_export(struct channel *c); static void channel_export_stopped(struct rt_export_request *req); @@ -622,6 +623,7 @@ channel_start_export(struct channel *c) c->refeed_req.dump_req = channel_dump_refeed_req; c->refeed_req.log_state_change = channel_refeed_log_state_change; c->refeed_req.mark_seen = channel_rpe_mark_seen_refeed; + c->refeed_req.prefilter.hook = channel_refeed_prefilter; DBG("%s.%s: Channel start export req=%p\n", c->proto->name, c->name, &c->out_req); rt_request_export(c->table, &c->out_req); @@ -719,9 +721,26 @@ channel_init_feeding(struct channel *c) c->refeeding = c->refeed_pending; c->refeed_pending = NULL; c->refeed_trie = f_new_trie(lp_new(c->proto->pool), 0); + rt_request_export(c->table, &c->refeed_req); } +static int +channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n) +{ + const struct channel *c = + SKIP_BACK(struct channel, refeed_req, + SKIP_BACK(struct rt_export_request, prefilter, p) + ); + + for (struct channel_feeding_request *cfr = c->refeeding; cfr; cfr = cfr->next) + if (!cfr->trie || trie_match_net(cfr->trie, n)) + return 1; + + return 0; +} + + static void channel_feed_end(struct channel *c) { diff --git a/nest/rt-table.c b/nest/rt-table.c index d0b4f117..160d24b1 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2229,6 +2229,7 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho /* fall through */ case TE_ADDR_NONE: case TE_ADDR_TRIE: + case TE_ADDR_HOOK: FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); hook->h.event.hook = rt_feed_by_fib; break; @@ -2327,6 +2328,7 @@ rt_table_export_stop_locked(struct rt_export_hook *hh) } /* fall through */ case TE_ADDR_NONE: + case TE_ADDR_HOOK: case TE_ADDR_TRIE: fit_get(&tab->fib, &hook->feed_fit); break; @@ -4423,6 +4425,8 @@ rt_feed_by_fib(void *data) return; } } + else + req_trace(c->h.req, D_ROUTES, "Feeding %N rejected by prefilter", n->n.addr); } FIB_ITERATE_END; } diff --git a/nest/rt.h b/nest/rt.h index 5070fcc5..bd9f9363 100644 --- a/nest/rt.h +++ b/nest/rt.h @@ -304,6 +304,7 @@ struct rt_prefilter { union { const struct f_trie *trie; const net_addr *addr; /* Network prefilter address */ + int (*hook)(const struct rt_prefilter *, const net_addr *); }; /* Network prefilter mode (TE_ADDR_*) */ enum { @@ -312,6 +313,7 @@ struct rt_prefilter { TE_ADDR_FOR, /* Longest prefix match - show route for */ TE_ADDR_IN, /* Interval query - show route in */ TE_ADDR_TRIE, /* Query defined by trie */ + TE_ADDR_HOOK, /* Query processed by supplied custom hook */ } mode; } PACKED; @@ -352,6 +354,7 @@ static inline int rt_prefilter_net(const struct rt_prefilter *p, const net_addr case TE_ADDR_EQUAL: return net_equal(n, p->addr); case TE_ADDR_FOR: return net_in_netX(p->addr, n); case TE_ADDR_TRIE: return trie_match_net(p->trie, n); + case TE_ADDR_HOOK: return p->hook(p, n); } bug("Crazy prefilter application attempt failed wildly.");