From: Maria Matejka Date: Mon, 9 Mar 2020 14:31:10 +0000 (+0100) Subject: Route export: rejected by filter bitmap X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7930c03a234fbe5185bdda270a4a85f49b3be8f5;p=thirdparty%2Fbird.git Route export: rejected by filter bitmap If a route has been rejected by filter, store that information to avoid repeated export filter runs on rejected routes. --- diff --git a/nest/proto.c b/nest/proto.c index 1c27e6381..b3b048193 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -463,6 +463,7 @@ channel_stop_export(struct channel *c) c->export_state = ES_DOWN; c->stats.exp_routes = 0; bmap_reset(&c->export_map, 1024); + bmap_reset(&c->export_reject_map, 1024); } @@ -550,6 +551,7 @@ channel_do_start(struct channel *c) c->feed_event = ev_new_init(c->proto->pool, channel_feed_loop, c); bmap_init(&c->export_map, c->proto->pool, 1024); + bmap_init(&c->export_reject_map, c->proto->pool, 1024); memset(&c->stats, 0, sizeof(struct proto_stats)); channel_reset_limit(&c->rx_limit); @@ -583,6 +585,7 @@ channel_do_flush(struct channel *c) /* This have to be done in here, as channel pool is freed before channel_do_down() */ bmap_free(&c->export_map); + bmap_free(&c->export_reject_map); c->in_table = NULL; c->reload_event = NULL; c->out_table = NULL; diff --git a/nest/protocol.h b/nest/protocol.h index 7bc7d728f..ea063326c 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -506,7 +506,8 @@ struct channel { struct rtable *table; const struct filter *in_filter; /* Input filter */ const struct filter *out_filter; /* Output filter */ - struct bmap export_map; /* Keeps track which routes passed export filter */ + struct bmap export_map; /* Keeps track which routes were really exported */ + struct bmap export_reject_map; /* Keeps track which routes were rejected by export 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 */ diff --git a/nest/route.h b/nest/route.h index 3d4a01f01..2759bc172 100644 --- a/nest/route.h +++ b/nest/route.h @@ -337,7 +337,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f void *net_route(rtable *tab, const net_addr *n); int net_roa_check(rtable *tab, const net_addr *n, u32 asn); rte *rte_find(net *net, struct rte_src *src); -int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter); +int rt_examine(struct channel *c, net_addr *a); 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); diff --git a/nest/rt-table.c b/nest/rt-table.c index 5e5fa22bc..921608056 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -442,33 +442,36 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si const struct filter *filter = c->out_filter; struct proto_stats *stats = &c->stats; rte *rt; - int v; rt = rt0; *rt_free = NULL; - v = p->preexport ? p->preexport(p, &rt, pool) : 0; - if (v < 0) + /* Do nothing if we have already rejected the route */ + if (silent && bmap_test(&c->export_reject_map, rt0->id)) + return NULL; + + int pv = p->preexport ? p->preexport(p, &rt, pool) : 0; + if (pv < 0) { if (silent) goto reject; stats->exp_updates_rejected++; - if (v == RIC_REJECT) + if (pv == RIC_REJECT) rte_trace_out(D_FILTERS, c, rt, "rejected by protocol"); goto reject; } - if (v > 0) + if (pv > 0) { if (!silent) rte_trace_out(D_FILTERS, c, rt, "forced accept by protocol"); goto accept; } - v = filter && ((filter == FILTER_REJECT) || + int fv = filter && ((filter == FILTER_REJECT) || (f_run(filter, &rt, pool, (silent ? FF_SILENT : 0)) > F_ACCEPT)); - if (v) + if (fv) { if (silent) goto reject; @@ -479,11 +482,19 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si } accept: + /* We have accepted the route */ + bmap_clear(&c->export_reject_map, rt0->id); + + /* Discard temporary rte */ if (rt != rt0) *rt_free = rt; return rt; reject: + /* We have rejected the route by filter */ + if (pv == 0) + bmap_set(&c->export_reject_map, rt0->id); + /* Discard temporary rte */ if (rt != rt0) rte_free(rt); @@ -839,7 +850,16 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old, continue; if (type && (type != c->ra_mode)) + { + /* If skipping other means of announcement, + * drop the rejection bit anyway + * as we won't get this route as old any more. + * This happens when updating hostentries. */ + if (old) + bmap_clear(&c->export_reject_map, old->id); + continue; + } struct rte_export_internal e = { .pub = { @@ -890,6 +910,11 @@ next_channel: /* Discard temporary rte */ if (e.rt_free) rte_free(e.rt_free); + + /* Drop the old stored rejection if applicable. + * new->id == old->id happens when updating hostentries. */ + if (old && (!new || (new->id != old->id))) + bmap_clear(&c->export_reject_map, old->id); } } @@ -1402,22 +1427,26 @@ rte_modify(rte *old) rte_update_unlock(); } -/* Check rtable for best route to given net whether it would be exported do p */ +/* Check channel for best route to given net whether it would be exported */ int -rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter) +rt_examine(struct channel *c, net_addr *a) { - net *n = net_find(t, a); + net *n = net_find(c->table, a); rte *rt = n ? n->routes : NULL; if (!rte_is_valid(rt)) return 0; + if (bmap_test(&c->export_reject_map, rt->id)) + return 0; + rte_update_lock(); + struct proto *p = c->proto; /* Rest is stripped down export_filter() */ int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0; if (v == RIC_PROCESS) - v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT); + v = (f_run(c->out_filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT); /* Discard temporary rte */ if (rt != n->routes) diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 042d37696..2f95a0bbc 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -555,7 +555,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, &cf->trigger); } static void