summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/rt-table.c72
1 files changed, 40 insertions, 32 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index ee69d7c4..837e0ab9 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -349,7 +349,7 @@ rte_mergable(rte *pri, rte *sec)
}
static void
-rte_trace(struct channel *c, rte *e, int dir, char *msg)
+rte_trace(struct channel *c, rte *e, int dir, const char *msg)
{
log(L_TRACE "%s.%s %c %s %N %uL %uG %s",
c->proto->name, c->name ?: "?", dir, msg, e->net, e->src->private_id, e->src->global_id,
@@ -357,14 +357,14 @@ rte_trace(struct channel *c, rte *e, int dir, char *msg)
}
static inline void
-rte_trace_in(uint flag, struct channel *c, rte *e, char *msg)
+rte_trace_in(uint flag, struct channel *c, rte *e, const char *msg)
{
if ((c->debug & flag) || (c->proto->debug & flag))
rte_trace(c, e, '>', msg);
}
static inline void
-rte_trace_out(uint flag, struct channel *c, rte *e, char *msg)
+rte_trace_out(uint flag, struct channel *c, rte *e, const char *msg)
{
if ((c->debug & flag) || (c->proto->debug & flag))
rte_trace(c, e, '<', msg);
@@ -1870,44 +1870,50 @@ rt_next_hop_update_rte(rtable *tab, net *n, rte *old)
static inline int
rt_next_hop_update_net(rtable *tab, net *n)
{
- struct rte_storage **k, *e, *new, *old_best, **new_best;
+ struct rte_storage *new;
int count = 0;
- int free_old_best = 0;
- old_best = n->routes;
+ struct rte_storage *old_best = n->routes;
if (!old_best)
return 0;
- for (k = &n->routes; e = *k; k = &e->next)
+ for (struct rte_storage *e, **k = &n->routes; e = *k; k = &e->next)
if (rta_next_hop_outdated(e->rte.attrs))
- {
- new = rt_next_hop_update_rte(tab, n, &e->rte);
- new->next = e->next;
- *k = new;
+ count++;
- rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated");
- rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
+ if (!count)
+ return 0;
+
+ struct rte_multiupdate {
+ struct rte_storage *old, *new;
+ } *updates = alloca(sizeof(struct rte_multiupdate) * count);
+
+ int pos = 0;
+ for (struct rte_storage *e, **k = &n->routes; e = *k; k = &e->next)
+ if (rta_next_hop_outdated(e->rte.attrs))
+ {
+ struct rte_storage *new = rt_next_hop_update_rte(tab, n, &e->rte);
/* Call a pre-comparison hook */
/* Not really an efficient way to compute this */
if (e->rte.src->proto->rte_recalculate)
- e->rte.src->proto->rte_recalculate(tab, n, &new->rte, &e->rte, NULL);
+ e->rte.src->proto->rte_recalculate(tab, n, &new->rte, &e->rte, &old_best->rte);
- if (e != old_best)
- rte_free(e, tab);
- else /* Freeing of the old best rte is postponed */
- free_old_best = 1;
+ updates[pos++] = (struct rte_multiupdate) {
+ .old = e,
+ .new = new,
+ };
- e = new;
- count++;
+ /* Replace the route in the list */
+ new->next = e->next;
+ *k = e = new;
}
- if (!count)
- return 0;
+ ASSERT_DIE(pos == count);
/* Find the new best route */
- new_best = NULL;
- for (k = &n->routes; e = *k; k = &e->next)
+ struct rte_storage **new_best = NULL;
+ for (struct rte_storage *e, **k = &n->routes; e = *k; k = &e->next)
{
if (!new_best || rte_better(&e->rte, &(*new_best)->rte))
new_best = k;
@@ -1922,15 +1928,17 @@ rt_next_hop_update_net(rtable *tab, net *n)
n->routes = new;
}
- /* Announce the new best route */
- if (new != old_best)
- rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated [best]");
-
- /* Propagate changes */
- rte_announce_i(tab, RA_UNDEF, n, NULL, NULL, n->routes, old_best);
+ /* Announce the changes */
+ for (int i=0; i<count; i++)
+ {
+ _Bool nb = (new == updates[i].new), ob = (old_best == updates[i].old);
+ const char *best_indicator[2][2] = { { "updated", "updated [-best]" }, { "updated [+best]", "updated [best]" } };
+ rte_trace_in(D_ROUTES, new->rte.sender, &updates[i].new->rte, best_indicator[nb][ob]);
+ rte_announce_i(tab, RA_UNDEF, n, updates[i].new, updates[i].old, new, old_best);
+ }
- if (free_old_best)
- rte_free(old_best, tab);
+ for (int i=0; i<count; i++)
+ rte_free(updates[i].old, tab);
return count;
}