mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 21:10:28 +00:00
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:
parent
c880b6367e
commit
fac76f9cf7
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 ();
|
||||||
|
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user