From 72855b16b72e9ad2c7eb0c0bfd8f5985f779608f Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:54 +0200 Subject: 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 Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent Jardin Signed-off-by: David Lamparter --- ripngd/ripng_zebra.c | 16 +++++++--- ripngd/ripngd.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++- ripngd/ripngd.h | 3 ++ 3 files changed, 103 insertions(+), 5 deletions(-) (limited to 'ripngd') 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 { -- cgit v1.2.3