[bgpd] Fix bug where FSM can stay hung forever in Idle/Clrng

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

	* bgp_route.c: (general) Fix logical bug in clearing, noted
	  by Chris Caputo in [quagga-users 6728] - clearing depended on
	  at least one route being added to workqueue, in order for
	  workqueue completion function to restart FSM. However, if no
	  routes are cleared, then the completion function never is
	  called, it needs to be called manually if the workqueue
	  didn't get scheduled.
	  Finally, clearing is per-peer-session, not per AFI/SAFI, so
	  the FSM synchronisation should be in bgp_clear_route_table.
	  (bgp_clear_route_table) Wrong place for FSM/clearing
	  synchronisation, move to..
	  (bgp_clear_route) FSM/clearing synchronisation should be
	  here.
	  If no routes were cleared, no workqueue scheduled, call
	  the completion func to ensure FSM kicks off again.
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index b49bea9..10c8869 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2555,6 +2555,25 @@
   /* If still no table => afi/safi isn't configured at all or smth. */
   if (! table)
     return;
+  
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    {
+      if (rn->info == NULL)
+        continue;
+      
+      bgp_lock_node (rn); /* unlocked: bgp_clear_node_queue_del */
+      work_queue_add (peer->clear_node_queue, rn);
+    }
+  return;
+}
+
+void
+bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct peer *rsclient;
+  struct listnode *node, *nnode;
 
   if (peer->clear_node_queue == NULL)
     bgp_clear_node_queue_init (peer);
@@ -2576,25 +2595,6 @@
       peer_lock (peer); /* bgp_clear_node_complete */
     }
   
-  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
-    {
-      if (rn->info == NULL)
-        continue;
-      
-      bgp_lock_node (rn); /* unlocked: bgp_clear_node_queue_del */
-      work_queue_add (peer->clear_node_queue, rn);
-    }
-  return;
-}
-
-void
-bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
-{
-  struct bgp_node *rn;
-  struct bgp_table *table;
-  struct peer *rsclient;
-  struct listnode *node, *nnode;
-
   if (safi != SAFI_MPLS_VPN)
     bgp_clear_route_table (peer, afi, safi, NULL, NULL);
   else
@@ -2608,6 +2608,12 @@
       if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
         bgp_clear_route_table (peer, afi, safi, NULL, rsclient);
     }
+  
+  /* If no routes were cleared, nothing was added to workqueue, run the
+   * completion function now.
+   */
+  if (!peer->clear_node_queue->thread)
+    bgp_clear_node_complete (peer->clear_node_queue);
 }
   
 void