[bgpd] Peer delete can race with reconfig leading to crash

2007-02-22 Paul Jakma <paul.jakma@sun.com>

	* bgp_fsm.c: (bgp_fsm_change_status) Handle state change into
	  clearing or greater here. Simpler.
	  (bgp_event) Clearing state change work moved to previous
	* bgp_route.c: (bgp_clear_route_node) Clearing adj-in here
	  is too late, as it leaves a race between a peer being deleted
	  and an identical peer being configured before clearing
	  completes, leading to a crash.
	  Simplest fix is to clean peers Adj-in up-front, rather than
	  queueing such work.
	  (bgp_clear_route_table) Clear peer's Adj-In and Adj-Out
	  up-front here, rather than queueing such work.
	  Extensive comment added on the various bits of indexed data
	  that exist and how they need to be dealt with.
	  (bgp_clear_route) Update comment.
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index d704c29..db7e69a 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -409,10 +409,16 @@
 {
   bgp_dump_state (peer, peer->status, status);
 
+  /* Transition into Clearing or Deleted must /always/ clear all routes.. 
+   * (and must do so before actually changing into Deleted..
+   */
+  if (status >= Clearing)
+    bgp_clear_route_all (peer);
+  
   /* Preserve old status and change into new status. */
   peer->ostatus = peer->status;
   peer->status = status;
-
+  
   if (BGP_DEBUG (normal, NORMAL))
     zlog_debug ("%s went from %s to %s",
 		peer->host,
@@ -1089,13 +1095,7 @@
     {
       /* If status is changed. */
       if (next != peer->status)
-        {
-          /* Transition into Clearing must /always/ clear all routes.. */
-          if (next == Clearing)
-            bgp_clear_route_all (peer);
-          
-          bgp_fsm_change_status (peer, next);
-        }
+        bgp_fsm_change_status (peer, next);
       
       /* Make sure timer is set. */
       bgp_timer_set (peer);