summaryrefslogtreecommitdiffstats
path: root/ripngd
diff options
context:
space:
mode:
authorFeng Lu <lu.feng@6wind.com>2015-05-22 11:39:54 +0200
committerDavid Lamparter <equinox@opensourcerouting.org>2015-05-27 21:52:25 +0200
commit72855b16b72e9ad2c7eb0c0bfd8f5985f779608f (patch)
tree308f4e057157ded800b1c3e188a5eadf77e693cb /ripngd
parente97c31aafc013b8b9a0e61cb79ee97a5f1e419bf (diff)
downloadquagga-72855b16b72e9ad2c7eb0c0bfd8f5985f779608f.tar.bz2
quagga-72855b16b72e9ad2c7eb0c0bfd8f5985f779608f.tar.xz
ripngd: allow to enable/disable the ECMP feature
Introduce a new command "[no] allow-ecmp" to enable/disable the ECMP feature in RIPng. By default, ECMP is not allowed. Once ECMP is disabled, only one route entry can exist in the list. * ripng_zebra.c: adjust a debugging information, which shows the number of nexthops according to whether ECMP is enabled. * ripngd.c: ripng_ecmp_add() will reject the new route if ECMP is not allowed and some entry already exists. A new configurable command "allow-ecmp" is added to control whether ECMP is allowed. When ECMP is disabled, ripng_ecmp_disable() is called to remove the multiple nexthops. * ripngd.h: Add a new member "ecmp" to "struct ripng", indicating whether ECMP is allowed or not. 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>
Diffstat (limited to 'ripngd')
-rw-r--r--ripngd/ripng_zebra.c16
-rw-r--r--ripngd/ripngd.c89
-rw-r--r--ripngd/ripngd.h3
3 files changed, 103 insertions, 5 deletions
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index b5cf445d..5d383fa2 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -102,10 +102,18 @@ ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd)
(struct prefix_ipv6 *)&rp->p, &api);
if (IS_RIPNG_DEBUG_ZEBRA)
- zlog_debug ("%s: %s/%d nexthops %d",
- (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \
- "Install into zebra" : "Delete from zebra",
- inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count);
+ {
+ if (ripng->ecmp)
+ zlog_debug ("%s: %s/%d nexthops %d",
+ (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \
+ "Install into zebra" : "Delete from zebra",
+ inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count);
+ else
+ zlog_debug ("%s: %s/%d",
+ (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \
+ "Install into zebra" : "Delete from zebra",
+ inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen);
+ }
}
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 21e45b6e..4a7f52fb 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -438,7 +438,8 @@ ripng_garbage_collect (struct thread *t)
static void ripng_timeout_update (struct ripng_info *rinfo);
/* Add new route to the ECMP list.
- * RETURN: the new entry added in the list
+ * RETURN: the new entry added in the list, or NULL if it is not the first
+ * entry and ECMP is not allowed.
*/
struct ripng_info *
ripng_ecmp_add (struct ripng_info *rinfo_new)
@@ -451,6 +452,11 @@ ripng_ecmp_add (struct ripng_info *rinfo_new)
rp->info = list_new ();
list = (struct list *)rp->info;
+ /* If ECMP is not allowed and some entry already exists in the list,
+ * do nothing. */
+ if (listcount (list) && !ripng->ecmp)
+ return NULL;
+
rinfo = ripng_info_new ();
memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
listnode_add (list, rinfo);
@@ -2636,6 +2642,80 @@ DEFUN (no_ripng_default_information_originate,
return CMD_SUCCESS;
}
+/* Update ECMP routes to zebra when ECMP is disabled. */
+static void
+ripng_ecmp_disable (void)
+{
+ struct route_node *rp;
+ struct ripng_info *rinfo, *tmp_rinfo;
+ struct list *list;
+ struct listnode *node, *nextnode;
+
+ if (!ripng)
+ return;
+
+ for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+ if ((list = rp->info) != NULL && listcount (list) > 1)
+ {
+ rinfo = listgetdata (listhead (list));
+ if (!ripng_route_rte (rinfo))
+ continue;
+
+ /* Drop all other entries, except the first one. */
+ 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);
+ }
+
+ /* Update zebra. */
+ ripng_zebra_ipv6_add (rp);
+
+ /* 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);
+ }
+}
+
+DEFUN (ripng_allow_ecmp,
+ ripng_allow_ecmp_cmd,
+ "allow-ecmp",
+ "Allow Equal Cost MultiPath\n")
+{
+ if (ripng->ecmp)
+ {
+ vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ripng->ecmp = 1;
+ zlog_info ("ECMP is enabled.");
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_allow_ecmp,
+ no_ripng_allow_ecmp_cmd,
+ "no allow-ecmp",
+ NO_STR
+ "Allow Equal Cost MultiPath\n")
+{
+ if (!ripng->ecmp)
+ {
+ vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ripng->ecmp = 0;
+ zlog_info ("ECMP is disabled.");
+ ripng_ecmp_disable ();
+ return CMD_SUCCESS;
+}
+
/* RIPng configuration write function. */
static int
ripng_config_write (struct vty *vty)
@@ -2675,6 +2755,10 @@ ripng_config_write (struct vty *vty)
VTY_NEWLINE);
+ /* ECMP configuration. */
+ if (ripng->ecmp)
+ vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
+
/* RIPng static routes. */
for (rp = route_top (ripng->route); rp; rp = route_next (rp))
if (rp->info != NULL)
@@ -3040,6 +3124,9 @@ ripng_init ()
install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
+ install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd);
+ install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
+
ripng_if_init ();
ripng_debug_init ();
diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h
index 75c5dfa0..706ff542 100644
--- a/ripngd/ripngd.h
+++ b/ripngd/ripngd.h
@@ -129,6 +129,9 @@ struct ripng
struct thread *t_triggered_update;
struct thread *t_triggered_interval;
+ /* RIPng ECMP flag */
+ unsigned int ecmp;
+
/* For redistribute route map. */
struct
{