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)
{
}
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);
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;
/*
* 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))
{
}
/* 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;
}
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);
}
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);
}
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);
}
}
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
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))
- if (rte_is_valid(e))
- {
- /* In the meantime, the protocol may fell down */
- if (c->export_state != ES_FEEDING)
- goto done;
+ for (rte *e = n->routes; e; e = e->next)
+ {
+ if (c->export_state != ES_FEEDING)
+ goto done;
- do_feed_channel(c, n, e);
- max_feed--;
+ if (rte_is_valid(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;
-
- if (!rte_is_valid(e))
- continue;
+ /* Discard temporary rte */
+ if (ee.rt_free)
+ rte_free(ee.rt_free);
+ }
- do_feed_channel(c, n, e);
- max_feed--;
- }
+ if (c->ra_mode != RA_ANY)
+ break;
+ }
}
FIB_ITERATE_END;