[ospfd] Restructure opsf_if_update() and ospf_network_run()

    Add an struct interface paramenter and adjust the affected
    code accordingly.

    The old code was a mess looping over all interfaces several times
    when one interface was added/changed.

    * ospfd/ospfd.h: Add struct interface parameter to ospf_if_update()
    * ospfd/ospf_zebra.c: Add ifp arg to ospf_if_update() calls.
      (ospf_interface_address_delete) delete ospf_if_update() call,
      redundant as function calls ospf_if_free() itself.
    * ospfd/ospfd.c: (ospf_network_unset) handle deconfiguration here,
      rather than ospf_if_update.
      (ospf_network_run_interface) ospf_network_run, for
      any given interface.
      (ospf_network_run) move guts to previous, and use it.
      (ospf_if_update) Adjust to take struct interface as argument, as
      all callers have a specific ifp in mind.
      Iterate over ifp's connected list and call ospf_network_run_interface
      instead of ospf_network_run, turning this path into O(nm) rather
      than O(n^2).
      Adjust all code dealing with opsf_if_update and ospf_network_run to
      pass the new struct interface * arg.

     (some minor modifications and bug-additions by Paul Jakma).

Signed-off-by: Paul Jakma <paul@quagga.net>
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index f302d28..e27f139 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -87,7 +87,6 @@
 ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length)
 {
   struct interface *ifp;
-  struct ospf *ospf;
 
   ifp = zebra_interface_add_read (zclient->ibuf);
 
@@ -103,9 +102,7 @@
       IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp);
     }
 
-  ospf = ospf_lookup ();
-  if (ospf != NULL)
-    ospf_if_update (ospf);
+  ospf_if_update (NULL, ifp);
 
 #ifdef HAVE_SNMP
   ospf_snmp_if_update (ifp);
@@ -255,7 +252,6 @@
 ospf_interface_address_add (int command, struct zclient *zclient,
                             zebra_size_t length)
 {
-  struct ospf *ospf;
   struct connected *c;
 
   c = zebra_interface_address_read (command, zclient->ibuf);
@@ -270,9 +266,7 @@
       zlog_debug("Zebra: interface %s address add %s", c->ifp->name, buf);
     }
 
-  ospf = ospf_lookup ();
-  if (ospf != NULL)
-    ospf_if_update (ospf);
+  ospf_if_update (NULL, c->ifp);
 
 #ifdef HAVE_SNMP
   ospf_snmp_if_update (c->ifp);
@@ -285,7 +279,6 @@
 ospf_interface_address_delete (int command, struct zclient *zclient,
                                zebra_size_t length)
 {
-  struct ospf *ospf;
   struct connected *c;
   struct interface *ifp;
   struct ospf_interface *oi;
@@ -327,10 +320,6 @@
 
   connected_free (c);
 
-  ospf = ospf_lookup ();
-  if (ospf != NULL)
-    ospf_if_update (ospf);
-
   return 0;
 }
 
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index a4c4fac..32580cc 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -68,7 +68,9 @@
 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_network_run (struct prefix *, struct ospf_area *);
+static void ospf_network_run_interface (struct prefix *, struct ospf_area *,
+                                        struct interface *);
 static void ospf_finish_final (struct ospf *);
 
 #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1
@@ -78,6 +80,7 @@
 {
   struct in_addr router_id, router_id_old;
   struct ospf_interface *oi;
+  struct interface *ifp;
   struct listnode *node;
 
   if (IS_DEBUG_OSPF_EVENT)
@@ -130,7 +133,8 @@
 		     ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
       
       /* update ospf_interface's */
-      ospf_if_update (ospf);
+      for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp))
+        ospf_if_update (ospf, ifp);
     }
 }
 
@@ -745,7 +749,7 @@
   area = ospf_area_get (ospf, area_id, ret);
 
   /* Run network config now. */
-  ospf_network_run (ospf, (struct prefix *)p, area);
+  ospf_network_run ((struct prefix *)p, area);
 
   /* Update connected redistribute. */
   if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
@@ -770,6 +774,8 @@
   struct route_node *rn;
   struct ospf_network *network;
   struct external_info *ei;
+  struct listnode *node, *nnode;
+  struct ospf_interface *oi;
 
   rn = route_node_lookup (ospf->networks, (struct prefix *)p);
   if (rn == NULL)
@@ -783,7 +789,31 @@
   rn->info = NULL;
   route_unlock_node (rn);
 
-  ospf_if_update (ospf);
+  /* Find interfaces that not configured already.  */
+  for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
+    {
+      int found = 0;
+      struct connected *co = oi->connected;
+      
+      if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+        continue;
+      
+      for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
+        {
+          if (rn->info == NULL)
+            continue;
+          
+          if (ospf_network_match_iface(co,&rn->p))
+            {
+              found = 1;
+              route_unlock_node (rn);
+              break;
+            }
+        }
+
+      if (found == 0)
+        ospf_if_free (oi);
+    }
   
   /* Update connected redistribute. */
   if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
@@ -857,73 +887,78 @@
 }
 
 void
-ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area)
+ospf_network_run_interface (struct prefix *p, struct ospf_area *area,
+                            struct interface *ifp)
+{
+  struct listnode *cnode;
+  struct connected *co;
+  
+  if (memcmp (ifp->name, "VLINK", 5) == 0)
+    return;
+  
+  /* if interface prefix is match specified prefix,
+     then create socket and join multicast group. */
+  for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co))
+    {
+      struct prefix *addr;
+      
+      if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY))
+        continue;
+
+      addr = CONNECTED_ID(co);
+
+      if (p->family == co->address->family 
+          && ! ospf_if_is_configured (area->ospf, &(addr->u.prefix4))
+          && ospf_network_match_iface(co,p))
+        {
+           struct ospf_interface *oi;
+            
+            oi = ospf_if_new (area->ospf, ifp, co->address);
+            oi->connected = co;
+            
+            oi->area = area;
+
+            oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4);
+            oi->output_cost = ospf_if_get_output_cost (oi);
+            
+            /* Add pseudo neighbor. */
+            ospf_nbr_add_self (oi);
+
+            /* Relate ospf interface to ospf instance. */
+            oi->ospf = area->ospf;
+
+            /* update network type as interface flag */
+            /* If network type is specified previously,
+               skip network type setting. */
+            oi->type = IF_DEF_PARAMS (ifp)->type;
+            
+            ospf_area_add_if (oi->area, oi);
+            
+            /* if router_id is not configured, dont bring up
+             * interfaces.
+             * ospf_router_id_update() will call ospf_if_update
+             * whenever r-id is configured instead.
+             */
+            if ((area->ospf->router_id.s_addr != 0)
+                && if_is_operative (ifp)) 
+              ospf_if_up (oi);
+          }
+    }
+}
+
+void
+ospf_network_run (struct prefix *p, struct ospf_area *area)
 {
   struct interface *ifp;
-  struct connected *co;
   struct listnode *node;
 
   /* Schedule Router ID Update. */
-  if (ospf->router_id.s_addr == 0)
-    ospf_router_id_update (ospf);
+  if (area->ospf->router_id.s_addr == 0)
+    ospf_router_id_update (area->ospf);
   
   /* Get target interface. */
   for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp))
-    {
-      struct listnode *cnode;
-      
-      if (memcmp (ifp->name, "VLINK", 5) == 0)
-	continue;
-	
-      /* if interface prefix is match specified prefix,
-	 then create socket and join multicast group. */
-      for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co))
-	{
-	  struct prefix *addr;
-	  
-          if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY))
-            continue;
-
-	  addr = CONNECTED_ID(co);
-
-	  if (p->family == co->address->family 
-	      && ! ospf_if_is_configured (ospf, &(addr->u.prefix4))
-	      && ospf_network_match_iface(co,p))
-	    {
-	       struct ospf_interface *oi;
-		
-		oi = ospf_if_new (ospf, ifp, co->address);
-		oi->connected = co;
-		
-		oi->area = area;
-
-		oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4);
-		oi->output_cost = ospf_if_get_output_cost (oi);
-		
-		/* Add pseudo neighbor. */
-		ospf_nbr_add_self (oi);
-
-		/* Relate ospf interface to ospf instance. */
-		oi->ospf = ospf;
-
-		/* update network type as interface flag */
-		/* If network type is specified previously,
-		   skip network type setting. */
-		oi->type = IF_DEF_PARAMS (ifp)->type;
-		
-		ospf_area_add_if (oi->area, oi);
-		
-		/* if router_id is not configured, dont bring up
-		 * interfaces.
-                 * ospf_router_id_update() will call ospf_if_update
-                 * whenever r-id is configured instead.
-                 */
-		if ((ospf->router_id.s_addr != 0)
-		    && if_is_operative (ifp)) 
-		  ospf_if_up (oi);
-	      }
-	}
-    }
+    ospf_network_run_interface (p, area, ifp);
 }
 
 void
@@ -954,55 +989,27 @@
 }
 
 void
-ospf_if_update (struct ospf *ospf)
+ospf_if_update (struct ospf *ospf, struct interface *ifp)
 {
   struct route_node *rn;
-  struct listnode *node, *nnode;
   struct ospf_network *network;
   struct ospf_area *area;
-  struct ospf_interface *oi;
+  
+  if (!ospf)
+    ospf = ospf_lookup ();
 
-  if (ospf != NULL)
-    {
-      /* Router-ID must be configured. */
-      if (ospf->router_id.s_addr == 0)
-        return;
-      
-      /* Find interfaces that not configured already.  */
-      for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
-	{
-	  int found = 0;
-	  struct connected *co = oi->connected;
-	  
-	  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
-	    continue;
-	  
-	  for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
-	    {
-	      if (rn->info == NULL)
-		continue;
-	      
-	      if (ospf_network_match_iface(co,&rn->p))
-		{
-		  found = 1;
-		  route_unlock_node (rn);
-		  break;
-		}
-	    }
-
-	  if (found == 0)
-	    ospf_if_free (oi);
-	}
-	
-      /* Run each interface. */
-      for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
-	if (rn->info != NULL)
-	  {
-	    network = (struct ospf_network *) rn->info;
-	    area = ospf_area_get (ospf, network->area_id, network->format);
-	    ospf_network_run (ospf, &rn->p, area);
-	  }
-    }
+  /* Router-ID must be configured. */
+  if (ospf->router_id.s_addr == 0)
+    return;
+  
+  /* Run each netowrk for this interface. */
+  for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
+    if (rn->info != NULL)
+      {
+        network = (struct ospf_network *) rn->info;
+        area = ospf_area_get (ospf, network->area_id, network->format);
+        ospf_network_run_interface (&rn->p, area, ifp);
+      }
 }
 
 void
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index b618711..6a60e86 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -588,7 +588,7 @@
 extern int ospf_nbr_nbma_poll_interval_unset (struct ospf *, struct in_addr);
 extern void ospf_prefix_list_update (struct prefix_list *);
 extern void ospf_init (void);
-extern void ospf_if_update (struct ospf *);
+extern void ospf_if_update (struct ospf *, struct interface *);
 extern void ospf_ls_upd_queue_empty (struct ospf_interface *);
 extern void ospf_terminate (void);
 extern void ospf_nbr_nbma_if_update (struct ospf *, struct ospf_interface *);