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; - - rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated"); - rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL); - - /* 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); - - if (e != old_best) - rte_free(e, tab); - else /* Freeing of the old best rte is postponed */ - free_old_best = 1; - - e = new; - count++; - } + count++; 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, &old_best->rte); + + updates[pos++] = (struct rte_multiupdate) { + .old = e, + .new = new, + }; + + /* Replace the route in the list */ + new->next = e->next; + *k = e = new; + } + + 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]"); + /* Announce the changes */ + for (int i=0; irte.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); + } - /* Propagate changes */ - rte_announce_i(tab, RA_UNDEF, n, NULL, NULL, n->routes, old_best); - - if (free_old_best) - rte_free(old_best, tab); + for (int i=0; i