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/ripngd.c b/ripngd/ripngd.c
index 4c0b67d..21e45b6 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -421,8 +421,13 @@
rp = rinfo->rp;
/* Unlock route_node. */
- rp->info = NULL;
- route_unlock_node (rp);
+ listnode_delete (rp->info, rinfo);
+ if (list_isempty ((struct list *)rp->info))
+ {
+ list_free (rp->info);
+ rp->info = NULL;
+ route_unlock_node (rp);
+ }
/* Free RIPng routing information. */
ripng_info_free (rinfo);
@@ -430,41 +435,159 @@
return 0;
}
+static void ripng_timeout_update (struct ripng_info *rinfo);
+
+/* Add new route to the ECMP list.
+ * RETURN: the new entry added in the list
+ */
+struct ripng_info *
+ripng_ecmp_add (struct ripng_info *rinfo_new)
+{
+ struct route_node *rp = rinfo_new->rp;
+ struct ripng_info *rinfo = NULL;
+ struct list *list = NULL;
+
+ if (rp->info == NULL)
+ rp->info = list_new ();
+ list = (struct list *)rp->info;
+
+ rinfo = ripng_info_new ();
+ memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
+ listnode_add (list, rinfo);
+
+ if (ripng_route_rte (rinfo))
+ {
+ ripng_timeout_update (rinfo);
+ ripng_zebra_ipv6_add (rp);
+ }
+
+ ripng_aggregate_increment (rp, rinfo);
+
+ /* Set the route change flag on the first entry. */
+ rinfo = listgetdata (listhead (list));
+ SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
+
+ /* Signal the output process to trigger an update. */
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+
+ return rinfo;
+}
+
+/* Replace the ECMP list with the new route.
+ * RETURN: the new entry added in the list
+ */
+struct ripng_info *
+ripng_ecmp_replace (struct ripng_info *rinfo_new)
+{
+ struct route_node *rp = rinfo_new->rp;
+ struct list *list = (struct list *)rp->info;
+ struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
+ struct listnode *node = NULL, *nextnode = NULL;
+
+ if (list == NULL || listcount (list) == 0)
+ return ripng_ecmp_add (rinfo_new);
+
+ /* Get the first entry */
+ rinfo = listgetdata (listhead (list));
+
+ /* Learnt route replaced by a local one. Delete it from zebra. */
+ if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new))
+ if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
+ ripng_zebra_ipv6_delete (rp);
+
+ if (rinfo->metric != RIPNG_METRIC_INFINITY)
+ ripng_aggregate_decrement_list (rp, list);
+
+ /* Re-use the first entry, and delete the others. */
+ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
+ if (tmp_rinfo != rinfo)
+ {
+ RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
+ RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
+ list_delete_node (list, node);
+ ripng_info_free (tmp_rinfo);
+ }
+
+ RIPNG_TIMER_OFF (rinfo->t_timeout);
+ RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+ memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
+
+ if (ripng_route_rte (rinfo))
+ {
+ ripng_timeout_update (rinfo);
+ /* The ADD message implies an update. */
+ ripng_zebra_ipv6_add (rp);
+ }
+
+ ripng_aggregate_increment (rp, rinfo);
+
+ /* Set the route change flag. */
+ SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
+
+ /* Signal the output process to trigger an update. */
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+
+ return rinfo;
+}
+
+/* Delete one route from the ECMP list.
+ * RETURN:
+ * null - the entry is freed, and other entries exist in the list
+ * the entry - the entry is the last one in the list; its metric is set
+ * to INFINITY, and the garbage collector is started for it
+ */
+struct ripng_info *
+ripng_ecmp_delete (struct ripng_info *rinfo)
+{
+ struct route_node *rp = rinfo->rp;
+ struct list *list = (struct list *)rp->info;
+
+ RIPNG_TIMER_OFF (rinfo->t_timeout);
+
+ if (rinfo->metric != RIPNG_METRIC_INFINITY)
+ ripng_aggregate_decrement (rp, rinfo);
+
+ if (listcount (list) > 1)
+ {
+ /* Some other ECMP entries still exist. Just delete this entry. */
+ RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+ listnode_delete (list, rinfo);
+ if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
+ /* The ADD message implies the update. */
+ ripng_zebra_ipv6_add (rp);
+ ripng_info_free (rinfo);
+ rinfo = NULL;
+ }
+ else
+ {
+ assert (rinfo == listgetdata (listhead (list)));
+
+ /* This is the only entry left in the list. We must keep it in
+ * the list for garbage collection time, with INFINITY metric. */
+
+ rinfo->metric = RIPNG_METRIC_INFINITY;
+ RIPNG_TIMER_ON (rinfo->t_garbage_collect,
+ ripng_garbage_collect, ripng->garbage_time);
+
+ if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
+ ripng_zebra_ipv6_delete (rp);
+ }
+
+ /* Set the route change flag on the first entry. */
+ rinfo = listgetdata (listhead (list));
+ SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
+
+ /* Signal the output process to trigger an update. */
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+
+ return rinfo;
+}
+
/* Timeout RIPng routes. */
static int
ripng_timeout (struct thread *t)
{
- struct ripng_info *rinfo;
- struct route_node *rp;
-
- rinfo = THREAD_ARG (t);
- rinfo->t_timeout = NULL;
-
- /* Get route_node pointer. */
- rp = rinfo->rp;
-
- /* - The garbage-collection timer is set for 120 seconds. */
- RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect,
- ripng->garbage_time);
-
- /* Delete this route from the kernel. */
- ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
- rinfo->ifindex);
- /* - The metric for the route is set to 16 (infinity). This causes
- the route to be removed from service. */
- rinfo->metric = RIPNG_METRIC_INFINITY;
- rinfo->flags &= ~RIPNG_RTF_FIB;
-
- /* Aggregate count decrement. */
- ripng_aggregate_decrement (rp, rinfo);
-
- /* - The route change flag is to indicate that this entry has been
- changed. */
- rinfo->flags |= RIPNG_RTF_CHANGED;
-
- /* - The output process is signalled to trigger a response. */
- ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
-
+ ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t));
return 0;
}
@@ -628,11 +751,12 @@
int ret;
struct prefix_ipv6 p;
struct route_node *rp;
- struct ripng_info *rinfo;
+ struct ripng_info *rinfo = NULL, newinfo;
struct ripng_interface *ri;
struct in6_addr *nexthop;
- u_char oldmetric;
int same = 0;
+ struct list *list = NULL;
+ struct listnode *node = NULL;
/* Make prefix structure. */
memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -653,24 +777,23 @@
if (ret < 0)
return;
+ memset (&newinfo, 0, sizeof (newinfo));
+ newinfo.type = ZEBRA_ROUTE_RIPNG;
+ newinfo.sub_type = RIPNG_ROUTE_RTE;
+ if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
+ newinfo.nexthop = ripng_nexthop->address;
+ else
+ newinfo.nexthop = from->sin6_addr;
+ newinfo.from = from->sin6_addr;
+ newinfo.ifindex = ifp->ifindex;
+ newinfo.metric = rte->metric;
+ newinfo.metric_out = rte->metric; /* XXX */
+ newinfo.tag = ntohs (rte->tag); /* XXX */
+
/* Modify entry. */
if (ri->routemap[RIPNG_FILTER_IN])
{
int ret;
- struct ripng_info newinfo;
-
- memset (&newinfo, 0, sizeof (struct ripng_info));
- newinfo.type = ZEBRA_ROUTE_RIPNG;
- newinfo.sub_type = RIPNG_ROUTE_RTE;
- if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
- newinfo.nexthop = ripng_nexthop->address;
- else
- newinfo.nexthop = from->sin6_addr;
- newinfo.from = from->sin6_addr;
- newinfo.ifindex = ifp->ifindex;
- newinfo.metric = rte->metric;
- newinfo.metric_out = rte->metric; /* XXX */
- newinfo.tag = ntohs(rte->tag); /* XXX */
ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
(struct prefix *)&p, RMAP_RIPNG, &newinfo);
@@ -731,24 +854,66 @@
/* Lookup RIPng routing table. */
rp = route_node_get (ripng->table, (struct prefix *) &p);
- /* Sanity check */
- rinfo = rp->info;
+ newinfo.rp = rp;
+ newinfo.nexthop = *nexthop;
+ newinfo.metric = rte->metric;
+ newinfo.tag = ntohs (rte->tag);
+
+ /* Check to see whether there is already RIPng route on the table. */
+ if ((list = rp->info) != NULL)
+ for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
+ {
+ /* Need to compare with redistributed entry or local entry */
+ if (!ripng_route_rte (rinfo))
+ break;
+
+ if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
+ IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
+ break;
+
+ if (!listnextnode (node))
+ {
+ /* Not found in the list */
+
+ if (rte->metric > rinfo->metric)
+ {
+ /* New route has a greater metric. Discard it. */
+ route_unlock_node (rp);
+ return;
+ }
+
+ if (rte->metric < rinfo->metric)
+ /* New route has a smaller metric. Replace the ECMP list
+ * with the new one in below. */
+ break;
+
+ /* Metrics are same. Keep "rinfo" null and the new route
+ * is added in the ECMP list in below. */
+ }
+ }
+
if (rinfo)
{
/* Redistributed route check. */
if (rinfo->type != ZEBRA_ROUTE_RIPNG
&& rinfo->metric != RIPNG_METRIC_INFINITY)
- return;
+ {
+ route_unlock_node (rp);
+ return;
+ }
/* Local static route. */
if (rinfo->type == ZEBRA_ROUTE_RIPNG
&& ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
(rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
&& rinfo->metric != RIPNG_METRIC_INFINITY)
- return;
+ {
+ route_unlock_node (rp);
+ return;
+ }
}
- if (rp->info == NULL)
+ if (!rinfo)
{
/* Now, check to see whether there is already an explicit route
for the destination prefix. If there is no such route, add
@@ -756,53 +921,10 @@
infinity (there is no point in adding a route which
unusable). */
if (rte->metric != RIPNG_METRIC_INFINITY)
- {
- rinfo = ripng_info_new ();
-
- /* - Setting the destination prefix and length to those in
- the RTE. */
- rp->info = rinfo;
- rinfo->rp = rp;
-
- /* - Setting the metric to the newly calculated metric (as
- described above). */
- rinfo->metric = rte->metric;
- rinfo->tag = ntohs (rte->tag);
-
- /* - Set the next hop address to be the address of the router
- from which the datagram came or the next hop address
- specified by a next hop RTE. */
- IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
- IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
- rinfo->ifindex = ifp->ifindex;
-
- /* - Initialize the timeout for the route. If the
- garbage-collection timer is running for this route, stop it. */
- ripng_timeout_update (rinfo);
-
- /* - Set the route change flag. */
- rinfo->flags |= RIPNG_RTF_CHANGED;
-
- /* - Signal the output process to trigger an update (see section
- 2.5). */
- ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
-
- /* Finally, route goes into the kernel. */
- rinfo->type = ZEBRA_ROUTE_RIPNG;
- rinfo->sub_type = RIPNG_ROUTE_RTE;
-
- ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex,
- rinfo->metric);
- rinfo->flags |= RIPNG_RTF_FIB;
-
- /* Aggregate check. */
- ripng_aggregate_increment (rp, rinfo);
- }
+ ripng_ecmp_add (&newinfo);
}
else
{
- rinfo = rp->info;
-
/* If there is an existing route, compare the next hop address
to the address of the router from which the datagram came.
If this datagram is from the same router as the existing
@@ -810,9 +932,6 @@
same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
&& (rinfo->ifindex == ifp->ifindex));
- if (same)
- ripng_timeout_update (rinfo);
-
/* Next, compare the metrics. If the datagram is from the same
router as the existing route, and the new metric is different
than the old one; or, if the new metric is lower than the old
@@ -820,96 +939,24 @@
if ((same && rinfo->metric != rte->metric) ||
rte->metric < rinfo->metric)
{
- /* - Adopt the route from the datagram. That is, put the
- new metric in, and adjust the next hop address (if
- necessary). */
- oldmetric = rinfo->metric;
- rinfo->metric = rte->metric;
- rinfo->tag = ntohs (rte->tag);
- IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
- rinfo->ifindex = ifp->ifindex;
-
- /* Should a new route to this network be established
- while the garbage-collection timer is running, the
- new route will replace the one that is about to be
- deleted. In this case the garbage-collection timer
- must be cleared. */
-
- if (oldmetric == RIPNG_METRIC_INFINITY &&
- rinfo->metric < RIPNG_METRIC_INFINITY)
- {
- rinfo->type = ZEBRA_ROUTE_RIPNG;
- rinfo->sub_type = RIPNG_ROUTE_RTE;
-
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
-
- if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
- IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
-
- ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
- rinfo->flags |= RIPNG_RTF_FIB;
-
- /* The aggregation counter needs to be updated because
- the prefixes, which are into the gc, have been
- removed from the aggregator (see ripng_timout). */
- ripng_aggregate_increment (rp, rinfo);
- }
-
- /* Update nexthop and/or metric value. */
- if (oldmetric != RIPNG_METRIC_INFINITY)
- {
- ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
- ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
- rinfo->flags |= RIPNG_RTF_FIB;
-
- if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
- IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
- }
-
- /* - Set the route change flag and signal the output process
- to trigger an update. */
- rinfo->flags |= RIPNG_RTF_CHANGED;
- ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
-
- /* - If the new metric is infinity, start the deletion
- process (described above); */
- if (rinfo->metric == RIPNG_METRIC_INFINITY)
- {
- /* If the new metric is infinity, the deletion process
- begins for the route, which is no longer used for
- routing packets. Note that the deletion process is
- started only when the metric is first set to
- infinity. If the metric was already infinity, then a
- new deletion process is not started. */
- if (oldmetric != RIPNG_METRIC_INFINITY)
- {
- /* - The garbage-collection timer is set for 120 seconds. */
- RIPNG_TIMER_ON (rinfo->t_garbage_collect,
- ripng_garbage_collect, ripng->garbage_time);
- RIPNG_TIMER_OFF (rinfo->t_timeout);
-
- /* - The metric for the route is set to 16
- (infinity). This causes the route to be removed
- from service.*/
- ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
- rinfo->flags &= ~RIPNG_RTF_FIB;
-
- /* Aggregate count decrement. */
- ripng_aggregate_decrement (rp, rinfo);
-
- /* - The route change flag is to indicate that this
- entry has been changed. */
- /* - The output process is signalled to trigger a
- response. */
- ; /* Above processes are already done previously. */
- }
- }
- else
- {
- /* otherwise, re-initialize the timeout. */
- ripng_timeout_update (rinfo);
- }
+ if (listcount (list) == 1)
+ {
+ if (newinfo.metric != RIPNG_METRIC_INFINITY)
+ ripng_ecmp_replace (&newinfo);
+ else
+ ripng_ecmp_delete (rinfo);
+ }
+ else
+ {
+ if (newinfo.metric < rinfo->metric)
+ ripng_ecmp_replace (&newinfo);
+ else /* newinfo.metric > rinfo->metric */
+ ripng_ecmp_delete (rinfo);
+ }
}
+ else /* same & no change */
+ ripng_timeout_update (rinfo);
+
/* Unlock tempolary lock of the route. */
route_unlock_node (rp);
}
@@ -921,7 +968,8 @@
unsigned int ifindex, struct in6_addr *nexthop)
{
struct route_node *rp;
- struct ripng_info *rinfo;
+ struct ripng_info *rinfo = NULL, newinfo;
+ struct list *list = NULL;
/* Redistribute route */
if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
@@ -930,10 +978,20 @@
return;
rp = route_node_get (ripng->table, (struct prefix *) p);
- rinfo = rp->info;
- if (rinfo)
+ memset (&newinfo, 0, sizeof (struct ripng_info));
+ newinfo.type = type;
+ newinfo.sub_type = sub_type;
+ newinfo.ifindex = ifindex;
+ newinfo.metric = 1;
+ newinfo.rp = rp;
+ if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
+ newinfo.nexthop = *nexthop;
+
+ if ((list = rp->info) != NULL && listcount (list) != 0)
{
+ rinfo = listgetdata (listhead (list));
+
if (rinfo->type == ZEBRA_ROUTE_CONNECT
&& rinfo->sub_type == RIPNG_ROUTE_INTERFACE
&& rinfo->metric != RIPNG_METRIC_INFINITY) {
@@ -953,42 +1011,12 @@
return;
}
}
-
- RIPNG_TIMER_OFF (rinfo->t_timeout);
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
- /* Tells the other daemons about the deletion of
- * this RIPng route
- **/
- if (ripng_route_rte (rinfo))
- ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
- rinfo->metric);
-
- rp->info = NULL;
- ripng_info_free (rinfo);
-
+ rinfo = ripng_ecmp_replace (&newinfo);
route_unlock_node (rp);
-
}
-
- rinfo = ripng_info_new ();
-
- rinfo->type = type;
- rinfo->sub_type = sub_type;
- rinfo->ifindex = ifindex;
- rinfo->metric = 1;
- rinfo->rp = rp;
-
- if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
- rinfo->nexthop = *nexthop;
-
- rinfo->flags |= RIPNG_RTF_FIB;
- rp->info = rinfo;
-
- /* Aggregate check. */
- ripng_aggregate_increment (rp, rinfo);
-
- rinfo->flags |= RIPNG_RTF_CHANGED;
+ else
+ rinfo = ripng_ecmp_add (&newinfo);
if (IS_RIPNG_DEBUG_EVENT) {
if (!nexthop)
@@ -1021,31 +1049,37 @@
if (rp)
{
- rinfo = rp->info;
+ struct list *list = rp->info;
- if (rinfo != NULL
- && rinfo->type == type
- && rinfo->sub_type == sub_type
- && rinfo->ifindex == ifindex)
- {
- /* Perform poisoned reverse. */
- rinfo->metric = RIPNG_METRIC_INFINITY;
- RIPNG_TIMER_ON (rinfo->t_garbage_collect,
- ripng_garbage_collect, ripng->garbage_time);
- RIPNG_TIMER_OFF (rinfo->t_timeout);
+ if (list != NULL && listcount (list) != 0)
+ {
+ rinfo = listgetdata (listhead (list));
+ if (rinfo != NULL
+ && rinfo->type == type
+ && rinfo->sub_type == sub_type
+ && rinfo->ifindex == ifindex)
+ {
+ /* Perform poisoned reverse. */
+ rinfo->metric = RIPNG_METRIC_INFINITY;
+ RIPNG_TIMER_ON (rinfo->t_garbage_collect,
+ ripng_garbage_collect, ripng->garbage_time);
+ RIPNG_TIMER_OFF (rinfo->t_timeout);
- /* Aggregate count decrement. */
- ripng_aggregate_decrement (rp, rinfo);
+ /* Aggregate count decrement. */
+ ripng_aggregate_decrement (rp, rinfo);
- rinfo->flags |= RIPNG_RTF_CHANGED;
-
- if (IS_RIPNG_DEBUG_EVENT)
- zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
- inet6_ntoa(p->prefix), p->prefixlen,
- ifindex2ifname(ifindex));
+ rinfo->flags |= RIPNG_RTF_CHANGED;
- ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
- }
+ if (IS_RIPNG_DEBUG_EVENT)
+ zlog_debug ("Poisone %s/%d on the interface %s with an "
+ "infinity metric [delete]",
+ inet6_ntoa (p->prefix), p->prefixlen,
+ ifindex2ifname (ifindex));
+
+ ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+ }
+ }
+ route_unlock_node (rp);
}
}
@@ -1054,14 +1088,16 @@
ripng_redistribute_withdraw (int type)
{
struct route_node *rp;
- struct ripng_info *rinfo;
+ struct ripng_info *rinfo = NULL;
+ struct list *list = NULL;
if (!ripng)
return;
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
- if ((rinfo = rp->info) != NULL)
+ if ((list = rp->info) != NULL)
{
+ rinfo = listgetdata (listhead (list));
if ((rinfo->type == type)
&& (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
{
@@ -1296,7 +1332,7 @@
if (rp)
{
- rinfo = rp->info;
+ rinfo = listgetdata (listhead ((struct list *)rp->info));
rte->metric = rinfo->metric;
route_unlock_node (rp);
}
@@ -1404,12 +1440,18 @@
ripng_clear_changed_flag (void)
{
struct route_node *rp;
- struct ripng_info *rinfo;
+ struct ripng_info *rinfo = NULL;
+ struct list *list = NULL;
+ struct listnode *listnode = NULL;
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
- if ((rinfo = rp->info) != NULL)
- if (rinfo->flags & RIPNG_RTF_CHANGED)
- rinfo->flags &= ~RIPNG_RTF_CHANGED;
+ if ((list = rp->info) != NULL)
+ for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
+ {
+ UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
+ /* This flag can be set only on the first entry. */
+ break;
+ }
}
/* Regular update of RIPng route. Send all routing formation to RIPng
@@ -1587,6 +1629,8 @@
struct ripng_aggregate *aggregate;
struct prefix_ipv6 *p;
struct list * ripng_rte_list;
+ struct list *list = NULL;
+ struct listnode *listnode = NULL;
if (IS_RIPNG_DEBUG_EVENT) {
if (to)
@@ -1603,7 +1647,9 @@
for (rp = route_top (ripng->table); rp; rp = route_next (rp))
{
- if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
+ if ((list = rp->info) != NULL &&
+ (rinfo = listgetdata (listhead (list))) != NULL &&
+ rinfo->suppress == 0)
{
/* If no route-map are applied, the RTE will be these following
* informations.
@@ -1635,8 +1681,17 @@
if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
{
/* We perform split horizon for RIPng routes. */
- if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
- rinfo->ifindex == ifp->ifindex)
+ int suppress = 0;
+ struct ripng_info *tmp_rinfo = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
+ if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
+ tmp_rinfo->ifindex == ifp->ifindex)
+ {
+ suppress = 1;
+ break;
+ }
+ if (suppress)
continue;
}
@@ -1715,9 +1770,12 @@
* for RIPng routes.
**/
if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
- if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
- rinfo->ifindex == ifp->ifindex)
- rinfo->metric_out = RIPNG_METRIC_INFINITY;
+ struct ripng_info *tmp_rinfo = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
+ if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
+ tmp_rinfo->ifindex == ifp->ifindex)
+ rinfo->metric_out = RIPNG_METRIC_INFINITY;
}
/* Add RTE to the list */
@@ -1983,6 +2041,8 @@
struct ripng_info *rinfo;
struct ripng_aggregate *aggregate;
struct prefix_ipv6 *p;
+ struct list *list = NULL;
+ struct listnode *listnode = NULL;
int len;
if (! ripng)
@@ -2020,7 +2080,8 @@
VTY_NEWLINE);
}
- if ((rinfo = rp->info) != NULL)
+ if ((list = rp->info) != NULL)
+ for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
{
p = (struct prefix_ipv6 *) &rp->p;
@@ -2757,24 +2818,37 @@
int i;
struct route_node *rp;
struct ripng_info *rinfo;
+ struct ripng_aggregate *aggregate;
+ struct list *list = NULL;
+ struct listnode *listnode = NULL;
if (ripng) {
/* Clear RIPng routes */
- for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
- if ((rinfo = rp->info) != NULL) {
- if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
- (rinfo->sub_type == RIPNG_ROUTE_RTE))
- ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
- &rinfo->nexthop, rinfo->metric);
+ for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+ {
+ if ((list = rp->info) != NULL)
+ {
+ rinfo = listgetdata (listhead (list));
+ if (ripng_route_rte (rinfo))
+ ripng_zebra_ipv6_delete (rp);
- RIPNG_TIMER_OFF (rinfo->t_timeout);
- RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+ for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
+ {
+ RIPNG_TIMER_OFF (rinfo->t_timeout);
+ RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+ ripng_info_free (rinfo);
+ }
+ list_delete (list);
+ rp->info = NULL;
+ route_unlock_node (rp);
+ }
- rp->info = NULL;
- route_unlock_node (rp);
-
- ripng_info_free(rinfo);
- }
+ if ((aggregate = rp->aggregate) != NULL)
+ {
+ ripng_aggregate_free (aggregate);
+ rp->aggregate = NULL;
+ route_unlock_node (rp);
+ }
}
/* Cancel the RIPng timers */