2003-06-19 Paul Jakma <paul@dishone.st>

	* ospf_abr.c (ospf_abr_nssa_am_elected): new function.
	  Look through LSDB for an area and try determine whether other
	  routers are more 'electable' than this router. Presumes caller
	  has checked Role.
	  (ospf_abr_nssa_check_status): new function. check any NSSA related
          status changes. At present determines NSSATranslatorState should
	  be enabled or disabled.
	  (ospf_abr_announce_network_to_area): remove the redundant
	  call to ospf_abr_announce_network_to_area() (as per Vadim,
	  [zebra 14710], problem 7).
	  (global): Update NSSATranslator to NSSATranslatorState as per
	  ospfd.h changes
	  (ospf_abr_announce_nssa_defaults): call
	  ospf_abr_announce_network_to_area() to inject default summaries.
	  (ospf_abr_nssa_task): undo commented out calls to
	  ospf_abr_prepare_aggregates() and ospf_abr_send_nssa_aggregates(),
	  if they're borked, lets fix them.
	  (ospf_abr_task): remove call to ospf_abr_nssa_task() - move this
	  to the timer scheduler.
	  (ospf_abr_task_timer): call ospf_abr_nssa_task() and
	  ospf_abr_nssa_check_status()
	  (misc): some minor reformatting.
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index 638cf1c..8991bd7 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -347,6 +347,133 @@
   return ospf->backbone->full_nbrs;
 }
 
+#ifdef HAVE_NSSA
+/* Determine whether this router is elected translator or not for area */
+int
+ospf_abr_nssa_am_elected (struct ospf_area *area)
+{
+  struct route_node *rn;
+  struct ospf_lsa *lsa;
+  struct router_lsa *rlsa;
+  struct in_addr *best = NULL;
+  
+  LSDB_LOOP ( ROUTER_LSDB (area), rn, lsa)
+    {
+      /* sanity checks */
+      if (!lsa 
+          || (lsa->data->type != OSPF_ROUTER_LSA) 
+          || IS_LSA_SELF (lsa))
+        continue;
+      
+      rlsa = (struct router_lsa *) lsa->data;
+      
+      /* ignore non-ABR routers */
+      if (!IS_ROUTER_LSA_BORDER (rlsa))
+        continue;
+      
+      /* Router has Nt flag - always translate */
+      if (IS_ROUTER_LSA_NT (rlsa))
+        {
+          if (IS_DEBUG_OSPF_NSSA)
+            zlog_info ("ospf_abr_nssa_am_elected: ",
+                       "router %s asserts Nt",
+                       inet_ntoa (lsa->data->id) );
+          return 0;
+        }
+      
+      if (best == NULL)
+      	best = &lsa->data->id;
+      else
+        if ( IPV4_ADDR_CMP (&best, &lsa->data->id) < 0)
+          best = &lsa->data->id;
+    }
+    
+    if (IS_DEBUG_OSPF_NSSA)
+      zlog_info ("ospf_abr_nssa_am_elected: best electable ABR is: %s",
+                  (best) ? inet_ntoa (*best) : "<none>" );
+                  
+    if (best == NULL)
+      return 1;
+    
+    if ( IPV4_ADDR_CMP (&best, &area->ospf->router_id) < 0)
+      return 1;
+    else
+      return 0;
+}
+
+/* Check NSSA ABR status
+ * assumes there are nssa areas
+ */
+void 
+ospf_abr_nssa_check_status (struct ospf *ospf)
+{
+  struct ospf_area *area;
+  listnode lnode;
+    
+  LIST_LOOP (ospf->areas, area, lnode)
+    {
+    
+      if (area->external_routing != OSPF_AREA_NSSA)
+        continue;
+        
+      if (IS_DEBUG_OSPF (nssa, NSSA))
+        zlog_info ("ospf_abr_nssa_check_status: "
+                    "checking area %s",
+                    inet_ntoa (area->area_id));
+      
+      if (!IS_OSPF_ABR (area->ospf))
+        {
+          if (IS_DEBUG_OSPF (nssa, NSSA))
+          zlog_info ("ospf_abr_nssa_check_status: "
+                     "not ABR");
+          area->NSSATranslatorState = OSPF_NSSA_STATE_DISABLED;
+          continue;
+        }
+      
+      switch (area->NSSATranslatorRole)
+        {      
+          case OSPF_NSSA_ROLE_NEVER:
+            /* We never Translate Type-7 LSA. */
+            /* TODO: check previous state and flush? */
+            if (IS_DEBUG_OSPF (nssa, NSSA))
+              zlog_info ("ospf_abr_nssa_check_status: "
+                         "never translate");
+            area->NSSATranslatorState = OSPF_NSSA_STATE_DISABLED;
+            continue;
+             
+          case OSPF_NSSA_ROLE_ALWAYS:
+            /* We always translate if we are an ABR
+             * TODO: originate new LSAs if state change?
+             * or let the nssa abr task take care of it?
+             */
+            if (IS_DEBUG_OSPF (nssa, NSSA))
+              zlog_info ("ospf_abr_nssa_check_status: "
+                         "translate always");
+            area->NSSATranslatorState = OSPF_NSSA_STATE_ENABLED;
+            continue;
+      
+          case OSPF_NSSA_ROLE_CANDIDATE:
+            /* We are a candidate for Translation */
+            if (ospf_abr_nssa_am_elected (area) > 0 )
+              {
+                area->NSSATranslatorState = OSPF_NSSA_STATE_ENABLED;
+                if (IS_DEBUG_OSPF (nssa, NSSA))
+                  zlog_info ("ospf_abr_nssa_check_status: "
+                             "elected translator");
+               }
+            else
+               {
+                 area->NSSATranslatorState = OSPF_NSSA_STATE_DISABLED;
+                 if (IS_DEBUG_OSPF (nssa, NSSA))
+                   zlog_info ("ospf_abr_nssa_check_status: "
+                              "not elected");
+               }
+            continue;
+         }
+    }
+}
+#endif /* HAVE_NSSA */
+
 /* Check area border router status. */
 void
 ospf_check_abr_status (struct ospf *ospf)
@@ -365,7 +492,7 @@
   for (node = listhead (ospf->areas); node; nextnode (node))
     {
       area = getdata (node);
-
+      
       if (listcount (area->oiflist)) 
 	{
 	  areas_configured++;
@@ -604,9 +731,6 @@
 	zlog_info ("ospf_abr_announce_network_to_area(): "
 		   "flooding new version of summary");
 
-#ifndef HAVE_NSSA      
-      ospf_flood_through_area (area, NULL, lsa);
-#endif /* ! HAVE_NSSA */
     }
 
   if (IS_DEBUG_OSPF_EVENT)
@@ -808,7 +932,7 @@
     {
       area = getdata (node);
 
-      if (! area->NSSATranslator)
+      if (! area->NSSATranslatorState)
 	continue; /* skip if not translator */
       
       if (area->external_routing != OSPF_AREA_NSSA)
@@ -1320,7 +1444,7 @@
     {
       area = getdata (node);
 
-      if (! area->NSSATranslator)
+      if (! area->NSSATranslatorState)
 	continue;
 
       if (IS_DEBUG_OSPF_NSSA)
@@ -1359,15 +1483,16 @@
 	    }
 
           if (range->specifics)
-	    {
-	      if (IS_DEBUG_OSPF_NSSA)
-		zlog_info ("ospf_abr_send_nssa_aggregates(): active range");
+            {
+              if (IS_DEBUG_OSPF_NSSA)
+                zlog_info ("ospf_abr_send_nssa_aggregates(): active range");
 
-	      /* Fetch LSA-Type-7 from aggregate prefix, and then
-                 translate, Install (as Type-5), Approve, and Flood */
-		ospf_abr_translate_nssa_range (&p, range->cost);
-	    } /* if (range->specifics)*/
-	} /* all area ranges*/
+              /* Fetch LSA-Type-7 from aggregate prefix, and then
+               *  translate, Install (as Type-5), Approve, and Flood
+               */
+              ospf_abr_translate_nssa_range (&p, range->cost);
+            }
+        } /* all area ranges*/
     } /* all areas */
 
   if (IS_DEBUG_OSPF_NSSA)
@@ -1395,23 +1520,24 @@
     {
       area = getdata (node);
       if (IS_DEBUG_OSPF_NSSA)
-	zlog_info ("ospf_abr_announce_nssa_defaults(): looking at area %s",
-		   inet_ntoa (area->area_id));
+        zlog_info ("ospf_abr_announce_nssa_defaults(): looking at area %s",
+                   inet_ntoa (area->area_id));
 
       if (area->external_routing != OSPF_AREA_NSSA)
-	continue;
+        continue;
 
       if (OSPF_IS_AREA_BACKBONE (area))
-	continue; /* Sanity Check */
+        continue; /* Sanity Check */
 
       /* if (!TranslatorRole continue V 1.0 look for "always" conf */
-      if (area->NSSATranslator)
-	{
-	  if (IS_DEBUG_OSPF_NSSA)
-	    zlog_info ("ospf_abr_announce_nssa_defaults(): "
-		       "announcing 0.0.0.0/0 to this nssa");
-	  /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */
-	}
+      if (area->NSSATranslatorState)
+        {
+          if (IS_DEBUG_OSPF_NSSA)
+            zlog_info ("ospf_abr_announce_nssa_defaults(): "
+                       "announcing 0.0.0.0/0 to this nssa");
+          /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */
+          ospf_abr_announce_network_to_area (&p, area->default_cost, area);
+        }
     }
 }
 #endif /* HAVE_NSSA */
@@ -1606,24 +1732,24 @@
   /* RESET all Ranges in every Area, same as summaries */
   if (IS_DEBUG_OSPF_NSSA)
     zlog_info ("ospf_abr_nssa_task(): NSSA initialize aggregates");
-
-  /*    ospf_abr_prepare_aggregates ();  TURNED OFF just for now */
+  ospf_abr_prepare_aggregates (ospf);  /*TURNED OFF just for now */
 
   /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or
-     Aggregate as Type-7 */
-  /* Install or Approve in Type-5 Global LSDB */
+   *  Aggregate as Type-7
+   * Install or Approve in Type-5 Global LSDB 
+   */
   if (IS_DEBUG_OSPF_NSSA)
     zlog_info ("ospf_abr_nssa_task(): process translates");
-
   ospf_abr_process_nssa_translates (ospf);
 
   /* Translate/Send any "ranged" aggregates, and also 5-Install and
-     Approve */
-  /* Scan Type-7's for aggregates, translate to Type-5's,
-     Install/Flood/Approve */
+   *  Approve
+   * Scan Type-7's for aggregates, translate to Type-5's,
+   *  Install/Flood/Approve 
+   */
   if (IS_DEBUG_OSPF_NSSA)
     zlog_info("ospf_abr_nssa_task(): send NSSA aggregates");
-  /*       ospf_abr_send_nssa_aggregates ();  TURNED OFF FOR NOW */
+  ospf_abr_send_nssa_aggregates (ospf);  /*TURNED OFF FOR NOW */
 
   /* Send any NSSA defaults as Type-5 */
   if (IS_DEBUG_OSPF_NSSA)
@@ -1690,10 +1816,6 @@
 
   ospf_abr_manage_discard_routes (ospf);
 
-#ifdef HAVE_NSSA
-  ospf_abr_nssa_task (ospf); /* if nssa-abr, then scan Type-7 LSDB */
-#endif /* HAVE_NSSA */
-
   if (IS_DEBUG_OSPF_EVENT)
     zlog_info ("ospf_abr_task(): Stop");
 }
@@ -1712,6 +1834,10 @@
   ospf_check_abr_status (ospf);
 
   ospf_abr_task (ospf);
+#ifdef HAVE_NSSA  
+  ospf_abr_nssa_check_status (ospf);
+  ospf_abr_nssa_task (ospf); /* if nssa-abr, then scan Type-7 LSDB */
+#endif /* HAVE_NSSA */
 
   return 0;
 }