0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 02:01:55 +00:00

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.
This commit is contained in:
Maria Matejka 2020-03-09 15:31:10 +01:00
parent f2e9c7b285
commit e64fd37675
5 changed files with 47 additions and 14 deletions

View File

@ -299,6 +299,7 @@ channel_stop_export(struct channel *c)
c->export_state = ES_DOWN; c->export_state = ES_DOWN;
c->stats.exp_routes = 0; c->stats.exp_routes = 0;
bmap_reset(&c->export_map, 1024); bmap_reset(&c->export_map, 1024);
bmap_reset(&c->export_reject_map, 1024);
} }
@ -378,6 +379,7 @@ channel_do_start(struct channel *c)
c->feed_event = ev_new_init(c->proto->pool, channel_feed_loop, 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_map, c->proto->pool, 1024);
bmap_init(&c->export_reject_map, c->proto->pool, 1024);
memset(&c->stats, 0, sizeof(struct proto_stats)); memset(&c->stats, 0, sizeof(struct proto_stats));
channel_reset_limit(&c->rx_limit); channel_reset_limit(&c->rx_limit);
@ -400,6 +402,7 @@ channel_do_flush(struct channel *c)
/* This have to be done in here, as channel pool is freed before channel_do_down() */ /* 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_map);
bmap_free(&c->export_reject_map);
c->in_table = NULL; c->in_table = NULL;
c->reload_event = NULL; c->reload_event = NULL;
c->out_table = NULL; c->out_table = NULL;

View File

@ -499,7 +499,8 @@ struct channel {
struct rtable *table; struct rtable *table;
const struct filter *in_filter; /* Input filter */ const struct filter *in_filter; /* Input filter */
const struct filter *out_filter; /* Output 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 rx_limit; /* Receive limit (for in_keep_filtered) */
struct channel_limit in_limit; /* Input limit */ struct channel_limit in_limit; /* Input limit */
struct channel_limit out_limit; /* Output limit */ struct channel_limit out_limit; /* Output limit */

View File

@ -320,7 +320,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
void *net_route(rtable *tab, const net_addr *n); void *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn); int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
rte *rte_find(net *net, struct rte_src *src); 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); 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_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c); void rt_refresh_end(rtable *t, struct channel *c);

View File

@ -434,33 +434,36 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
const struct filter *filter = c->out_filter; const struct filter *filter = c->out_filter;
struct proto_stats *stats = &c->stats; struct proto_stats *stats = &c->stats;
rte *rt; rte *rt;
int v;
rt = rt0; rt = rt0;
*rt_free = NULL; *rt_free = NULL;
v = p->preexport ? p->preexport(p, &rt, pool) : 0; /* Do nothing if we have already rejected the route */
if (v < 0) 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) if (silent)
goto reject; goto reject;
stats->exp_updates_rejected++; stats->exp_updates_rejected++;
if (v == RIC_REJECT) if (pv == RIC_REJECT)
rte_trace_out(D_FILTERS, p, rt, "rejected by protocol"); rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
goto reject; goto reject;
} }
if (v > 0) if (pv > 0)
{ {
if (!silent) if (!silent)
rte_trace_out(D_FILTERS, p, rt, "forced accept by protocol"); rte_trace_out(D_FILTERS, p, rt, "forced accept by protocol");
goto accept; goto accept;
} }
v = filter && ((filter == FILTER_REJECT) || int fv = filter && ((filter == FILTER_REJECT) ||
(f_run(filter, &rt, pool, (f_run(filter, &rt, pool,
(silent ? FF_SILENT : 0)) > F_ACCEPT)); (silent ? FF_SILENT : 0)) > F_ACCEPT));
if (v) if (fv)
{ {
if (silent) if (silent)
goto reject; goto reject;
@ -471,11 +474,19 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
} }
accept: accept:
/* We have accepted the route */
bmap_clear(&c->export_reject_map, rt0->id);
/* Discard temporary rte */
if (rt != rt0) if (rt != rt0)
*rt_free = rt; *rt_free = rt;
return rt; return rt;
reject: reject:
/* We have rejected the route by filter */
if (pv == 0)
bmap_set(&c->export_reject_map, rt0->id);
/* Discard temporary rte */ /* Discard temporary rte */
if (rt != rt0) if (rt != rt0)
rte_free(rt); rte_free(rt);
@ -829,7 +840,16 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
continue; continue;
if (type && (type != c->ra_mode)) 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; continue;
}
struct rte_export_internal e = { struct rte_export_internal e = {
.pub = { .pub = {
@ -880,6 +900,11 @@ next_channel:
/* Discard temporary rte */ /* Discard temporary rte */
if (e.rt_free) if (e.rt_free)
rte_free(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);
} }
} }
@ -1383,22 +1408,26 @@ rte_modify(rte *old)
rte_update_unlock(); 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 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; rte *rt = n ? n->routes : NULL;
if (!rte_is_valid(rt)) if (!rte_is_valid(rt))
return 0; return 0;
if (bmap_test(&c->export_reject_map, rt->id))
return 0;
rte_update_lock(); rte_update_lock();
struct proto *p = c->proto;
/* Rest is stripped down export_filter() */ /* Rest is stripped down export_filter() */
int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0; int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0;
if (v == RIC_PROCESS) 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 */ /* Discard temporary rte */
if (rt != n->routes) if (rt != n->routes)

View File

@ -555,7 +555,7 @@ radv_check_active(struct radv_proto *p)
return 1; return 1;
struct channel *c = p->p.main_channel; 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 static void