Rework of SPF threads schedule logic. I'm not 100% sure whether it's right
thing to do to have completely separate threads for IPv4 and IPv6 SPF
though. But it works and it's now possible to have both IPv4 and IPv6
enabled in interface. One bug fixed in LSP regeneration scheduling as well.
diff --git a/isisd/ChangeLog b/isisd/ChangeLog
index 1464c33..4bd3494 100644
--- a/isisd/ChangeLog
+++ b/isisd/ChangeLog
@@ -1,3 +1,11 @@
+2004-09-19 Hasso Tepper <hasso at quagga.net>
+
+	* isis_spf.h: Renamed t_spf_periodic to t_spf as it's not used to
+	  store pointer to periodic SPF thread only.
+	* isis_spf.c: Cleaned up SPF threads schedule code. IPv4 and IPv6
+	  threads are independant now. Used macros wherever possible.
+	* isis_lsp.c: Fixed bug in scheduling LSP regeneration.
+
 2004-09-17 LIU Xin <lx at ns.6test.edu.cn>
 	
 	* isis_circuit.c: According to RFC1142 the first DIS election will be
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 677e2c3..d52efb6 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -1895,7 +1895,7 @@
 	  area->lsp_regenerate_pending[0] = 1;
 	  thread_add_timer (master, lsp_l1_regenerate, area,
 			    MIN_LSP_GEN_INTERVAL - diff);
-	  return ISIS_OK;
+	  goto L2;
 	}
       else
 	lsp_non_pseudo_regenerate (area, 1);
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index bd79659..b2845ae 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1022,21 +1022,6 @@
   spftree->lastrun = time (NULL);
   spftree->pending = 0;
 
-  if (level == 1)
-    {
-      /* FIXME: Should do it earlier. */
-      spftree->t_spf_periodic = NULL;
-      THREAD_TIMER_ON (master, spftree->t_spf_periodic, isis_run_spf_l1, area,
-		       isis_jitter (PERIODIC_SPF_INTERVAL, 10));
-    }
-  else
-    {
-      /* FIXME: Should do it earlier. */
-      spftree->t_spf_periodic = NULL;
-      THREAD_TIMER_ON (master, spftree->t_spf_periodic, isis_run_spf_l2, area,
-		       isis_jitter (PERIODIC_SPF_INTERVAL, 10));
-    }
-
   return retval;
 }
 
@@ -1049,27 +1034,25 @@
   area = THREAD_ARG (thread);
   assert (area);
 
+  area->spftree[0]->t_spf = NULL;
+
   if (!(area->is_type & IS_LEVEL_1))
     {
       if (isis->debugs & DEBUG_SPF_EVENTS)
-	{
-	  zlog_warn ("ISIS-SPF (%s) area does not share level",
-		     area->area_tag);
-	}
+	zlog_warn ("ISIS-SPF (%s) area does not share level",
+		   area->area_tag);
       return ISIS_WARNING;
     }
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
-    {
-      zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
-    }
+    zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
 
   if (area->ip_circuits)
     retval = isis_run_spf (area, 1, AF_INET);
-#ifdef HAVE_IPV6
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 1, AF_INET6);
-#endif
+
+  THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area,
+		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+
   return retval;
 }
 
@@ -1082,27 +1065,23 @@
   area = THREAD_ARG (thread);
   assert (area);
 
+  area->spftree[1]->t_spf = NULL;
+
   if (!(area->is_type & IS_LEVEL_2))
     {
       if (isis->debugs & DEBUG_SPF_EVENTS)
-	{
-	  zlog_warn ("ISIS-SPF (%s) area does not share level",
-		     area->area_tag);
-	}
+	zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
       return ISIS_WARNING;
     }
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
-    {
-      zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
-    }
+    zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
 
   if (area->ip_circuits)
     retval = isis_run_spf (area, 2, AF_INET);
-#ifdef HAVE_IPV6
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 2, AF_INET6);
-#endif
+
+  THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area,
+		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 
   return retval;
 }
@@ -1123,25 +1102,24 @@
   if (now - isis->uptime < 60 || isis->uptime == 0)
     {
       if (level == 1)
-	thread_add_timer (master, isis_run_spf_l1, area, 60);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60);
       else
-	thread_add_timer (master, isis_run_spf_l2, area, 60);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60);
 
       spftree->pending = 1;
       return retval;
     }
-  /* FIXME: This stuff is just mess. All spf thread add/cancel
-     logic should be reviewed. */
-  THREAD_TIMER_OFF (spftree->t_spf_periodic);
+
+  THREAD_TIMER_OFF (spftree->t_spf);
 
   if (diff < MINIMUM_SPF_INTERVAL)
     {
       if (level == 1)
-	thread_add_timer (master, isis_run_spf_l1, area,
-			  MINIMUM_SPF_INTERVAL - diff);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
+			 MINIMUM_SPF_INTERVAL - diff);
       else
-	thread_add_timer (master, isis_run_spf_l2, area,
-			  MINIMUM_SPF_INTERVAL - diff);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
+			 MINIMUM_SPF_INTERVAL - diff);
 
       spftree->pending = 1;
     }
@@ -1149,6 +1127,12 @@
     {
       spftree->pending = 0;
       retval = isis_run_spf (area, level, AF_INET);
+      if (level == 1)
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
+			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+      else
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
+			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
     }
 
   return retval;
@@ -1156,6 +1140,66 @@
 
 #ifdef HAVE_IPV6
 int
+isis_run_spf6_l1 (struct thread *thread)
+{
+  struct isis_area *area;
+  int retval = ISIS_OK;
+
+  area = THREAD_ARG (thread);
+  assert (area);
+
+  area->spftree6[0]->t_spf = NULL;
+
+  if (!(area->is_type & IS_LEVEL_1))
+    {
+      if (isis->debugs & DEBUG_SPF_EVENTS)
+	zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
+      return ISIS_WARNING;
+    }
+
+  if (isis->debugs & DEBUG_SPF_EVENTS)
+    zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
+
+  if (area->ipv6_circuits)
+    retval = isis_run_spf (area, 1, AF_INET6);
+
+  THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area,
+		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+
+  return retval;
+}
+
+int
+isis_run_spf6_l2 (struct thread *thread)
+{
+  struct isis_area *area;
+  int retval = ISIS_OK;
+
+  area = THREAD_ARG (thread);
+  assert (area);
+
+  area->spftree6[1]->t_spf = NULL;
+
+  if (!(area->is_type & IS_LEVEL_2))
+    {
+      if (isis->debugs & DEBUG_SPF_EVENTS)
+        zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
+      return ISIS_WARNING;
+    }
+
+  if (isis->debugs & DEBUG_SPF_EVENTS)
+    zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
+
+  if (area->ipv6_circuits)
+    retval = isis_run_spf (area, 2, AF_INET6);
+
+  THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area,
+		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+
+  return retval;
+}
+
+int
 isis_spf_schedule6 (struct isis_area *area, int level)
 {
   int retval = ISIS_OK;
@@ -1167,29 +1211,28 @@
 
   diff = now - spftree->lastrun;
 
-  THREAD_TIMER_OFF (spftree->t_spf_periodic);
-
   /* FIXME: let's wait a minute before doing the SPF */
   if (now - isis->uptime < 60 || isis->uptime == 0)
     {
       if (level == 1)
-	thread_add_timer (master, isis_run_spf_l1, area, 60);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, 60);
       else
-	thread_add_timer (master, isis_run_spf_l2, area, 60);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, 60);
 
       spftree->pending = 1;
       return retval;
     }
-
+  
+  THREAD_TIMER_OFF (spftree->t_spf);
 
   if (diff < MINIMUM_SPF_INTERVAL)
     {
       if (level == 1)
-	thread_add_timer (master, isis_run_spf_l1, area,
-			  MINIMUM_SPF_INTERVAL - diff);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+			 MINIMUM_SPF_INTERVAL - diff);
       else
-	thread_add_timer (master, isis_run_spf_l2, area,
-			  MINIMUM_SPF_INTERVAL - diff);
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+			 MINIMUM_SPF_INTERVAL - diff);
 
       spftree->pending = 1;
     }
@@ -1197,11 +1240,17 @@
     {
       spftree->pending = 0;
       retval = isis_run_spf (area, level, AF_INET6);
+
+      if (level == 1)
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+      else
+	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
     }
 
   return retval;
 }
-
 #endif
 
 void
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index 432f846..8912add 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -60,7 +60,7 @@
 
 struct isis_spftree
 {
-  struct thread *t_spf_periodic;	/* periodic spf threads  */
+  struct thread *t_spf;		/* spf threads */
   time_t lastrun;		/* for scheduling */
   int pending;			/* already scheduled */
   struct list *paths;		/* the SPT */