[bgpd] Fix bug where a deleted route that was quickly re-added was being lost

2006-11-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>

	* bgp_route.c: (bgp_info_restore) New function that undoes
	  the effects of a previous call to bgp_info_delete.  This is
	  used when a route is deleted and quickly re-added before the
	  deletion has been processed.
	  (bgp_static_update_rsclient, bgp_static_update_main,
	  bgp_redistribute_add) Check whether a pre-existing route
	  has the BGP_INFO_REMOVED set, and, if so, we need to call
	  bgp_info_restore to resurrect it.
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index 2b40456..c862949 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,3 +1,14 @@
+2006-11-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
+
+	* bgp_route.c: (bgp_info_restore) New function that undoes
+	  the effects of a previous call to bgp_info_delete.  This is
+	  used when a route is deleted and quickly re-added before the
+	  deletion has been processed.
+	  (bgp_static_update_rsclient, bgp_static_update_main,
+	  bgp_redistribute_add) Check whether a pre-existing route
+	  has the BGP_INFO_REMOVED set, and, if so, we need to call
+	  bgp_info_restore to resurrect it.
+
 2006-10-27 Paul Jakma <paul.jakma@sun.com>
 
 	* bgp_route.c: (bgp_table_stats) oops, u_intXX_t should be
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 3cae06e..ce44842 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -192,6 +192,17 @@
   UNSET_FLAG (ri->flags, BGP_INFO_VALID);
 }
 
+/* undo the effects of a previous call to bgp_info_delete; typically
+   called when a route is deleted and then quickly re-added before the
+   deletion has been processed */
+static void
+bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri)
+{
+  bgp_info_unset_flag (rn, ri, BGP_INFO_REMOVED);
+  /* unset of previous already took care of pcount */
+  SET_FLAG (ri->flags, BGP_INFO_VALID);
+}
+
 /* Adjust pcount as required */   
 static void
 bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
@@ -3051,7 +3062,8 @@
 
   if (ri)
        {
-      if (attrhash_cmp (ri->attr, attr_new))
+      if (attrhash_cmp (ri->attr, attr_new) &&
+	  !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
         {
           bgp_unlock_node (rn);
           bgp_attr_unintern (attr_new);
@@ -3064,6 +3076,8 @@
           bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
 
           /* Rewrite BGP route information. */
+	  if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+	    bgp_info_restore(rn, ri);
           bgp_attr_unintern (ri->attr);
           ri->attr = attr_new;
           ri->uptime = time (NULL);
@@ -3158,7 +3172,8 @@
 
   if (ri)
     {
-      if (attrhash_cmp (ri->attr, attr_new))
+      if (attrhash_cmp (ri->attr, attr_new) &&
+	  !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
 	{
 	  bgp_unlock_node (rn);
 	  bgp_attr_unintern (attr_new);
@@ -3171,7 +3186,10 @@
 	  bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
 
 	  /* Rewrite BGP route information. */
-	  bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+	  if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+	    bgp_info_restore(rn, ri);
+	  else
+	    bgp_aggregate_decrement (bgp, p, ri, afi, safi);
 	  bgp_attr_unintern (ri->attr);
 	  ri->attr = attr_new;
 	  ri->uptime = time (NULL);
@@ -4952,7 +4970,8 @@
  
  	  if (bi)
  	    {
- 	      if (attrhash_cmp (bi->attr, new_attr))
+ 	      if (attrhash_cmp (bi->attr, new_attr) &&
+		  !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
  		{
  		  bgp_attr_unintern (new_attr);
  		  aspath_unintern (attr.aspath);
@@ -4965,7 +4984,10 @@
  		  bgp_info_set_flag (bn, bi, BGP_INFO_ATTR_CHANGED);
  
  		  /* Rewrite BGP route information. */
- 		  bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
+		  if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
+		    bgp_info_restore(bn, bi);
+		  else
+		    bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
  		  bgp_attr_unintern (bi->attr);
  		  bi->attr = new_attr;
  		  bi->uptime = time (NULL);