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)
 	{