Date: Fri, 20 Dec 2002 17:28:45 +0900
From: Masahiko Endo <endo@suri.co.jp>
Reply-To: zebra@zebra.org
To: zebra@zebra.org
Cc: kunihiro@zebra.org, yokota@kddlabs.co.jp
Subject: [zebra 16823] [PATCH] Bugfix and new feature in Opaque-LSA
handling.

----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * -----
Changes 2002.12.20

1. Bug fixes

  1.1 When an opaque LSA is being removed from (or added to) the LSDB,
      it does not mean a change in network topology. Therefore, SPF
      recalculation should not be triggered in that case.
      There was an assertion failure problem "assert (rn && rn->info)"
      inside the function "ospf_ase_incremental_update()", because
      the upper function "ospf_lsa_maxage_walker_remover()" called it
      when a type-11 opaque LSA is removed due to MaxAge.

  1.2 Type-9 LSA is defined to have "link-local" flooding scope.
      In the Database exchange procedure with a new neighbor, a type-9
      LSA was added in the database summary of a DD message, even if
      the link is different from the one that have bound to.

2. Feature enhancements

  2.1 Though a "wildcard" concept to handle type-9/10/11 LSAs altogether
      has introduced about a year ago, it was only a symbol definition
      and actual handling mechanism was not implemented. Now it works.
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index c2fade2..9a9942f 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2377,6 +2377,11 @@
       break;
 #ifdef HAVE_OPAQUE_LSA
     case OSPF_OPAQUE_LINK_LSA:
+      if (IS_LSA_SELF (lsa))
+          lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */
+      else
+          ; /* Incoming "oi" for this LSA has set at LSUpd reception. */
+      /* Fallthrough */
     case OSPF_OPAQUE_AREA_LSA:
     case OSPF_OPAQUE_AS_LSA:
       new = ospf_opaque_lsa_install (lsa, rt_recalc);
@@ -2611,21 +2616,32 @@
 
         switch (lsa->data->type)
           {
-          case OSPF_AS_EXTERNAL_LSA:
 #ifdef HAVE_OPAQUE_LSA
           case OSPF_OPAQUE_AS_LSA:
+          case OSPF_OPAQUE_LINK_LSA:
+          case OSPF_OPAQUE_AREA_LSA:
+            /*
+             * As a general rule, whenever network topology has changed
+             * (due to an LSA removal in this case), routing recalculation
+             * should be triggered. However, this is not true for opaque
+             * LSAs. Even if an opaque LSA instance is going to be removed
+             * from the routing domain, it does not mean a change in network
+             * topology, and thus, routing recalculation is not needed here.
+             */
+            break;
 #endif /* HAVE_OPAQUE_LSA */
 #ifdef HAVE_NSSA
-	  case OSPF_AS_NSSA_LSA:
+	      case OSPF_AS_NSSA_LSA:
 #endif
-	    ospf_ase_incremental_update (lsa, ospf_top);
-            break;
+          case OSPF_AS_EXTERNAL_LSA:
+	       ospf_ase_incremental_update (lsa, ospf_top);
+           break;
           default:
-	    ospf_spf_calculate_schedule ();
-            break;
+	       ospf_spf_calculate_schedule ();
+           break;
           }
 
-	ospf_lsa_maxage (lsa);
+	   ospf_lsa_maxage (lsa);
       }
 
   return 0;
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index cfb18a9..5730357 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -229,6 +229,26 @@
   if (lsa == NULL)
     return 0;
 
+#ifdef HAVE_OPAQUE_LSA
+  switch (lsa->data->type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+      /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
+      if (lsa->oi != nbr->oi)
+          return 0;
+      break;
+    case OSPF_OPAQUE_AREA_LSA:
+      /*
+       * It is assured by the caller function "nsm_negotiation_done()"
+       * that every given LSA belongs to the same area with "nbr".
+       */
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+    default:
+      break;
+    }
+#endif /* HAVE_OPAQUE_LSA */
+
 #ifdef HAVE_NSSA
   /* Stay away from any Local Translated Type-7 LSAs */
   if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 67c6608..5d5b30c 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -239,6 +239,7 @@
   int (* del_lsa_hook)(struct ospf_lsa *lsa);
 };
 
+static list ospf_opaque_wildcard_funclist; /* Handle LSA-9/10/11 altogether. */
 static list ospf_opaque_type9_funclist;
 static list ospf_opaque_type10_funclist;
 static list ospf_opaque_type11_funclist;
@@ -255,6 +256,9 @@
 {
   list funclist;
 
+  funclist = ospf_opaque_wildcard_funclist = list_new ();
+  funclist->del = ospf_opaque_del_functab;
+
   funclist = ospf_opaque_type9_funclist  = list_new ();
   funclist->del = ospf_opaque_del_functab;
 
@@ -271,6 +275,9 @@
 {
   list funclist;
 
+  funclist = ospf_opaque_wildcard_funclist;
+  list_delete (funclist);
+
   funclist = ospf_opaque_type9_funclist;
   list_delete (funclist);
 
@@ -289,6 +296,16 @@
 
   switch (lsa_type)
     {
+    case OPAQUE_TYPE_WILDCARD:
+      /* XXX
+       * This is an ugly trick to handle type-9/10/11 LSA altogether.
+       * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor
+       * an officially assigned opaque-type.
+       * Though it is possible that the value might be officially used
+       * in the future, we use it internally as a special label, for now.
+       */
+      funclist = ospf_opaque_wildcard_funclist;
+      break;
     case OSPF_OPAQUE_LINK_LSA:
       funclist = ospf_opaque_type9_funclist;
       break;
@@ -434,6 +451,7 @@
  */
 struct opaque_info_per_type
 {
+  u_char lsa_type;
   u_char opaque_type;
 
   enum { PROC_NORMAL, PROC_SUSPEND } status;
@@ -451,7 +469,7 @@
   struct thread *t_opaque_lsa_self;
 
   /*
-   * Backpointer to an "owner" which is opaque-type dependent.
+   * Backpointer to an "owner" which is LSA-type dependent.
    *   type-9:  struct ospf_interface
    *   type-10: struct ospf_area
    *   type-11: struct ospf
@@ -523,11 +541,13 @@
       listnode_add (top->opaque_lsa_self, oipt);
       break;
     default:
+      zlog_warn ("register_opaque_info_per_type: Unexpected LSA-type(%u)", new->data->type);
       free_opaque_info_per_type ((void *) oipt);
       oipt = NULL;
       goto out; /* This case may not exist. */
     }
 
+  oipt->lsa_type = new->data->type;
   oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr));
   oipt->status = PROC_NORMAL;
   oipt->t_opaque_lsa_self = NULL;
@@ -560,6 +580,32 @@
       ospf_opaque_lsa_flush_schedule (lsa);
     }
 
+  /* Remove "oipt" from its owner's self-originated LSA list. */
+  switch (oipt->lsa_type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+      {
+        struct ospf_interface *oi = (struct ospf_interface *)(oipt->owner);
+        listnode_delete (oi->opaque_lsa_self, oipt);
+        break;
+      }
+    case OSPF_OPAQUE_AREA_LSA:
+      {
+        struct ospf_area *area = (struct ospf_area *)(oipt->owner);
+        listnode_delete (area->opaque_lsa_self, oipt);
+        break;
+      }
+    case OSPF_OPAQUE_AS_LSA:
+      {
+        struct ospf *top = (struct ospf *)(oipt->owner);
+        listnode_delete (top->opaque_lsa_self, oipt);
+        break;
+      }
+    default:
+      zlog_warn ("free_opaque_info_per_type: Unexpected LSA-type(%u)", oipt->lsa_type);
+      break; /* This case may not exist. */
+    }
+
   OSPF_TIMER_OFF (oipt->t_opaque_lsa_self);
   list_delete (oipt->id_list);
   XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
@@ -923,6 +969,10 @@
   list funclist;
   int rc = -1;
 
+  funclist = ospf_opaque_wildcard_funclist;
+  if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+    goto out;
+
   funclist = ospf_opaque_type9_funclist;
   if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
     goto out;
@@ -946,6 +996,10 @@
   list funclist;
   int rc = -1;
 
+  funclist = ospf_opaque_wildcard_funclist;
+  if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+    goto out;
+
   funclist = ospf_opaque_type9_funclist;
   if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
     goto out;
@@ -968,6 +1022,9 @@
 {
   list funclist;
 
+  funclist = ospf_opaque_wildcard_funclist;
+  opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
   funclist = ospf_opaque_type9_funclist;
   opaque_lsa_ism_change_callback (funclist, oi, old_status);
 
@@ -1017,6 +1074,9 @@
       ;
     }
 
+  funclist = ospf_opaque_wildcard_funclist;
+  opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
   funclist = ospf_opaque_type9_funclist;
   opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
 
@@ -1038,6 +1098,9 @@
   if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
     vty_out (vty, " capability opaque%s", VTY_NEWLINE);
 
+  funclist = ospf_opaque_wildcard_funclist;
+  opaque_lsa_config_write_router_callback (funclist, vty);
+
   funclist = ospf_opaque_type9_funclist;
   opaque_lsa_config_write_router_callback (funclist, vty);
 
@@ -1055,6 +1118,9 @@
 {
   list funclist;
 
+  funclist = ospf_opaque_wildcard_funclist;
+  opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
   funclist = ospf_opaque_type9_funclist;
   opaque_lsa_config_write_if_callback (funclist, vty, ifp);
 
@@ -1072,6 +1138,9 @@
 {
   list funclist;
 
+  funclist = ospf_opaque_wildcard_funclist;
+  opaque_lsa_config_write_debug_callback (funclist, vty);
+
   funclist = ospf_opaque_type9_funclist;
   opaque_lsa_config_write_debug_callback (funclist, vty);
 
@@ -1142,6 +1211,10 @@
    * Some Opaque-LSA user may want to monitor every LSA installation
    * into the LSDB, regardless with target LSA type.
    */
+  funclist = ospf_opaque_wildcard_funclist;
+  if (new_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
   funclist = ospf_opaque_type9_funclist;
   if (new_lsa_callback (funclist, lsa) != 0)
     goto out;
@@ -1169,6 +1242,10 @@
    * Some Opaque-LSA user may want to monitor every LSA deletion
    * from the LSDB, regardless with target LSA type.
    */
+  funclist = ospf_opaque_wildcard_funclist;
+  if (del_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
   funclist = ospf_opaque_type9_funclist;
   if (del_lsa_callback (funclist, lsa) != 0)
     goto out;
@@ -1473,6 +1550,13 @@
   switch (lsa->data->type)
     {
     case OSPF_OPAQUE_LINK_LSA:
+      if ((top = oi_to_top (lsa->oi)) == NULL)
+        {
+          /* Above conditions must have passed. */
+          zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
+          goto out;
+        }
+      break;
     case OSPF_OPAQUE_AREA_LSA:
       if (lsa->area == NULL || (top = lsa->area->top) == NULL)
         {