mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Route export: passing the export state in a dedicated structure
This commit is contained in:
parent
eb5298f3e1
commit
1f5a3605cf
252
nest/rt-table.c
252
nest/rt-table.c
@ -351,6 +351,14 @@ rte_free_quick(rte *e)
|
||||
sl_free(rte_slab, e);
|
||||
}
|
||||
|
||||
struct rte_export_internal {
|
||||
struct rte_export pub;
|
||||
rte *new_best;
|
||||
rte *old_best;
|
||||
rte *rt_free;
|
||||
uint refeed:1;
|
||||
};
|
||||
|
||||
static int /* Actually better or at least as good as */
|
||||
rte_better(rte *new, rte *old)
|
||||
{
|
||||
@ -481,17 +489,18 @@ export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent)
|
||||
}
|
||||
|
||||
static void
|
||||
do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
|
||||
do_rt_notify(struct channel *c, struct rte_export_internal *e)
|
||||
{
|
||||
struct proto *p = c->proto;
|
||||
struct proto_stats *stats = &c->stats;
|
||||
struct rte_export *ep = &(e->pub);
|
||||
|
||||
if (refeed && new)
|
||||
if (e->refeed && ep->new)
|
||||
c->refeed_count++;
|
||||
|
||||
/* Apply export limit */
|
||||
struct channel_limit *l = &c->out_limit;
|
||||
if (l->action && !old && new)
|
||||
if (l->action && !ep->old && ep->new)
|
||||
{
|
||||
if (stats->exp_routes >= l->limit)
|
||||
channel_notify_limit(c, l, PLD_OUT, stats->exp_routes);
|
||||
@ -499,98 +508,82 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
|
||||
if (l->state == PLS_BLOCKED)
|
||||
{
|
||||
stats->exp_updates_rejected++;
|
||||
rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
|
||||
rte_trace_out(D_FILTERS, p, ep->new, "rejected [limit]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct rte_src *src = old ? old->attrs->src : new->attrs->src;
|
||||
|
||||
/* Apply export table */
|
||||
struct rte *old_exported = NULL;
|
||||
rte *old_exported = NULL;
|
||||
if (c->out_table)
|
||||
{
|
||||
if (!rte_update_out(c, net->n.addr, src, new, &old_exported, refeed))
|
||||
if (!rte_update_out(c, ep->net->n.addr, ep->old_src, ep->new, &(old_exported), e->refeed))
|
||||
return;
|
||||
}
|
||||
else if (c->out_filter == FILTER_ACCEPT)
|
||||
old_exported = old;
|
||||
old_exported = ep->old;
|
||||
|
||||
if (new)
|
||||
if (ep->new)
|
||||
stats->exp_updates_accepted++;
|
||||
else
|
||||
stats->exp_withdraws_accepted++;
|
||||
|
||||
if (old)
|
||||
if (ep->old)
|
||||
{
|
||||
bmap_clear(&c->export_map, old->id);
|
||||
bmap_clear(&c->export_map, ep->old->id);
|
||||
stats->exp_routes--;
|
||||
}
|
||||
|
||||
if (new)
|
||||
if (ep->new)
|
||||
{
|
||||
bmap_set(&c->export_map, new->id);
|
||||
bmap_set(&c->export_map, ep->new->id);
|
||||
stats->exp_routes++;
|
||||
}
|
||||
|
||||
if (p->debug & D_ROUTES)
|
||||
{
|
||||
if (new && old)
|
||||
rte_trace_out(D_ROUTES, p, new, "replaced");
|
||||
else if (new)
|
||||
rte_trace_out(D_ROUTES, p, new, "added");
|
||||
else if (old)
|
||||
rte_trace_out(D_ROUTES, p, old, "removed");
|
||||
if (ep->new && ep->old)
|
||||
rte_trace_out(D_ROUTES, p, ep->new, "replaced");
|
||||
else if (ep->new)
|
||||
rte_trace_out(D_ROUTES, p, ep->new, "added");
|
||||
else if (ep->old)
|
||||
rte_trace_out(D_ROUTES, p, ep->old, "removed");
|
||||
}
|
||||
|
||||
struct rte_export export = {
|
||||
.net = net,
|
||||
.new_src = new ? new->attrs->src : NULL,
|
||||
.new = new,
|
||||
.old_src = old ? old->attrs->src : NULL,
|
||||
.old = old,
|
||||
};
|
||||
ep->old = old_exported;
|
||||
|
||||
p->rt_notify(c, &export);
|
||||
p->rt_notify(c, ep);
|
||||
|
||||
if (c->out_table && old_exported)
|
||||
rte_free_quick(old_exported);
|
||||
}
|
||||
|
||||
static void
|
||||
rt_notify_basic(struct channel *c, net *net, rte *new, rte *old, int refeed)
|
||||
rt_notify_basic(struct channel *c, struct rte_export_internal *e)
|
||||
{
|
||||
// struct proto *p = c->proto;
|
||||
rte *new_free = NULL;
|
||||
|
||||
if (new)
|
||||
if (e->pub.new)
|
||||
c->stats.exp_updates_received++;
|
||||
else
|
||||
c->stats.exp_withdraws_received++;
|
||||
|
||||
if (new)
|
||||
new = export_filter(c, new, &new_free, 0);
|
||||
if (e->pub.new)
|
||||
e->pub.new = export_filter(c, e->pub.new, &e->rt_free, 0);
|
||||
|
||||
if (old && !bmap_test(&c->export_map, old->id))
|
||||
old = NULL;
|
||||
if (e->pub.old && !bmap_test(&c->export_map, e->pub.old->id))
|
||||
e->pub.old = NULL;
|
||||
|
||||
if (!new && !old)
|
||||
if (!e->pub.new && !e->pub.old)
|
||||
return;
|
||||
|
||||
do_rt_notify(c, net, new, old, refeed);
|
||||
|
||||
/* Discard temporary rte */
|
||||
if (new_free)
|
||||
rte_free(new_free);
|
||||
do_rt_notify(c, e);
|
||||
}
|
||||
|
||||
static void
|
||||
rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, int refeed)
|
||||
rt_notify_accepted(struct channel *c, struct rte_export_internal *e)
|
||||
{
|
||||
// struct proto *p = c->proto;
|
||||
rte *new_best = NULL;
|
||||
rte *old_best = NULL;
|
||||
rte *new_free = NULL;
|
||||
int new_first = 0;
|
||||
|
||||
/*
|
||||
@ -609,17 +602,17 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
|
||||
* old_best is after new_changed -> try new_changed, otherwise old_best
|
||||
*/
|
||||
|
||||
if (net->routes)
|
||||
if (e->pub.net->routes)
|
||||
c->stats.exp_updates_received++;
|
||||
else
|
||||
c->stats.exp_withdraws_received++;
|
||||
|
||||
/* Find old_best - either old_changed, or route for net->routes */
|
||||
if (old_changed && bmap_test(&c->export_map, old_changed->id))
|
||||
old_best = old_changed;
|
||||
if (e->pub.old && bmap_test(&c->export_map, e->pub.old->id))
|
||||
old_best = e->pub.old;
|
||||
else
|
||||
{
|
||||
for (rte *r = net->routes; rte_is_valid(r); r = r->next)
|
||||
for (rte *r = e->pub.net->routes; rte_is_valid(r); r = r->next)
|
||||
{
|
||||
if (bmap_test(&c->export_map, r->id))
|
||||
{
|
||||
@ -628,24 +621,24 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
|
||||
}
|
||||
|
||||
/* Note if new_changed found before old_best */
|
||||
if (r == new_changed)
|
||||
if (r == e->pub.new)
|
||||
new_first = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find new_best */
|
||||
if ((new_changed == old_changed) || (old_best == old_changed))
|
||||
if ((e->pub.new == e->pub.old) || (old_best == e->pub.old))
|
||||
{
|
||||
/* Feed or old_best changed -> find first accepted by filters */
|
||||
for (rte *r = net->routes; rte_is_valid(r); r = r->next)
|
||||
if (new_best = export_filter(c, r, &new_free, 0))
|
||||
for (rte *r = e->pub.net->routes; rte_is_valid(r); r = r->next)
|
||||
if (new_best = export_filter(c, r, &e->rt_free, 0))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Other cases -> either new_changed, or old_best (and nothing changed) */
|
||||
if (new_first && (new_changed = export_filter(c, new_changed, &new_free, 0)))
|
||||
new_best = new_changed;
|
||||
if (new_first && (e->pub.new = export_filter(c, e->pub.new, &e->rt_free, 0)))
|
||||
new_best = e->pub.new;
|
||||
else
|
||||
return;
|
||||
}
|
||||
@ -653,11 +646,12 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
|
||||
if (!new_best && !old_best)
|
||||
return;
|
||||
|
||||
do_rt_notify(c, net, new_best, old_best, refeed);
|
||||
e->pub.new = new_best;
|
||||
e->pub.new_src = new_best ? new_best->attrs->src : NULL;
|
||||
e->pub.old = old_best;
|
||||
e->pub.old_src = old_best ? old_best->attrs->src : NULL;
|
||||
|
||||
/* Discard temporary rte */
|
||||
if (new_free)
|
||||
rte_free(new_free);
|
||||
do_rt_notify(c, e);
|
||||
}
|
||||
|
||||
|
||||
@ -721,46 +715,41 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
|
||||
|
||||
|
||||
static void
|
||||
rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
|
||||
rte *new_best, rte *old_best, int refeed)
|
||||
rt_notify_merged(struct channel *c, struct rte_export_internal *e)
|
||||
{
|
||||
// struct proto *p = c->proto;
|
||||
rte *new_free = NULL;
|
||||
|
||||
/* We assume that all rte arguments are either NULL or rte_is_valid() */
|
||||
|
||||
/* This check should be done by the caller */
|
||||
if (!new_best && !old_best)
|
||||
if (!e->new_best && !e->old_best)
|
||||
return;
|
||||
|
||||
/* Check whether the change is relevant to the merged route */
|
||||
if ((new_best == old_best) &&
|
||||
(new_changed != old_changed) &&
|
||||
!rte_mergable(new_best, new_changed) &&
|
||||
!rte_mergable(old_best, old_changed))
|
||||
if ((e->new_best == e->old_best) &&
|
||||
(e->pub.new != e->pub.old) &&
|
||||
!rte_mergable(e->new_best, e->pub.new) &&
|
||||
!rte_mergable(e->old_best, e->pub.old))
|
||||
return;
|
||||
|
||||
if (new_best)
|
||||
if (e->new_best)
|
||||
c->stats.exp_updates_received++;
|
||||
else
|
||||
c->stats.exp_withdraws_received++;
|
||||
|
||||
/* Prepare new merged route */
|
||||
if (new_best)
|
||||
new_best = rt_export_merged(c, net, &new_free, rte_update_pool, 0);
|
||||
if (e->new_best)
|
||||
e->pub.new = rt_export_merged(c, e->pub.net, &(e->rt_free), rte_update_pool, 0);
|
||||
|
||||
/* Check old merged route */
|
||||
if (old_best && !bmap_test(&c->export_map, old_best->id))
|
||||
old_best = NULL;
|
||||
if (e->old_best && !bmap_test(&c->export_map, e->old_best->id))
|
||||
e->pub.old = NULL;
|
||||
|
||||
if (!new_best && !old_best)
|
||||
if (!e->pub.new && !e->pub.old)
|
||||
return;
|
||||
|
||||
do_rt_notify(c, net, new_best, old_best, refeed);
|
||||
e->pub.new_src = e->pub.new ? e->pub.new->attrs->src : NULL;
|
||||
e->pub.old_src = e->pub.old ? e->pub.old->attrs->src : NULL;
|
||||
|
||||
/* Discard temporary rte */
|
||||
if (new_free)
|
||||
rte_free(new_free);
|
||||
do_rt_notify(c, e);
|
||||
}
|
||||
|
||||
|
||||
@ -842,26 +831,48 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
|
||||
if (type && (type != c->ra_mode))
|
||||
continue;
|
||||
|
||||
struct rte_export_internal e = {
|
||||
.pub = {
|
||||
.net = net,
|
||||
.new_src = new ? new->attrs->src : NULL,
|
||||
.new = new,
|
||||
.old_src = old ? old->attrs->src : NULL,
|
||||
.old = old,
|
||||
},
|
||||
.new_best = new_best,
|
||||
.old_best = old_best,
|
||||
};
|
||||
|
||||
switch (c->ra_mode)
|
||||
{
|
||||
case RA_OPTIMAL:
|
||||
if (new_best != old_best)
|
||||
rt_notify_basic(c, net, new_best, old_best, 0);
|
||||
{
|
||||
e.pub.new = new_best;
|
||||
e.pub.new_src = new_best ? new_best->attrs->src : NULL;
|
||||
e.pub.old = old_best;
|
||||
e.pub.old_src = old_best ? old_best->attrs->src : NULL;
|
||||
rt_notify_basic(c, &e);
|
||||
}
|
||||
break;
|
||||
|
||||
case RA_ANY:
|
||||
if (new != old)
|
||||
rt_notify_basic(c, net, new, old, 0);
|
||||
rt_notify_basic(c, &e);
|
||||
break;
|
||||
|
||||
case RA_ACCEPTED:
|
||||
rt_notify_accepted(c, net, new, old, 0);
|
||||
rt_notify_accepted(c, &e);
|
||||
break;
|
||||
|
||||
case RA_MERGED:
|
||||
rt_notify_merged(c, net, new, old, new_best, old_best, 0);
|
||||
rt_notify_merged(c, &e);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Discard temporary rte */
|
||||
if (e.rt_free)
|
||||
rte_free(e.rt_free);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2104,19 +2115,6 @@ rt_commit(struct config *new, struct config *old)
|
||||
DBG("\tdone\n");
|
||||
}
|
||||
|
||||
static inline void
|
||||
do_feed_channel(struct channel *c, net *n, rte *e)
|
||||
{
|
||||
rte_update_lock();
|
||||
if (c->ra_mode == RA_ACCEPTED)
|
||||
rt_notify_accepted(c, n, NULL, NULL, c->refeeding);
|
||||
else if (c->ra_mode == RA_MERGED)
|
||||
rt_notify_merged(c, n, NULL, NULL, e, e, c->refeeding);
|
||||
else /* RA_BASIC */
|
||||
rt_notify_basic(c, n, e, e, c->refeeding);
|
||||
rte_update_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* rt_feed_channel - advertise all routes to a channel
|
||||
* @c: channel to be fed
|
||||
@ -2142,39 +2140,57 @@ rt_feed_channel(struct channel *c)
|
||||
|
||||
FIB_ITERATE_START(&c->table->fib, fit, net, n)
|
||||
{
|
||||
rte *e = n->routes;
|
||||
if (max_feed <= 0)
|
||||
{
|
||||
FIB_ITERATE_PUT(fit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((c->ra_mode == RA_OPTIMAL) ||
|
||||
(c->ra_mode == RA_ACCEPTED) ||
|
||||
(c->ra_mode == RA_MERGED))
|
||||
for (rte *e = n->routes; e; e = e->next)
|
||||
{
|
||||
if (c->export_state != ES_FEEDING)
|
||||
goto done;
|
||||
|
||||
if (rte_is_valid(e))
|
||||
{
|
||||
/* In the meantime, the protocol may fell down */
|
||||
if (c->export_state != ES_FEEDING)
|
||||
goto done;
|
||||
{
|
||||
max_feed--;
|
||||
|
||||
do_feed_channel(c, n, e);
|
||||
max_feed--;
|
||||
struct rte_export_internal ee = {
|
||||
.pub = {
|
||||
.net = n,
|
||||
},
|
||||
.new_best = n->routes,
|
||||
.old_best = n->routes,
|
||||
.refeed = c->refeeding,
|
||||
};
|
||||
|
||||
switch (c->ra_mode) {
|
||||
case RA_OPTIMAL:
|
||||
case RA_ANY:
|
||||
ee.pub.new = e;
|
||||
ee.pub.new_src = e->attrs->src;
|
||||
ee.pub.old = e;
|
||||
ee.pub.old_src = e->attrs->src;
|
||||
rt_notify_basic(c, &ee);
|
||||
break;
|
||||
case RA_ACCEPTED:
|
||||
rt_notify_accepted(c, &ee);
|
||||
break;
|
||||
case RA_MERGED:
|
||||
rt_notify_merged(c, &ee);
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if (c->ra_mode == RA_ANY)
|
||||
for(e = n->routes; e; e = e->next)
|
||||
{
|
||||
/* In the meantime, the protocol may fell down */
|
||||
if (c->export_state != ES_FEEDING)
|
||||
goto done;
|
||||
/* Discard temporary rte */
|
||||
if (ee.rt_free)
|
||||
rte_free(ee.rt_free);
|
||||
}
|
||||
|
||||
if (!rte_is_valid(e))
|
||||
continue;
|
||||
|
||||
do_feed_channel(c, n, e);
|
||||
max_feed--;
|
||||
}
|
||||
if (c->ra_mode != RA_ANY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
FIB_ITERATE_END;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user