diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index fc0229ba10..85b6007f36 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -299,6 +299,16 @@ To start OSPF process you have to specify the OSPF router. command can be used when the neighbor state get stuck at some state and this can be used to recover it from that state. +.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) +.. clicmd:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) + +.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) +.. clicmd:: no maximum-paths + + CLI to control maximum number of equal cost paths to reach a specific + destination.(ECMP) + Reset CLI, resets the maximum supported multi path to the default value. + .. _ospf-area: Areas diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 1e0814764b..95553dacdf 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1987,3 +1987,27 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason) thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf, delay, &ospf->t_spf_calc); } + +/* Restart OSPF SPF algorithm*/ +void ospf_restart_spf(struct ospf *ospf) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Restart SPF.", __PRETTY_FUNCTION__); + + /* Handling inter area and intra area routes*/ + if (ospf->new_table) { + ospf_route_delete(ospf, ospf->new_table); + ospf_route_table_free(ospf->new_table); + ospf->new_table = route_table_init(); + } + + /* Handling of TYPE-5 lsa(external routes) */ + if (ospf->old_external_route) { + ospf_route_delete(ospf, ospf->old_external_route); + ospf_route_table_free(ospf->old_external_route); + ospf->old_external_route = route_table_init(); + } + + /* Trigger SPF */ + ospf_spf_calculate_schedule(ospf, SPF_FLAG_CONFIG_CHANGE); +} diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h index 835caab288..4ff4a6d125 100644 --- a/ospfd/ospf_spf.h +++ b/ospfd/ospf_spf.h @@ -98,6 +98,6 @@ extern struct vertex_parent *ospf_spf_vertex_parent_find(struct in_addr id, extern int vertex_parent_cmp(void *aa, void *bb); extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i); - +extern void ospf_restart_spf(struct ospf *ospf); /* void ospf_spf_calculate_timer_add (); */ #endif /* _QUAGGA_OSPF_SPF_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 134d8b6d1d..d7e8665489 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2699,6 +2699,50 @@ DEFUN(no_ospf_ti_lfa, no_ospf_ti_lfa_cmd, return CMD_SUCCESS; } +static void ospf_maxpath_set(struct vty *vty, struct ospf *ospf, uint16_t paths) +{ + if (ospf->max_multipath == paths) + return; + + ospf->max_multipath = paths; + + /* Send deletion notification to zebra to delete all + * ospf specific routes and reinitiat SPF to reflect + * the new max multipath. + */ + ospf_restart_spf(ospf); +} + +/* Ospf Maximum multiple paths config support */ +DEFUN (ospf_max_multipath, + ospf_max_multipath_cmd, + "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), + "Max no of multiple paths for ECMP support\n" + "Number of paths\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + int idx_number = 1; + uint16_t maxpaths; + + maxpaths = strtol(argv[idx_number]->arg, NULL, 10); + + ospf_maxpath_set(vty, ospf, maxpaths); + return CMD_SUCCESS; +} + +DEFUN (no_ospf_max_multipath, + no_ospf_max_multipath_cmd, + "no maximum-paths", + NO_STR + "Max no of multiple paths for ECMP support\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + uint16_t maxpaths = MULTIPATH_NUM; + + ospf_maxpath_set(vty, ospf, maxpaths); + return CMD_SUCCESS; +} + static const char *const ospf_abr_type_descr_str[] = { "Unknown", "Standard (RFC2328)", "Alternative IBM", "Alternative Cisco", "Alternative Shortcut" @@ -3228,6 +3272,10 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, /* Show refresh parameters. */ vty_out(vty, " Refresh timer %d secs\n", ospf->lsa_refresh_interval); + + /* show max multipath */ + vty_out(vty, " Maximum multiple paths(ECMP) supported %d\n", + ospf->max_multipath); } /* Show ABR/ASBR flags. */ @@ -12274,6 +12322,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf) vty_out(vty, " ospf write-multiplier %d\n", ospf->write_oi_count); + if (ospf->max_multipath != MULTIPATH_NUM) + vty_out(vty, " maximum-paths %d\n", ospf->max_multipath); + /* Max-metric router-lsa print */ config_write_stub_router(vty, ospf); @@ -12802,6 +12853,10 @@ void ospf_vty_init(void) install_element(OSPF_NODE, &ospf_ti_lfa_cmd); install_element(OSPF_NODE, &no_ospf_ti_lfa_cmd); + /* Max path configurations */ + install_element(OSPF_NODE, &ospf_max_multipath_cmd); + install_element(OSPF_NODE, &no_ospf_max_multipath_cmd); + /* Init interface related vty commands. */ ospf_vty_if_init(); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 15a95162d3..a2ce4d1ce7 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -297,7 +297,7 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, } for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) { - if (api.nexthop_num >= MULTIPATH_NUM) + if (api.nexthop_num >= ospf->max_multipath) break; ospf_zebra_add_nexthop(ospf, path, &api); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index b1b8324074..259209a736 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -367,6 +367,9 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name) new->maxage_lsa = route_table_init(); new->t_maxage_walker = NULL; + /* Max paths initialization */ + new->max_multipath = MULTIPATH_NUM; + /* Distance table init. */ new->distance_table = route_table_init(); @@ -887,6 +890,7 @@ static void ospf_finish_final(struct ospf *ospf) close(ospf->fd); stream_free(ospf->ibuf); ospf->fd = -1; + ospf->max_multipath = MULTIPATH_NUM; ospf_delete(ospf); if (ospf->name) { diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 45e011fece..7463e069ad 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -374,6 +374,11 @@ struct ospf { */ int aggr_action; + /* Max number of multiple paths + * to support ECMP. + */ + uint16_t max_multipath; + /* MPLS LDP-IGP Sync */ struct ldp_sync_info_cmd ldp_sync_cmd;