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_interface.c b/ripngd/ripng_interface.c
index 8717bfb..3588463 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -163,38 +163,15 @@
   struct route_node *rp;
   struct ripng_info *rinfo;
   struct ripng_interface *ri;
+  struct list *list = NULL;
+  struct listnode *listnode = NULL, *nextnode = NULL;
 
   if (ripng)
-    {
-      for (rp = route_top (ripng->table); rp; rp = route_next (rp))
-	if ((rinfo = rp->info) != NULL)
-	  {
-	    /* Routes got through this interface. */
-	    if (rinfo->ifindex == ifp->ifindex
-		&& rinfo->type == ZEBRA_ROUTE_RIPNG
-		&& rinfo->sub_type == RIPNG_ROUTE_RTE)
-	      {
-		ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p,
-					 &rinfo->nexthop,
-					 rinfo->ifindex);
-
-		ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
-					   (struct prefix_ipv6 *)&rp->p,
-					   rinfo->ifindex);
-	      }
-	    else
-	      {
-		/* All redistributed routes got through this interface,
-		 * but the static and system ones are kept. */
-		if ((rinfo->ifindex == ifp->ifindex) &&
-		    (rinfo->type != ZEBRA_ROUTE_STATIC) &&
-		    (rinfo->type != ZEBRA_ROUTE_SYSTEM))
-		  ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
-					     (struct prefix_ipv6 *) &rp->p,
-					     rinfo->ifindex);
-	      }
-	  }
-    }
+    for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+      if ((list = rp->info) != NULL)
+        for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo))
+          if (rinfo->ifindex == ifp->ifindex)
+            ripng_ecmp_delete (rinfo);
 
   ri = ifp->info;