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>
(cherry picked from commit 72855b16b72e9ad2c7eb0c0bfd8f5985f779608f)
This commit is contained in:
Feng Lu 2015-05-22 11:39:54 +02:00 committed by Donald Sharp
parent c880b6367e
commit fac76f9cf7
3 changed files with 103 additions and 5 deletions

View File

@ -96,10 +96,18 @@ ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd)
(struct prefix_ipv6 *)&rp->p, &api); (struct prefix_ipv6 *)&rp->p, &api);
if (IS_RIPNG_DEBUG_ZEBRA) if (IS_RIPNG_DEBUG_ZEBRA)
zlog_debug ("%s: %s/%d nexthops %d", {
(cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ if (ripng->ecmp)
"Install into zebra" : "Delete from zebra", zlog_debug ("%s: %s/%d nexthops %d",
inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count); (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);
}
} }
} }

View File

@ -440,7 +440,8 @@ ripng_garbage_collect (struct thread *t)
static void ripng_timeout_update (struct ripng_info *rinfo); static void ripng_timeout_update (struct ripng_info *rinfo);
/* Add new route to the ECMP list. /* 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 * struct ripng_info *
ripng_ecmp_add (struct ripng_info *rinfo_new) ripng_ecmp_add (struct ripng_info *rinfo_new)
@ -453,6 +454,11 @@ ripng_ecmp_add (struct ripng_info *rinfo_new)
rp->info = list_new (); rp->info = list_new ();
list = (struct list *)rp->info; 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 (); rinfo = ripng_info_new ();
memcpy (rinfo, rinfo_new, sizeof (struct ripng_info)); memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
listnode_add (list, rinfo); listnode_add (list, rinfo);
@ -2638,6 +2644,80 @@ DEFUN (no_ripng_default_information_originate,
return CMD_SUCCESS; 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. */ /* RIPng configuration write function. */
static int static int
ripng_config_write (struct vty *vty) ripng_config_write (struct vty *vty)
@ -2677,6 +2757,10 @@ ripng_config_write (struct vty *vty)
VTY_NEWLINE); VTY_NEWLINE);
/* ECMP configuration. */
if (ripng->ecmp)
vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
/* RIPng static routes. */ /* RIPng static routes. */
for (rp = route_top (ripng->route); rp; rp = route_next (rp)) for (rp = route_top (ripng->route); rp; rp = route_next (rp))
if (rp->info != NULL) if (rp->info != NULL)
@ -3042,6 +3126,9 @@ ripng_init ()
install_element (RIPNG_NODE, &ripng_default_information_originate_cmd); install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
install_element (RIPNG_NODE, &no_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_if_init ();
ripng_debug_init (); ripng_debug_init ();

View File

@ -129,6 +129,9 @@ struct ripng
struct thread *t_triggered_update; struct thread *t_triggered_update;
struct thread *t_triggered_interval; struct thread *t_triggered_interval;
/* RIPng ECMP flag */
unsigned int ecmp;
/* For redistribute route map. */ /* For redistribute route map. */
struct struct
{ {