ripngd: add ECMP support
* Each node in the routing table is changed into a list, holding
the multiple equal-cost paths.
* If one of the multiple entries gets less-preferred (greater
metric or greater distance), it will be directly deleted instead
of starting a garbage-collection timer for it.
The garbage-collection timer is started only when the last entry
in the list gets INFINITY.
* Some new functions are used to maintain the ECMP list. And hence
ripng_route_process(), ripng_redistribute_add() and ripng_timeout()
are significantly simplified.
* ripng_zebra_ipv6_add() and ripng_zebra_ipv6_delete() now can share
the common code. The common part is moved to ripng_zebra_ipv6_send().
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Vincent Jardin <vincent.jardin@6wind.com>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c
index d4bf026..f26302e 100644
--- a/ripngd/ripng_route.c
+++ b/ripngd/ripng_route.c
@@ -40,7 +40,7 @@
return new;
}
-static void
+void
ripng_aggregate_free (struct ripng_aggregate *aggregate)
{
XFREE (MTYPE_RIPNG_AGGREGATE, aggregate);
@@ -76,6 +76,23 @@
}
}
+/* Aggregate count decrement check for a list. */
+void
+ripng_aggregate_decrement_list (struct route_node *child, struct list *list)
+{
+ struct route_node *np;
+ struct ripng_aggregate *aggregate;
+ struct ripng_info *rinfo = NULL;
+ struct listnode *node = NULL;
+
+ for (np = child; np; np = np->parent)
+ if ((aggregate = np->aggregate) != NULL)
+ aggregate->count -= listcount (list);
+
+ for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
+ rinfo->suppress--;
+}
+
/* RIPng routes treatment. */
int
ripng_aggregate_add (struct prefix *p)
@@ -85,6 +102,8 @@
struct ripng_info *rinfo;
struct ripng_aggregate *aggregate;
struct ripng_aggregate *sub;
+ struct list *list = NULL;
+ struct listnode *node = NULL;
/* Get top node for aggregation. */
top = route_node_get (ripng->table, p);
@@ -99,11 +118,12 @@
for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top))
{
/* Suppress normal route. */
- if ((rinfo = rp->info) != NULL)
- {
- aggregate->count++;
- rinfo->suppress++;
- }
+ if ((list = rp->info) != NULL)
+ for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
+ {
+ aggregate->count++;
+ rinfo->suppress++;
+ }
/* Suppress aggregate route. This may not need. */
if (rp != top && (sub = rp->aggregate) != NULL)
{
@@ -124,6 +144,8 @@
struct ripng_info *rinfo;
struct ripng_aggregate *aggregate;
struct ripng_aggregate *sub;
+ struct list *list = NULL;
+ struct listnode *node = NULL;
/* Get top node for aggregation. */
top = route_node_get (ripng->table, p);
@@ -135,11 +157,12 @@
for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top))
{
/* Suppress normal route. */
- if ((rinfo = rp->info) != NULL)
- {
- aggregate->count--;
- rinfo->suppress--;
- }
+ if ((list = rp->info) != NULL)
+ for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
+ {
+ aggregate->count--;
+ rinfo->suppress--;
+ }
if (rp != top && (sub = rp->aggregate) != NULL)
{