bgpd: reduce struct attr_extra allocations/freeing

Try to use on stack structs for temporary uses.

Signed-off-by: Jorge Boncompte [DTI2] <jorge@dti2.net>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index b63ac4c..2d82acc 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -319,10 +319,14 @@
 void
 bgp_attr_dup (struct attr *new, struct attr *orig)
 {
+  struct attr_extra *extra = new->extra;
+
   *new = *orig;
   if (orig->extra)
     {
-      new->extra = bgp_attr_extra_new();
+      /* if caller provided attr_extra space use it */
+      if (! extra)
+        new->extra = bgp_attr_extra_new();
       *new->extra = *orig->extra;
     }
 }
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index a421fd7..c2045a8 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1051,8 +1051,11 @@
       || (ri->extra && ri->extra->suppress) )
     {
       struct bgp_info info;
-      struct attr dummy_attr = { 0 };
-      
+      struct attr dummy_attr;
+      struct attr_extra dummy_extra;
+
+      dummy_attr.extra = &dummy_extra;
+
       info.peer = peer;
       info.attr = attr;
 
@@ -1073,10 +1076,7 @@
 	ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info);
 
       peer->rmap_type = 0;
-      
-      if (dummy_attr.extra)
-        bgp_attr_extra_free (&dummy_attr);
-      
+
       if (ret == RMAP_DENYMATCH)
 	{
 	  bgp_attr_flush (attr);
@@ -1212,9 +1212,7 @@
   if (p->family == AF_INET6)
     {
       struct attr_extra *attre = attr->extra;
-      
-      assert (attr->extra);
-      
+
       /* Left nexthop_local unchanged if so configured. */
       if ( CHECK_FLAG (rsclient->af_flags[afi][safi], 
            PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) )
@@ -1429,7 +1427,8 @@
                                struct bgp_node *rn, afi_t afi, safi_t safi)
 {
   struct prefix *p;
-  struct attr attr = { 0 };
+  struct attr attr;
+  struct attr_extra extra;
 
   p = &rn->p;
 
@@ -1446,6 +1445,9 @@
       PEER_STATUS_ORF_WAIT_REFRESH))
     return 0;
 
+  /* It's initialized in bgp_announce_[check|check_rsclient]() */
+  attr.extra = &extra;
+
   switch (rn->table->type)
     {
       case BGP_TABLE_MAIN:
@@ -1466,9 +1468,7 @@
 	  bgp_adj_out_unset (rn, peer, p, afi, safi);
         break;
     }
-  
-  bgp_attr_extra_free (&attr);
-  
+
   return 0;
 }
 
@@ -1830,7 +1830,8 @@
 {
   struct bgp_node *rn;
   struct bgp *bgp;
-  struct attr new_attr = { 0 };
+  struct attr new_attr;
+  struct attr_extra new_extra;
   struct attr *attr_new;
   struct attr *attr_new2;
   struct bgp_info *ri;
@@ -1865,6 +1866,7 @@
       goto filtered;
     }
   
+  new_attr.extra = &new_extra;
   bgp_attr_dup (&new_attr, attr);
 
   /* Apply export policy. */
@@ -1902,10 +1904,7 @@
          goto filtered;
        }
     }
-  
-  /* new_attr isn't passed to any functions after here */
-  bgp_attr_extra_free (&new_attr);
-  
+
   /* If the update is implicit withdraw. */
   if (ri)
     {
@@ -1993,9 +1992,7 @@
   
   /* Process change. */
   bgp_process (bgp, rn, afi, safi);
-  
-  bgp_attr_extra_free (&new_attr);
-  
+
   return;
 
  filtered: 
@@ -2012,10 +2009,7 @@
     bgp_rib_remove (rn, ri, peer, afi, safi);
 
   bgp_unlock_node (rn);
-  
-  if (new_attr.extra)
-    bgp_attr_extra_free (&new_attr);
-  
+
   return;
 }
 
@@ -2060,7 +2054,8 @@
   int aspath_loop_count = 0;
   struct bgp_node *rn;
   struct bgp *bgp;
-  struct attr new_attr = { 0 };
+  struct attr new_attr;
+  struct attr_extra new_extra;
   struct attr *attr_new;
   struct bgp_info *ri;
   struct bgp_info *new;
@@ -2126,9 +2121,10 @@
       goto filtered;
     }
 
-  /* Apply incoming route-map. */
+  new_attr.extra = &new_extra;
   bgp_attr_dup (&new_attr, attr);
 
+  /* Apply incoming route-map. */
   if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY)
     {
       reason = "route-map;";
@@ -2207,8 +2203,7 @@
 
 	  bgp_unlock_node (rn);
 	  bgp_attr_unintern (&attr_new);
-	  bgp_attr_extra_free (&new_attr);
-	  
+
 	  return 0;
 	}
 
@@ -2269,7 +2264,6 @@
 	  if (ret == BGP_DAMP_SUPPRESSED)
 	    {
 	      bgp_unlock_node (rn);
-	      bgp_attr_extra_free (&new_attr);
 	      return 0;
 	    }
 	}
@@ -2295,8 +2289,7 @@
 
       bgp_process (bgp, rn, afi, safi);
       bgp_unlock_node (rn);
-      bgp_attr_extra_free (&new_attr);
-      
+
       return 0;
     }
 
@@ -2345,9 +2338,7 @@
   
   /* route_node_get lock */
   bgp_unlock_node (rn);
-  
-  bgp_attr_extra_free (&new_attr);
-  
+
   /* If maximum prefix count is configured and current prefix
      count exeed it. */
   if (bgp_maximum_prefix_overflow (peer, afi, safi, 0))
@@ -2372,9 +2363,7 @@
     bgp_rib_remove (rn, ri, peer, afi, safi);
 
   bgp_unlock_node (rn);
-  
-  bgp_attr_extra_free (&new_attr);
-  
+
   return 0;
 }
 
@@ -2550,8 +2539,9 @@
 {
   struct bgp_node *rn;
   struct bgp_info *ri;
-  struct attr attr = { 0 };
-  
+  struct attr attr;
+  struct attr_extra extra;
+
   if (! table)
     table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];
 
@@ -2559,6 +2549,9 @@
       && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
     bgp_default_originate (peer, afi, safi, 0);
 
+  /* It's initialized in bgp_announce_[check|check_rsclient]() */
+  attr.extra = &extra;
+
   for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn))
     for (ri = rn->info; ri; ri = ri->next)
       if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer)
@@ -2569,8 +2562,6 @@
 	    bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri);
 	  else
 	    bgp_adj_out_unset (rn, peer, &rn->p, afi, safi);
-          
-          bgp_attr_extra_free (&attr);
 	}
 }
 
@@ -3267,7 +3258,8 @@
   struct bgp_info info;
   struct attr *attr_new;
   struct attr attr;
-  struct attr new_attr = { 0 };
+  struct attr new_attr;
+  struct attr_extra new_extra;
   struct bgp *bgp;
   int ret;
   char buf[SU_ADDRSTRLEN];
@@ -3319,7 +3311,8 @@
     }
   else
     attr_new = bgp_attr_intern (&attr);
-  
+
+  new_attr.extra = &new_extra;
   bgp_attr_dup(&new_attr, attr_new);
   
   SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK);
@@ -3349,7 +3342,6 @@
 
   bgp_attr_unintern (&attr_new);
   attr_new = bgp_attr_intern (&new_attr);
-  bgp_attr_extra_free (&new_attr);
 
   for (ri = rn->info; ri; ri = ri->next)
     if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP
@@ -5349,7 +5341,6 @@
   struct bgp_info info;
   struct bgp_node *bn;
   struct attr attr;
-  struct attr attr_new = { 0 };
   struct attr *new_attr;
   afi_t afi;
   int ret;
@@ -5377,7 +5368,11 @@
 
       if (bgp->redist[afi][type])
 	{
+	  struct attr attr_new;
+	  struct attr_extra extra_new;
+
 	  /* Copy attribute for modification. */
+	  attr_new.extra = &extra_new;
 	  bgp_attr_dup (&attr_new, &attr);
 
 	  if (bgp->redist_metric_flag[afi][type])
@@ -5400,8 +5395,7 @@
 		{
 		  /* Free uninterned attribute. */
 		  bgp_attr_flush (&attr_new);
-		  bgp_attr_extra_free (&attr_new);
-		  
+
 		  /* Unintern original. */
 		  aspath_unintern (&attr.aspath);
 		  bgp_attr_extra_free (&attr);
@@ -5414,8 +5408,7 @@
                                  afi, SAFI_UNICAST, p, NULL);
           
 	  new_attr = bgp_attr_intern (&attr_new);
-	  bgp_attr_extra_free (&attr_new);
-	  
+
  	  for (bi = bn->info; bi; bi = bi->next)
  	    if (bi->peer == bgp->peer_self
  		&& bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
@@ -6183,17 +6176,17 @@
 	      {
 		struct route_map *rmap = output_arg;
 		struct bgp_info binfo;
-		struct attr dummy_attr = { 0 }; 
+		struct attr dummy_attr;
+		struct attr_extra dummy_extra;
 		int ret;
 
+		dummy_attr.extra = &dummy_extra;
 		bgp_attr_dup (&dummy_attr, ri->attr);
+
 		binfo.peer = ri->peer;
 		binfo.attr = &dummy_attr;
 
 		ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo);
-		
-		bgp_attr_extra_free (&dummy_attr);
-		
 		if (ret == RMAP_DENYMATCH)
 		  continue;
 	      }