[ospfd] Fix SPF of virtual-links

2006-04-24 Paul Jakma <paul.jakma@sun.com>

	* (general) More Virtual-link fixes, again with much help in
	  testing / debug from Juergen Kammer. Primarily in SPF.
	* ospf_spf.h: Add guard. ospf_interface.h will include this
	  header.
	* ospf_interface.h: Modify ospf_vl_lookup definition to take
	  struct ospf as argument, so as to allow for NULL area
	  argument.
	  (struct ospf_vl_data) Remove out_oi, instead add a struct
	  vertex_nexthop, to use as initial nexthop for backbone paths
	  through a vlink.
	* ospf_interface.c: (ospf_vl_lookup) Modified to allow
	  NULL area to be passed to indicate "any" (first) area.
	  Add extra debug.
	  (ospf_vl_set_params) vl_oi -> nexthop. Add extra debug.
	  (ospf_vl_up_check) Fix debug, inet_ntoa returns a static
	  buffer..
	* ospf_route.c: (ospf_intra_add_router) Vlinks dont go through
	  backbone, don't bother checking.
	* ospf_spf.c: (static struct list vertex_list) Record vertices
	  that will need to be freed.
	  (cmp) Order network before router vertices, as required,
	  wasn't implemented.
	  (vertex_nexthop_free) Mild additional robustness check.
	  (vertex_parent_free) Take void argument, as this function
	  is passed as list deconstructor for vertex parent list.
	  (ospf_vertex_new) More debug. Set deconstructor for parent
	  list. Track allocated vertices on the vertex_list.
	  (ospf_vertex_free) Get rid of the tricky recursive cleanup of
	  vertices. Now frees only the given vertex.
	  (ospf_vertex_add_parent) Fix assert.
	  (ospf_nexthop_calculation) Fix calculation of nexthop for
	  VLink vertices, lookup the vl_data and use its previously
	  recorded nexthop information.
	  (ospf_spf_calculate) Vertices are freed simply by deleting
	  vertex_list nodes and letting ospf_vertex_free as deconstructor
	  work per-node.
	  (ospf_spf_calculate_timer) Trivial optimisation, leave
	  backbone SPF calculation till last to reduce SPF churn on
	  VLink updates.
	* ospf_vty.c: (ospf_find_vl_data) update call to ospf_vl_lookup
	  (no_ospf_area_vlink_cmd) ditto.
	  (show_ip_ospf_interface_sub) For Vlinks, the peer address is
	  more interesting than the output interface.
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 52adc42..1264cac 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -931,16 +931,36 @@
   vlink_count--;
 }
 
+/* Look up vl_data for given peer, optionally qualified to be in the
+ * specified area. NULL area returns first found..
+ */
 struct ospf_vl_data *
-ospf_vl_lookup (struct ospf_area *area, struct in_addr vl_peer)
+ospf_vl_lookup (struct ospf *ospf, struct ospf_area *area,
+                struct in_addr vl_peer)
 {
   struct ospf_vl_data *vl_data;
   struct listnode *node;
-
-  for (ALL_LIST_ELEMENTS_RO (area->ospf->vlinks, node, vl_data))
-    if (vl_data->vl_peer.s_addr == vl_peer.s_addr &&
-        IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
-      return vl_data;
+  
+  if (IS_DEBUG_OSPF_EVENT)
+    {
+      zlog_debug ("%s: Looking for %s", __func__, inet_ntoa (vl_peer));
+      if (area)
+        zlog_debug ("%s: in area %s", __func__, inet_ntoa (area->area_id));
+    }
+  
+  for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_debug ("%s: VL %s, peer %s", __func__,
+                    vl_data->vl_oi->ifp->name,
+                    inet_ntoa (vl_data->vl_peer));
+      
+      if (area && !IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
+        continue;
+      
+      if (IPV4_ADDR_SAME (&vl_data->vl_peer, &vl_peer))
+        return vl_data;
+    }
 
   return NULL;
 }
@@ -1005,14 +1025,15 @@
 
   for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
     {
-      vl_data->out_oi = vp->nexthop->oi;
+      vl_data->nexthop.oi = vp->nexthop->oi;
+      vl_data->nexthop.router = vp->nexthop->router;
       
       if (!IPV4_ADDR_SAME(&voi->address->u.prefix4,
-                          &vl_data->out_oi->address->u.prefix4))
+                          &vl_data->nexthop.oi->address->u.prefix4))
         changed = 1;
         
-      voi->address->u.prefix4 = vl_data->out_oi->address->u.prefix4;
-      voi->address->prefixlen = vl_data->out_oi->address->prefixlen;
+      voi->address->u.prefix4 = vl_data->nexthop.oi->address->u.prefix4;
+      voi->address->prefixlen = vl_data->nexthop.oi->address->prefixlen;
 
       break; /* We take the first interface. */
     }
@@ -1050,19 +1071,16 @@
                                      &rl->link[i].link_data))
                   changed = 1;
                 vl_data->peer_addr = rl->link[i].link_data;
-              if (IS_DEBUG_OSPF_EVENT)
-                zlog_debug ("ospf_vl_set_params: %s peer address is %s\n",
-                               vl_data->vl_oi->ifp->name, 
-                               inet_ntoa(vl_data->peer_addr));
-              return changed;
             }
         }
     }
     
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_debug ("ospf_vl_set_params: %s peer address is %s\n",
+    zlog_debug ("%s: %s peer address: %s, cost: %d,%schanged", __func__,
                vl_data->vl_oi->ifp->name,
-               inet_ntoa(vl_data->peer_addr));
+               inet_ntoa(vl_data->peer_addr),
+               voi->output_cost,
+               (changed ? " " : " un"));
                
   return changed;
 }
@@ -1088,10 +1106,10 @@
     {
       if (IS_DEBUG_OSPF_EVENT)
 	{
-	  zlog_debug ("ospf_vl_up_check(): considering VL, name: %s", 
-		     vl_data->vl_oi->ifp->name);
-	  zlog_debug ("ospf_vl_up_check(): VL area: %s, peer ID: %s", 
-		     inet_ntoa (vl_data->vl_area_id),
+	  zlog_debug ("%s: considering VL, %s in area %s", __func__,
+		     vl_data->vl_oi->ifp->name,
+		     inet_ntoa (vl_data->vl_area_id));
+	  zlog_debug ("%s: peer ID: %s", __func__,
 		     inet_ntoa (vl_data->vl_peer));
 	}