diff options
author | Lu Feng <lu.feng@6wind.com> | 2014-07-18 08:13:19 +0200 |
---|---|---|
committer | Daniel Walton <dwalton@cumulusnetworks.com> | 2016-05-26 19:12:05 +0200 |
commit | 8478ae7ef3f4ace7470f3bf47780c3d2f7727848 (patch) | |
tree | b1f9868ddf1cbd060494166805bbb1e162607ee8 | |
parent | ripd: add ECMP support (diff) | |
download | frr-8478ae7ef3f4ace7470f3bf47780c3d2f7727848.tar.xz frr-8478ae7ef3f4ace7470f3bf47780c3d2f7727848.zip |
ripd: allow to enable/disable the ECMP feature
Introduce a new command "[no] allow-ecmp" to enable/disable the
ECMP feature in RIP. By default, ECMP is not allowed.
Once ECMP is disabled, only one route entry can exist in the list.
* rip_zebra.c: adjust a debugging information, which shows the number
of nexthops according to whether ECMP is enabled.
* ripd.c: rip_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, rip_ecmp_disable() is called to
remove the multiple nexthops.
* ripd.h: Add a new member "ecmp" to "struct rip", 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: David Lamparter <equinox@opensourcerouting.org>
(cherry picked from commit 0b74a0a5db7bcf65bf68c44b547b02b1310b5cdb)
-rw-r--r-- | ripd/rip_zebra.c | 16 | ||||
-rw-r--r-- | ripd/ripd.c | 88 | ||||
-rw-r--r-- | ripd/ripd.h | 3 |
3 files changed, 102 insertions, 5 deletions
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 09a151093..6ca27d01d 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -95,10 +95,18 @@ rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) (struct prefix_ipv4 *)&rp->p, &api); if (IS_RIP_DEBUG_ZEBRA) - zlog_debug ("%s: %s/%d nexthops %d", - (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ - "Install into zebra" : "Delete from zebra", - inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); + { + if (rip->ecmp) + zlog_debug ("%s: %s/%d nexthops %d", + (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); + else + zlog_debug ("%s: %s/%d", + (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); + } rip_global_route_changes++; } diff --git a/ripd/ripd.c b/ripd/ripd.c index 02933924f..fc3ad3adb 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -156,7 +156,8 @@ rip_garbage_collect (struct thread *t) static void rip_timeout_update (struct rip_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 rip_info * rip_ecmp_add (struct rip_info *rinfo_new) @@ -169,6 +170,11 @@ rip_ecmp_add (struct rip_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) && !rip->ecmp) + return NULL; + rinfo = rip_info_new (); memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); listnode_add (list, rinfo); @@ -3443,6 +3449,80 @@ DEFUN (no_rip_distance_source_access_list, return CMD_SUCCESS; } +/* Update ECMP routes to zebra when ECMP is disabled. */ +static void +rip_ecmp_disable (void) +{ + struct route_node *rp; + struct rip_info *rinfo, *tmp_rinfo; + struct list *list; + struct listnode *node, *nextnode; + + if (!rip) + return; + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((list = rp->info) != NULL && listcount (list) > 1) + { + rinfo = listgetdata (listhead (list)); + if (!rip_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) + { + RIP_TIMER_OFF (tmp_rinfo->t_timeout); + RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); + list_delete_node (list, node); + rip_info_free (tmp_rinfo); + } + + /* Update zebra. */ + rip_zebra_ipv4_add (rp); + + /* Set the route change flag. */ + SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + } +} + +DEFUN (rip_allow_ecmp, + rip_allow_ecmp_cmd, + "allow-ecmp", + "Allow Equal Cost MultiPath\n") +{ + if (rip->ecmp) + { + vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip->ecmp = 1; + zlog_info ("ECMP is enabled."); + return CMD_SUCCESS; +} + +DEFUN (no_rip_allow_ecmp, + no_rip_allow_ecmp_cmd, + "no allow-ecmp", + NO_STR + "Allow Equal Cost MultiPath\n") +{ + if (!rip->ecmp) + { + vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip->ecmp = 0; + zlog_info ("ECMP is disabled."); + rip_ecmp_disable (); + return CMD_SUCCESS; +} + /* Print out routes update time. */ static void rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) @@ -3750,6 +3830,10 @@ config_write_rip (struct vty *vty) rdistance->access_list ? rdistance->access_list : "", VTY_NEWLINE); + /* ECMP configuration. */ + if (rip->ecmp) + vty_out (vty, " allow-ecmp%s", VTY_NEWLINE); + /* RIP static route configuration. */ for (rn = route_top (rip->route); rn; rn = route_next (rn)) if (rn->info) @@ -4087,6 +4171,8 @@ rip_init (void) install_element (RIP_NODE, &no_rip_distance_source_cmd); install_element (RIP_NODE, &rip_distance_source_access_list_cmd); install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); + install_element (RIP_NODE, &rip_allow_ecmp_cmd); + install_element (RIP_NODE, &no_rip_allow_ecmp_cmd); /* Debug related init. */ rip_debug_init (); diff --git a/ripd/ripd.h b/ripd/ripd.h index 3401f258f..fe9e521d8 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -143,6 +143,9 @@ struct rip u_char distance; struct route_table *distance_table; + /* RIP ECMP flag */ + unsigned int ecmp; + /* For redistribute route map. */ struct { |