[ospfd] NSSA translate-enabled ABR should declare itself as ASBR

2006-06-26 Paul Jakma <paul.jakma@sun.com>

	* ospf_abr.c: (general) NSSA translate-candidate ABRs need to
	  be ASBRs, or other routers may rightfully refuse to install
	  translated type-5s LSAs. reported by dendroot@gmail.com.
	  (ospf_abr_nssa_check_status) Detect change in translator
	  state when ABR, and inc/dec redistribute count as when we
	  leave/enter the disabled state - so that translate-enabled
	  ABR properly sets ASBR bit on non-NSSA areas.
	  Run the resulting function through indent to clean it up.
	* ospf_lsa.c: (router_lsa_flags) For purposes of ASBR bit,
	  NSSA area is same as stub area.
diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog
index f2cdae7..27fa804 100644
--- a/ospfd/ChangeLog
+++ b/ospfd/ChangeLog
@@ -1,3 +1,16 @@
+2006-06-26 Paul Jakma <paul.jakma@sun.com>
+
+	* ospf_abr.c: (general) NSSA translate-candidate ABRs need to
+	  be ASBRs, or other routers may rightfully refuse to install
+	  translated type-5s LSAs. reported by dendroot@gmail.com.
+	  (ospf_abr_nssa_check_status) Detect change in translator
+	  state when ABR, and inc/dec redistribute count as when we
+	  leave/enter the disabled state - so that translate-enabled
+	  ABR properly sets ASBR bit on non-NSSA areas.
+	  Run the resulting function through indent to clean it up.
+	* ospf_lsa.c: (router_lsa_flags) For purposes of ASBR bit,
+	  NSSA area is same as stub area.
+	  
 2006-06-24 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
 
 	* ospf_snmp.c: (ospfTrapNbrStateChange, ospfTrapIfStateChange) Improve
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index 225cf6e..88636f1 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -409,67 +409,80 @@
 {
   struct ospf_area *area;
   struct listnode *lnode, *nnode;
-    
+  
   for (ALL_LIST_ELEMENTS (ospf->areas, lnode, nnode, area))
     {
-    
+      u_char old_state = area->NSSATranslatorState;
+
       if (area->external_routing != OSPF_AREA_NSSA)
         continue;
-        
+
       if (IS_DEBUG_OSPF (nssa, NSSA))
         zlog_debug ("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_debug ("ospf_abr_nssa_check_status: "
-	    		"not ABR");
+            zlog_debug ("ospf_abr_nssa_check_status: " 
+                        "not ABR");
           area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_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_debug ("ospf_abr_nssa_check_status: "
-	      		  "never translate");
-            area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_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_debug ("ospf_abr_nssa_check_status: "
-			  "translate always");
-            area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_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_TRANSLATE_ENABLED;
-                if (IS_DEBUG_OSPF (nssa, NSSA))
-                  zlog_debug ("ospf_abr_nssa_check_status: "
-                              "elected translator");
-               }
-            else
-               {
-                 area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED;
-                 if (IS_DEBUG_OSPF (nssa, NSSA))
-                   zlog_debug ("ospf_abr_nssa_check_status: "
-			       "not elected");
-               }
-            continue;
-         }
+      else
+        {
+          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_debug ("ospf_abr_nssa_check_status: "
+			    "never translate");
+              area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED;
+              break;
+
+            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_debug ("ospf_abr_nssa_check_status: "
+                            "translate always");
+              area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_ENABLED;
+              break;
+
+            case OSPF_NSSA_ROLE_CANDIDATE:
+              /* We are a candidate for Translation */
+              if (ospf_abr_nssa_am_elected (area) > 0)
+                {
+                  area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_ENABLED;
+                  if (IS_DEBUG_OSPF (nssa, NSSA))
+                    zlog_debug ("ospf_abr_nssa_check_status: "
+                                "elected translator");
+                }
+              else
+                {
+                  area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED;
+                  if (IS_DEBUG_OSPF (nssa, NSSA))
+                    zlog_debug ("ospf_abr_nssa_check_status: " "not elected");
+                }
+              break;
+            }
+        }
+      /* RFC3101, 3.1:
+       * All NSSA border routers must set the E-bit in the Type-1 router-LSAs
+       * of their directly attached non-stub areas, even when they are not
+       * translating.
+       */
+      if (old_state != area->NSSATranslatorState)
+      	{
+          if (old_state == OSPF_NSSA_TRANSLATE_DISABLED)
+	    ospf_asbr_status_update (ospf, ++ospf->redistribute);
+	  else if (area->NSSATranslatorState == OSPF_NSSA_TRANSLATE_DISABLED)
+	    ospf_asbr_status_update (ospf, --ospf->redistribute);
+	}
     }
 }
 
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index a0afbad..509afc8 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -437,7 +437,8 @@
 	SET_FLAG (flags, ROUTER_LSA_SHORTCUT);
 
   /* ASBR can't exit in stub area. */
-  if (area->external_routing == OSPF_AREA_STUB)
+  if (area->external_routing == OSPF_AREA_STUB
+      || area->external_routing == OSPF_AREA_NSSA)
     UNSET_FLAG (flags, ROUTER_LSA_EXTERNAL);
   /* If ASBR set External flag */
   else if (IS_OSPF_ASBR (area->ospf))