diff options
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r-- | nest/rt-table.c | 72 |
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; } |