2005-10-29 Paul Jakma <paul.jakma@sun.com>

	* (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.
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index a85667e..31b9a4f 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -483,6 +483,19 @@
   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 @@
   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 @@
 	/* 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 @@
 {
   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 @@
       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 @@
 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 @@
 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 @@
   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 @@
 
 	  {
 	    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 @@
   /* 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 @@
   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 @@
 }
 
 /* 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);