From 88d6cf37f66c3b7d1abdaa20875418192d5219b8 Mon Sep 17 00:00:00 2001 From: paul Date: Sat, 29 Oct 2005 12:50:09 +0000 Subject: 2005-10-29 Paul Jakma * (general) RFC3137 stub-router support * ospfd.h: Add OSPF_OUTPUT_COST_INFINITE define. (struct ospf_master) Add a OSPF_MASTER_SHUTDOWN flag for options, to allow shutdown to distinguish between complete shutdown and shutdown of a subset of ospf instances. (struct ospf) Add stub_router_{startup,shutdown_}time, configuration of startup and shutdown time for stub-router. Add t_graceful_shutdown struct thread, timer for graceful shutdown, if needed. (struct ospf_area) Add stub_router_state - run time state of stub-router for an area. Add flags for ADMIN, IS and WAS states. Add t_stub_router, timer thread to resend router-lsa for an area. * ospf_lsa.c: (ospf_link_cost) new simple function to spit out either the given lnks cost or infinite cost if stub-router is in effect. (lsa_link_{ptop,broadcast,virtuallink,ptomp}_set) use previous function for transit-links. (ospf_stub_router_timer) timer thread for end of startup stub router. Change state as required for the area and setup re-origination of router-lsa. (ospf_stub_router_check) Check/do whether stub-router should be enabled, and whether it requires timer to be setup. (ospf_router_lsa_new) call previous function at top. (ospf_router_lsa_originate) no external callers, made static. * ospf_lsa.h: (ospf_router_lsa_originate) removed. * ospf_main.c: (sigint) make static. remove call to exit, as ospf_terminate now deals with exiting. * ospf_route.c: (ospf_terminate) removed, now in ospfd.c. * ospf_vty.c: (show_ip_ospf_area) print out state of stub-router, if active. (show_ip_ospf) print out configuration of stub-router support, and details of graceful-shutdown if the timer is active. ((no)?ospf_max_metric_router_lsa_{admin,startup,shutdown}) new commands to (de-)?configure stub-router support. (config_write_stub_router) write out config of stub-router. (ospf_config_write) call previous. (ospf_vty_init) install the new stub-router commands. * ospfd.c: various functions made static. (ospf_new) Set defaults for stub-router. Graceful shutdown is made to default on, just to be adventerous. (ospf_graceful_shutdown_finish) new function, final part of shutdown. (ospf_graceful_shutdown_timer) timer thread wrapper for graceful-shutdown. (ospf_graceful_shutdown_check) check whether to setup timer for shutdown or proceed directly to final shutdown. (ospf_terminate) moved here from ospf_route.c, call ospf_finish for each instance. (ospf_finish) renamed to ospf_finish_final and made static. (ospf_finish) new function, exported wrapper around ospf_graceful_shutdown_check. (ospf_finish_final) complete shutdown of an instance. Add missing TIMER_OFF's of two timer threads. (ospf_area_free) opaque self lsa timer should be turned off. --- ospfd/ChangeLog | 62 +++++++++++++++ ospfd/ospf_lsa.c | 95 +++++++++++++++++++++-- ospfd/ospf_lsa.h | 1 - ospfd/ospf_main.c | 7 +- ospfd/ospf_route.c | 15 ---- ospfd/ospf_vty.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++-- ospfd/ospfd.c | 140 ++++++++++++++++++++++++++++++--- ospfd/ospfd.h | 29 +++++-- 8 files changed, 522 insertions(+), 50 deletions(-) diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog index 72412d74..fc0d5993 100644 --- a/ospfd/ChangeLog +++ b/ospfd/ChangeLog @@ -1,3 +1,65 @@ +2005-10-29 Paul Jakma + + * (general) RFC3137 stub-router support + * ospfd.h: Add OSPF_OUTPUT_COST_INFINITE define. + (struct ospf_master) Add a OSPF_MASTER_SHUTDOWN flag for + options, to allow shutdown to distinguish between complete + shutdown and shutdown of a subset of ospf instances. + (struct ospf) + Add stub_router_{startup,shutdown_}time, configuration of startup + and shutdown time for stub-router. + Add t_graceful_shutdown struct thread, timer for graceful + shutdown, if needed. + (struct ospf_area) Add stub_router_state - run time state of + stub-router for an area. Add flags for ADMIN, IS and WAS + states. + Add t_stub_router, timer thread to resend router-lsa for an + area. + * ospf_lsa.c: (ospf_link_cost) new simple function to spit out + either the given lnks cost or infinite cost if stub-router is + in effect. + (lsa_link_{ptop,broadcast,virtuallink,ptomp}_set) use + previous function for transit-links. + (ospf_stub_router_timer) timer thread for end of startup stub + router. Change state as required for the area and setup + re-origination of router-lsa. + (ospf_stub_router_check) Check/do whether stub-router should be + enabled, and whether it requires timer to be setup. + (ospf_router_lsa_new) call previous function at top. + (ospf_router_lsa_originate) no external callers, made static. + * ospf_lsa.h: (ospf_router_lsa_originate) removed. + * ospf_main.c: (sigint) make static. + remove call to exit, as ospf_terminate now deals with + exiting. + * ospf_route.c: (ospf_terminate) removed, now in ospfd.c. + * ospf_vty.c: (show_ip_ospf_area) print out state of + stub-router, if active. + (show_ip_ospf) print out configuration of stub-router + support, and details of graceful-shutdown if the timer is + active. + ((no)?ospf_max_metric_router_lsa_{admin,startup,shutdown}) new + commands to (de-)?configure stub-router support. + (config_write_stub_router) write out config of stub-router. + (ospf_config_write) call previous. + (ospf_vty_init) install the new stub-router commands. + * ospfd.c: various functions made static. + (ospf_new) Set defaults for stub-router. Graceful shutdown + is made to default on, just to be adventerous. + (ospf_graceful_shutdown_finish) new function, final part of + shutdown. + (ospf_graceful_shutdown_timer) timer thread wrapper for + graceful-shutdown. + (ospf_graceful_shutdown_check) check whether to setup timer + for shutdown or proceed directly to final shutdown. + (ospf_terminate) moved here from ospf_route.c, call + ospf_finish for each instance. + (ospf_finish) renamed to ospf_finish_final and made static. + (ospf_finish) new function, exported wrapper around + ospf_graceful_shutdown_check. + (ospf_finish_final) complete shutdown of an instance. + Add missing TIMER_OFF's of two timer threads. + (ospf_area_free) opaque self lsa timer should be turned off. + 2005-10-23 Paul Jakma * ospf_apiserver.c: (ospf_apiserver_term) This function should diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index a85667e6..31b9a4f1 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -483,6 +483,19 @@ ospf_nbr_lookup_ptop (struct ospf_interface *oi) return nbr; } +/* Determine cost of link, taking RFC3137 stub-router support into + * consideration + */ +static u_int16_t +ospf_link_cost (struct ospf_interface *oi) +{ + /* RFC3137 stub router support */ + if (!CHECK_FLAG (oi->area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) + return oi->output_cost; + else + return OSPF_OUTPUT_COST_INFINITE; +} + /* Set a link information. */ static void link_info_set (struct stream *s, struct in_addr id, @@ -503,6 +516,7 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) int links = 0; struct ospf_neighbor *nbr; struct in_addr id, mask; + u_int16_t cost = ospf_link_cost (oi); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Set link Point-to-Point"); @@ -513,7 +527,7 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) /* For unnumbered point-to-point networks, the Link Data field should specify the interface's MIB-II ifIndex value. */ link_info_set (s, nbr->router_id, oi->address->u.prefix4, - LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost); + LSA_LINK_TYPE_POINTOPOINT, 0, cost); links++; } @@ -548,7 +562,8 @@ lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) { struct ospf_neighbor *dr; struct in_addr id, mask; - + u_int16_t cost = ospf_link_cost (oi); + /* Describe Type 3 Link. */ if (oi->state == ISM_Waiting) { @@ -565,7 +580,7 @@ lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) ospf_nbr_count (oi, NSM_Full) > 0) { link_info_set (s, DR (oi), oi->address->u.prefix4, - LSA_LINK_TYPE_TRANSIT, 0, oi->output_cost); + LSA_LINK_TYPE_TRANSIT, 0, cost); } /* Describe type 3 link. */ else @@ -581,7 +596,7 @@ static int lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi) { struct in_addr id, mask; - + /* Describe Type 3 Link. */ if (oi->state != ISM_Loopback) return 0; @@ -597,13 +612,14 @@ static int lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi) { struct ospf_neighbor *nbr; + u_int16_t cost = ospf_link_cost (oi); if (oi->state == ISM_PointToPoint) if ((nbr = ospf_nbr_lookup_ptop (oi))) if (nbr->state == NSM_Full) { link_info_set (s, nbr->router_id, oi->address->u.prefix4, - LSA_LINK_TYPE_VIRTUALLINK, 0, oi->output_cost); + LSA_LINK_TYPE_VIRTUALLINK, 0, cost); return 1; } @@ -623,6 +639,7 @@ lsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi) struct route_node *rn; struct ospf_neighbor *nbr = NULL; struct in_addr id, mask; + u_int16_t cost = ospf_link_cost (oi); mask.s_addr = 0xffffffff; id.s_addr = oi->address->u.prefix4.s_addr; @@ -641,7 +658,7 @@ lsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi) { link_info_set (s, nbr->router_id, oi->address->u.prefix4, - LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost); + LSA_LINK_TYPE_POINTOPOINT, 0, cost); links++; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("PointToMultipoint: set link to %s", @@ -721,7 +738,64 @@ ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area) /* Set # of links here. */ stream_putw_at (s, putp, cnt); } + +static int +ospf_stub_router_timer (struct thread *t) +{ + struct ospf_area *area = THREAD_ARG (t); + + area->t_stub_router = NULL; + + SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); + + /* clear stub route state and generate router-lsa refresh, don't + * clobber an administratively set stub-router state though. + */ + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) + return 0; + + UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); + + ospf_router_lsa_timer_add (area); + + return 0; +} +inline static void +ospf_stub_router_check (struct ospf_area *area) +{ + /* area must either be administratively configured to be stub + * or startup-time stub-router must be configured and we must in a pre-stub + * state. + */ + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) + { + SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); + return; + } + + /* not admin-stubbed, check whether startup stubbing is configured and + * whether it's not been done yet + */ + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED)) + return; + + if (area->ospf->stub_router_startup_time == OSPF_STUB_ROUTER_UNCONFIGURED) + { + /* stub-router is hence done forever for this area, even if someone + * tries configure it (take effect next restart). + */ + SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); + return; + } + + /* startup stub-router configured and not yet done */ + SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); + + OSPF_AREA_TIMER_ON (area->t_stub_router, ospf_stub_router_timer, + area->ospf->stub_router_startup_time); +} + /* Create new router-LSA. */ static struct ospf_lsa * ospf_router_lsa_new (struct ospf_area *area) @@ -735,6 +809,11 @@ ospf_router_lsa_new (struct ospf_area *area) if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Create router-LSA instance"); + /* check whether stub-router is desired, and if this is the first + * router LSA. + */ + ospf_stub_router_check (area); + /* Create a stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s); @@ -764,11 +843,11 @@ ospf_router_lsa_new (struct ospf_area *area) } /* Originate Router-LSA. */ -struct ospf_lsa * +static struct ospf_lsa * ospf_router_lsa_originate (struct ospf_area *area) { struct ospf_lsa *new; - + /* Create new router-LSA instance. */ new = ospf_router_lsa_new (area); diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 5cf69c31..42c08828 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -252,7 +252,6 @@ extern struct lsa_header *ospf_lsa_data_dup (struct lsa_header *); extern void ospf_lsa_data_free (struct lsa_header *); /* Prototype for various LSAs */ -extern struct ospf_lsa *ospf_router_lsa_originate (struct ospf_area *); extern int ospf_router_lsa_update_timer (struct thread *); extern void ospf_router_lsa_timer_add (struct ospf_area *); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 483b6387..3225d7d7 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -136,15 +136,12 @@ sighup (void) zlog (NULL, LOG_INFO, "SIGHUP received"); } -/* SIGINT handler. */ -static void __attribute__ ((noreturn)) +/* SIGINT / SIGTERM handler. */ +static void sigint (void) { zlog_notice ("Terminating on signal"); - ospf_terminate (); - - exit (0); } /* SIGUSR1 handler. */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index bdbdd03e..5eedbd82 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -690,21 +690,6 @@ ospf_route_table_dump (struct route_table *rt) zlog_debug ("========================================"); } -void -ospf_terminate () -{ - struct ospf *ospf; - struct listnode *node, *nnode; - - for (ALL_LIST_ELEMENTS (om->ospf, node, nnode, ospf)) - { - if (ospf->new_table) - ospf_route_delete (ospf->new_table); - if (ospf->old_external_route) - ospf_route_delete (ospf->old_external_route); - } -} - /* This is 16.4.1 implementation. o Intra-area paths using non-backbone areas are always the most preferred. o The other paths, intra-area backbone paths and inter-area paths, diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index e56027be..c3cc4cb4 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2517,7 +2517,21 @@ show_ip_ospf_area (struct vty *vty, struct ospf_area *area) VTY_NEWLINE); } } - + /* Stub-router state for this area */ + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) + { + char timebuf[9]; + vty_out (vty, " Originating stub / maximum-distance Router-LSA%s", + VTY_NEWLINE); + if (CHECK_FLAG(area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) + vty_out (vty, " Administratively activated (indefinitely)%s", + VTY_NEWLINE); + if (area->t_stub_router) + vty_out (vty, " Active from startup, %s remaining%s", + ospf_timer_dump (area->t_stub_router, timebuf, + sizeof(timebuf)), VTY_NEWLINE); + } + /* Show number of fully adjacent neighbors. */ vty_out (vty, " Number of fully adjacent neighbors in this area:" " %d%s", area->full_nbrs, VTY_NEWLINE); @@ -2592,7 +2606,12 @@ DEFUN (show_ip_ospf, vty_out (vty, " OSPF Routing Process, Router ID: %s%s", inet_ntoa (ospf->router_id), VTY_NEWLINE); - + + /* Graceful shutdown */ + if (ospf->t_graceful_shutdown) + vty_out (vty, " Graceful shutdown in progress, %s remaining%s", + ospf_timer_dump (ospf->t_graceful_shutdown, + timebuf, sizeof (timebuf)), VTY_NEWLINE); /* Show capability. */ vty_out (vty, " Supports only single TOS (TOS0) routes%s", VTY_NEWLINE); vty_out (vty, " This implementation conforms to RFC2328%s", VTY_NEWLINE); @@ -2607,7 +2626,21 @@ DEFUN (show_ip_ospf, " (origination blocked)" : "", VTY_NEWLINE); #endif /* HAVE_OPAQUE_LSA */ - + + /* Show stub-router configuration */ + if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED + || ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) + { + vty_out (vty, " Stub router advertisement is configured%s", + VTY_NEWLINE); + if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) + vty_out (vty, " Enabled for %us after start-up%s", + ospf->stub_router_startup_time, VTY_NEWLINE); + if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) + vty_out (vty, " Enabled for %us prior to full shutdown%s", + ospf->stub_router_shutdown_time, VTY_NEWLINE); + } + /* Show SPF timers. */ vty_out (vty, " Initial SPF scheduling delay %d millisec(s)%s" " Minimum hold time between consecutive SPFs %d millisec(s)%s" @@ -6771,7 +6804,171 @@ ALIAS (no_ip_ospf_mtu_ignore, "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") + +DEFUN (ospf_max_metric_router_lsa_admin, + ospf_max_metric_router_lsa_admin_cmd, + "max-metric router-lsa administrative", + "OSPF maximum / infinite-distance metric\n" + "Advertise own Router-LSA with infinite distance (stub router)\n" + "Administratively applied, for an indefinite period\n") +{ + struct listnode *ln; + struct ospf_area *area; + struct ospf *ospf = vty->index; + for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) + { + SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); + + if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) + ospf_router_lsa_timer_add (area); + } + return CMD_SUCCESS; +} + +DEFUN (no_ospf_max_metric_router_lsa_admin, + no_ospf_max_metric_router_lsa_admin_cmd, + "no max-metric router-lsa administrative", + NO_STR + "OSPF maximum / infinite-distance metric\n" + "Advertise own Router-LSA with infinite distance (stub router)\n" + "Administratively applied, for an indefinite period\n") +{ + struct listnode *ln; + struct ospf_area *area; + struct ospf *ospf = vty->index; + + for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) + { + UNSET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); + + /* Don't trample on the start-up stub timer */ + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED) + && !area->t_stub_router) + { + UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); + ospf_router_lsa_timer_add (area); + } + } + return CMD_SUCCESS; +} + +DEFUN (ospf_max_metric_router_lsa_startup, + ospf_max_metric_router_lsa_startup_cmd, + "max-metric router-lsa on-startup <5-86400>", + "OSPF maximum / infinite-distance metric\n" + "Advertise own Router-LSA with infinite distance (stub router)\n" + "Automatically advertise stub Router-LSA on startup of OSPF\n" + "Time (seconds) to advertise self as stub-router\n") +{ + unsigned int seconds; + struct ospf *ospf = vty->index; + + if (argc != 1) + { + vty_out (vty, "%% Must supply stub-router period"); + return CMD_WARNING; + } + + VTY_GET_INTEGER ("stub-router startup period", seconds, argv[0]); + + ospf->stub_router_startup_time = seconds; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_max_metric_router_lsa_startup, + no_ospf_max_metric_router_lsa_startup_cmd, + "no max-metric router-lsa on-startup", + NO_STR + "OSPF maximum / infinite-distance metric\n" + "Advertise own Router-LSA with infinite distance (stub router)\n" + "Automatically advertise stub Router-LSA on startup of OSPF\n") +{ + struct listnode *ln; + struct ospf_area *area; + struct ospf *ospf = vty->index; + + ospf->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; + + for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) + { + SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); + OSPF_TIMER_OFF (area->t_stub_router); + + /* Don't trample on admin stub routed */ + if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) + { + UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); + ospf_router_lsa_timer_add (area); + } + } + return CMD_SUCCESS; +} + +DEFUN (ospf_max_metric_router_lsa_shutdown, + ospf_max_metric_router_lsa_shutdown_cmd, + "max-metric router-lsa on-shutdown <5-86400>", + "OSPF maximum / infinite-distance metric\n" + "Advertise own Router-LSA with infinite distance (stub router)\n" + "Advertise stub-router prior to full shutdown of OSPF\n" + "Time (seconds) to wait till full shutdown\n") +{ + unsigned int seconds; + struct ospf *ospf = vty->index; + + if (argc != 1) + { + vty_out (vty, "%% Must supply stub-router shutdown period"); + return CMD_WARNING; + } + + VTY_GET_INTEGER ("stub-router shutdown wait period", seconds, argv[0]); + + ospf->stub_router_shutdown_time = seconds; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_max_metric_router_lsa_shutdown, + no_ospf_max_metric_router_lsa_shutdown_cmd, + "no max-metric router-lsa on-shutdown", + NO_STR + "OSPF maximum / infinite-distance metric\n" + "Advertise own Router-LSA with infinite distance (stub router)\n" + "Advertise stub-router prior to full shutdown of OSPF\n") +{ + struct ospf *ospf = vty->index; + + ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; + + return CMD_SUCCESS; +} + +static void +config_write_stub_router (struct vty *vty, struct ospf *ospf) +{ + struct listnode *ln; + struct ospf_area *area; + + if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) + vty_out (vty, " max-metric router-lsa on-startup %u%s", + ospf->stub_router_startup_time, VTY_NEWLINE); + if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) + vty_out (vty, " max-metric router-lsa on-shutdown %u%s", + ospf->stub_router_shutdown_time, VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) + { + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) + { + vty_out (vty, " max-metric router-lsa administrative%s", + VTY_NEWLINE); + break; + } + } + return; +} + static void show_ip_ospf_route_network (struct vty *vty, struct route_table *rt) { @@ -7612,9 +7809,12 @@ ospf_config_write (struct vty *vty) ospf->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || ospf->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT) vty_out (vty, " timers throttle spf %d %d %d%s", - ospf->spf_delay, ospf->spf_holdtime, + ospf->spf_delay, ospf->spf_holdtime, ospf->spf_max_holdtime, VTY_NEWLINE); - + + /* Max-metric router-lsa print */ + config_write_stub_router (vty, ospf); + /* SPF refresh parameters print. */ if (ospf->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT) vty_out (vty, " refresh timer %d%s", @@ -8052,16 +8252,27 @@ ospf_vty_init (void) install_element (OSPF_NODE, &ospf_area_import_list_cmd); install_element (OSPF_NODE, &no_ospf_area_import_list_cmd); - + + /* SPF timer commands */ install_element (OSPF_NODE, &ospf_timers_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_spf_cmd); install_element (OSPF_NODE, &ospf_timers_throttle_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_throttle_spf_cmd); + /* refresh timer commands */ install_element (OSPF_NODE, &ospf_refresh_timer_cmd); install_element (OSPF_NODE, &no_ospf_refresh_timer_val_cmd); install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd); + /* max-metric commands */ + install_element (OSPF_NODE, &ospf_max_metric_router_lsa_admin_cmd); + install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_admin_cmd); + install_element (OSPF_NODE, &ospf_max_metric_router_lsa_startup_cmd); + install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_startup_cmd); + install_element (OSPF_NODE, &ospf_max_metric_router_lsa_shutdown_cmd); + install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_shutdown_cmd); + + /* reference bandwidth commands */ install_element (OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd); install_element (OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index bf8ca4dc..69f091d7 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -64,13 +64,14 @@ extern struct zclient *zclient; extern struct in_addr router_id_zebra; -void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); -void ospf_network_free (struct ospf *, struct ospf_network *); -void ospf_area_free (struct ospf_area *); -void ospf_network_run (struct ospf *, struct prefix *, struct ospf_area *); +static void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); +static void ospf_network_free (struct ospf *, struct ospf_network *); +static void ospf_area_free (struct ospf_area *); +static void ospf_network_run (struct ospf *, struct prefix *, struct ospf_area *); +static void ospf_finish_final (struct ospf *); #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 - + void ospf_router_id_update (struct ospf *ospf) { @@ -172,7 +173,10 @@ ospf_new (void) new->new_external_route = route_table_init (); new->old_external_route = route_table_init (); new->external_lsas = route_table_init (); - + + new->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; + new->stub_router_shutdown_time = OSPF_STUB_ROUTER_SHUTDOWN_DEFAULT; + /* Distribute parameter init. */ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { @@ -263,9 +267,116 @@ ospf_get () return ospf; } + +/* Handle the second half of graceful shutdown. This is called either + * from the graceful-shutdown timer thread, or directly through + * ospf_graceful_shutdown_check. + * + * Function is to cleanup G-R state, if required then call ospf_finish_final + * to complete shutdown of this ospf instance. Possibly exit if the + * whole process is being shutdown and this was the last OSPF instance. + */ +static void +ospf_graceful_shutdown_finish (struct ospf *ospf) +{ + ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; + OSPF_TIMER_OFF (ospf->t_graceful_shutdown); + + ospf_finish_final (ospf); + + /* *ospf is now invalid */ + + /* ospfd being shut-down? If so, was this the last ospf instance? */ + if (CHECK_FLAG (om->options, OSPF_MASTER_SHUTDOWN) + && (listcount (om->ospf) == 0)) + exit (0); + + return; +} + +/* Timer thread for G-R */ +static int +ospf_graceful_shutdown_timer (struct thread *t) +{ + struct ospf *ospf = THREAD_ARG(t); + + ospf_graceful_shutdown_finish (ospf); + + return 0; +} + +/* Check whether graceful-shutdown must be scheduled, otherwise call + * down directly into second-half of instance shutdown. + */ +static void +ospf_graceful_shutdown_check (struct ospf *ospf) +{ + unsigned long timeout; + struct listnode *ln; + struct ospf_area *area; + + /* graceful shutdown already running? */ + if (ospf->t_graceful_shutdown) + return; + + /* Should we try push out max-metric LSAs? */ + if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) + { + for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) + { + SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); + + if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) + ospf_router_lsa_timer_add (area); + } + timeout = ospf->stub_router_shutdown_time; + } + else + /* No timer needed */ + return ospf_graceful_shutdown_finish (ospf); + + OSPF_TIMER_ON (ospf->t_graceful_shutdown, ospf_graceful_shutdown_timer, + timeout); + return; +} + +/* Shut down the entire process */ +void +ospf_terminate (void) +{ + struct ospf *ospf; + struct listnode *node, *nnode; + + /* shutdown already in progress */ + if (CHECK_FLAG (om->options, OSPF_MASTER_SHUTDOWN)) + return; + + SET_FLAG (om->options, OSPF_MASTER_SHUTDOWN); + + for (ALL_LIST_ELEMENTS (om->ospf, node, nnode, ospf)) + ospf_finish (ospf); + + /* Deliberately go back up, hopefully to thread scheduler, as + * One or more ospf_finish()'s may have deferred shutdown to a timer + * thread + */ +} void ospf_finish (struct ospf *ospf) +{ + /* let graceful shutdown decide */ + return ospf_graceful_shutdown_check (ospf); + + /* if ospf_graceful_shutdown returns, then ospf_finish_final is + * deferred to expiry of G-S timer thread. Return back up, hopefully + * to thread scheduler. + */ +} + +/* Final cleanup of ospf instance */ +static void +ospf_finish_final (struct ospf *ospf) { struct route_node *rn; struct ospf_nbr_nbma *nbr_nbma; @@ -279,8 +390,11 @@ ospf_finish (struct ospf *ospf) #ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_term (ospf); #endif /* HAVE_OPAQUE_LSA */ - - /* Unredister redistribution */ + + /* be nice if this worked, but it doesn't */ + /*ospf_flush_self_originated_lsas_now (ospf);*/ + + /* Unregister redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) ospf_redistribute_unset (ospf, i); @@ -347,10 +461,12 @@ ospf_finish (struct ospf *ospf) OSPF_TIMER_OFF (ospf->t_maxage); OSPF_TIMER_OFF (ospf->t_maxage_walker); OSPF_TIMER_OFF (ospf->t_abr_task); + OSPF_TIMER_OFF (ospf->t_asbr_check); OSPF_TIMER_OFF (ospf->t_distribute_update); OSPF_TIMER_OFF (ospf->t_lsa_refresher); OSPF_TIMER_OFF (ospf->t_read); OSPF_TIMER_OFF (ospf->t_write); + OSPF_TIMER_OFF (ospf->t_opaque_lsa_self); close (ospf->fd); stream_free(ospf->ibuf); @@ -435,7 +551,7 @@ ospf_area_new (struct ospf *ospf, struct in_addr area_id) new->external_routing = OSPF_AREA_DEFAULT; new->default_cost = 1; new->auth_type = OSPF_AUTH_NULL; - + /* New LSDB init. */ new->lsdb = ospf_lsdb_new (); @@ -496,7 +612,11 @@ ospf_area_free (struct ospf_area *area) /* Cancel timer. */ OSPF_TIMER_OFF (area->t_router_lsa_self); - + OSPF_TIMER_OFF (area->t_stub_router); +#ifdef HAVE_OPAQUE_LSA + OSPF_TIMER_OFF (area->t_opaque_lsa_self); +#endif /* HAVE_OPAQUE_LSA */ + if (OSPF_IS_AREA_BACKBONE (area)) area->ospf->backbone = NULL; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 38e56b6f..ed66ebf7 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -94,6 +94,7 @@ /* OSPF interface default values. */ #define OSPF_OUTPUT_COST_DEFAULT 10 +#define OSPF_OUTPUT_COST_INFINITE UINT16_MAX #define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT 40 #define OSPF_ROUTER_DEAD_INTERVAL_MINIMAL 1 #define OSPF_HELLO_INTERVAL_DEFAULT 10 @@ -152,6 +153,7 @@ struct ospf_master /* Various OSPF global configuration. */ u_char options; +#define OSPF_MASTER_SHUTDOWN (1 << 0) /* flag for ospf_finish / graceful-shutdown */ }; /* OSPF instance structure. */ @@ -192,10 +194,18 @@ struct ospf #define OPAQUE_BLOCK_TYPE_11_LSA_BIT (1 << 3) #endif /* HAVE_OPAQUE_LSA */ - unsigned int spf_delay; /* SPF delay time. */ - unsigned int spf_holdtime; /* SPF hold time. */ - unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ - unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ + /* RFC3137 stub router. Configured time to stay stub / max-metric */ + unsigned int stub_router_startup_time; /* seconds */ + unsigned int stub_router_shutdown_time; /* seconds */ +#define OSPF_STUB_ROUTER_UNCONFIGURED 0 +#define OSPF_STUB_ROUTER_SHUTDOWN_DEFAULT 2 + + /* SPF parameters */ + unsigned int spf_delay; /* SPF delay time. */ + unsigned int spf_holdtime; /* SPF hold time. */ + unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ + unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ + int default_originate; /* Default information originate. */ #define DEFAULT_ORIGINATE_NONE 0 #define DEFAULT_ORIGINATE_ZEBRA 1 @@ -253,6 +263,7 @@ struct ospf #endif /* HAVE_OPAQUE_LSA */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ + struct thread *t_graceful_shutdown; /* Graceful/stub-router shutdown timer*/ struct thread *t_write; struct thread *t_read; @@ -351,6 +362,7 @@ struct ospf_area int shortcut_capability; /* Other ABRs agree on S-bit */ u_int32_t default_cost; /* StubDefaultCost. */ int auth_type; /* Authentication type. */ + u_char NSSATranslatorRole; /* NSSA configured role */ #define OSPF_NSSA_ROLE_NEVER 0 @@ -365,7 +377,13 @@ struct ospf_area #define OSPF_TRANSIT_FALSE 0 #define OSPF_TRANSIT_TRUE 1 struct route_table *ranges; /* Configured Area Ranges. */ - + + /* RFC3137 stub router state flags for area */ + u_char stub_router_state; +#define OSPF_AREA_ADMIN_STUB_ROUTED (1 << 0) /* admin stub-router set */ +#define OSPF_AREA_IS_STUB_ROUTED (1 << 1) /* stub-router active */ +#define OSPF_AREA_WAS_START_STUB_ROUTED (1 << 2) /* startup SR was done */ + /* Area related LSDBs[Type1-4]. */ struct ospf_lsdb *lsdb; @@ -415,6 +433,7 @@ struct ospf_area /* Threads. */ struct thread *t_router_lsa_self;/* Self-originated router-LSA timer. */ + struct thread *t_stub_router; /* Stub-router timer */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ #endif /* HAVE_OPAQUE_LSA */ -- cgit v1.2.1