diff options
Diffstat (limited to 'bgpd')
-rw-r--r-- | bgpd/bgp_aspath.c | 1 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 34 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_clist.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_clist.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_community.c | 7 | ||||
-rw-r--r-- | bgpd/bgp_community.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_dump.c | 7 | ||||
-rw-r--r-- | bgpd/bgp_dump.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.c | 7 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_filter.c | 31 | ||||
-rw-r--r-- | bgpd/bgp_filter.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_main.c | 109 | ||||
-rw-r--r-- | bgpd/bgp_nexthop.c | 28 | ||||
-rw-r--r-- | bgpd/bgp_nexthop.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 164 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 12 | ||||
-rw-r--r-- | bgpd/bgp_table.c | 44 | ||||
-rw-r--r-- | bgpd/bgp_table.h | 8 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 18 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 2 | ||||
-rw-r--r-- | bgpd/bgpd.c | 62 |
24 files changed, 435 insertions, 110 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 002fff9f..13f32b86 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1799,6 +1799,7 @@ void aspath_finish (void) { hash_free (ashash); + ashash = NULL; if (snmp_stream) stream_free (snmp_stream); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 82d907e2..94168372 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -148,6 +148,7 @@ cluster_free (struct cluster_list *cluster) XFREE (MTYPE_CLUSTER, cluster); } +#if 0 static struct cluster_list * cluster_dup (struct cluster_list *cluster) { @@ -166,6 +167,7 @@ cluster_dup (struct cluster_list *cluster) return new; } +#endif static struct cluster_list * cluster_intern (struct cluster_list *cluster) @@ -198,6 +200,13 @@ cluster_init (void) { cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); } + +static void +cluster_finish (void) +{ + hash_free (cluster_hash); + cluster_hash = NULL; +} /* Unknown transit attribute. */ static struct hash *transit_hash; @@ -278,6 +287,13 @@ transit_init (void) { transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); } + +static void +transit_finish (void) +{ + hash_free (transit_hash); + transit_hash = NULL; +} /* Attribute hash routines. */ static struct hash *attrhash; @@ -436,6 +452,13 @@ attrhash_init (void) } static void +attrhash_finish (void) +{ + hash_free (attrhash); + attrhash = NULL; +} + +static void attr_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct attr *attr = backet->data; @@ -2302,6 +2325,17 @@ bgp_attr_init (void) transit_init (); } +void +bgp_attr_finish (void) +{ + aspath_finish (); + attrhash_finish (); + community_finish (); + ecommunity_finish (); + cluster_finish (); + transit_finish (); +} + /* Make attribute packet. */ void bgp_dump_routes_attr (struct stream *s, struct attr *attr, diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 12149a17..ed8753bd 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -140,6 +140,7 @@ struct transit /* Prototypes. */ extern void bgp_attr_init (void); +extern void bgp_attr_finish (void); extern int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); extern int bgp_attr_check (struct peer *, struct attr *); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 8d8c90c4..d6601674 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -829,7 +829,7 @@ community_list_init (void) } /* Terminate community-list. */ -static void +void community_list_terminate (struct community_list_handler *ch) { struct community_list_master *cm; diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 6d7e363e..5dcb3b4c 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -125,6 +125,7 @@ extern struct community_list_handler *bgp_clist; /* Prototypes. */ extern struct community_list_handler *community_list_init (void); +extern void community_list_terminate (struct community_list_handler *); extern int community_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index d40d69a2..ae1d7a15 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -636,3 +636,10 @@ community_init (void) comhash = hash_create ((unsigned int (*) (void *))community_hash_make, (int (*) (const void *, const void *))community_cmp); } + +void +community_finish (void) +{ + hash_free (comhash); + comhash = NULL; +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index aed7f330..bc1e56ef 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -52,6 +52,7 @@ struct community /* Prototypes of communities attribute functions. */ extern void community_init (void); +extern void community_finish (void); extern void community_free (struct community *); extern struct community *community_uniq_sort (struct community *); extern struct community *community_parse (u_int32_t *, u_short); diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 53dea805..8087a403 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -865,3 +865,10 @@ bgp_dump_init (void) install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); } + +void +bgp_dump_finish (void) +{ + stream_free (bgp_dump_obuf); + bgp_dump_obuf = NULL; +} diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h index 6bb1197b..e097c784 100644 --- a/bgpd/bgp_dump.h +++ b/bgpd/bgp_dump.h @@ -48,6 +48,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 2 extern void bgp_dump_init (void); +extern void bgp_dump_finish (void); extern void bgp_dump_state (struct peer *, int, int); extern void bgp_dump_packet (struct peer *, int, struct stream *); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 6152a1db..8d5fa741 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -262,6 +262,13 @@ ecommunity_init (void) { ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); } + +void +ecommunity_finish (void) +{ + hash_free (ecomhash); + ecomhash = NULL; +} /* Extended Communities token enum. */ enum ecommunity_token diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 5c8deb56..942fdc73 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -66,6 +66,7 @@ struct ecommunity_val #define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE) extern void ecommunity_init (void); +extern void ecommunity_finish (void); extern void ecommunity_free (struct ecommunity *); extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short); extern struct ecommunity *ecommunity_dup (struct ecommunity *); diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index bdb756cb..8ee62b01 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -181,6 +181,11 @@ as_list_new (void) static void as_list_free (struct as_list *aslist) { + if (aslist->name) + { + free (aslist->name); + aslist->name = NULL; + } XFREE (MTYPE_AS_LIST, aslist); } @@ -198,6 +203,7 @@ as_list_insert (const char *name) /* Allocate new access_list and copy given name. */ aslist = as_list_new (); aslist->name = strdup (name); + assert (aslist->name); /* If name is made by all digit character. We treat it as number. */ @@ -693,3 +699,28 @@ bgp_filter_init (void) install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd); install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd); } + +void +bgp_filter_reset (void) +{ + struct as_list *aslist; + struct as_list *next; + + for (aslist = as_list_master.num.head; aslist; aslist = next) + { + next = aslist->next; + as_list_delete (aslist); + } + + for (aslist = as_list_master.str.head; aslist; aslist = next) + { + next = aslist->next; + as_list_delete (aslist); + } + + assert (as_list_master.num.head == NULL); + assert (as_list_master.num.tail == NULL); + + assert (as_list_master.str.head == NULL); + assert (as_list_master.str.tail == NULL); +} diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index d389f165..8c27a930 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -28,6 +28,7 @@ enum as_filter_type }; extern void bgp_filter_init (void); +extern void bgp_filter_reset (void); extern enum as_filter_type as_list_apply (struct as_list *, void *); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 620ca128..9d14683c 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -31,10 +31,22 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "privs.h" #include "sigevent.h" +#include "zclient.h" +#include "routemap.h" +#include "filter.h" +#include "plist.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_filter.h" /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = @@ -61,6 +73,8 @@ void sighup (void); void sigint (void); void sigusr1 (void); +static void bgp_exit (int); + static struct quagga_signal_t bgp_signals[] = { { @@ -182,7 +196,7 @@ sigint (void) if (! retain_mode) bgp_terminate (); - exit (0); + bgp_exit (0); } /* SIGUSR1 handler. */ @@ -191,6 +205,99 @@ sigusr1 (void) { zlog_rotate (NULL); } + +/* + Try to free up allocations we know about so that diagnostic tools such as + valgrind are able to better illuminate leaks. + + Zebra route removal and protocol teardown are not meant to be done here. + For example, "retain_mode" may be set. +*/ +static void +bgp_exit (int status) +{ + struct bgp *bgp; + struct listnode *node, *nnode; + int *socket; + struct interface *ifp; + extern struct zclient *zclient; + extern struct zclient *zlookup; + + /* it only makes sense for this to be called on a clean exit */ + assert (status == 0); + + /* reverse bgp_master_init */ + for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) + bgp_delete (bgp); + list_free (bm->bgp); + + /* reverse bgp_master_init */ + for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket)) + { + if (close ((int)(long)socket) == -1) + zlog_err ("close (%d): %s", (int)(long)socket, safe_strerror (errno)); + } + list_delete (bm->listen_sockets); + + /* reverse bgp_zebra_init/if_init */ + if (retain_mode) + if_add_hook (IF_DELETE_HOOK, NULL); + for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) + if_delete (ifp); + list_free (iflist); + + /* reverse bgp_attr_init */ + bgp_attr_finish (); + + /* reverse bgp_dump_init */ + bgp_dump_finish (); + + /* reverse bgp_route_init */ + bgp_route_finish (); + + /* reverse bgp_route_map_init/route_map_init */ + route_map_finish (); + + /* reverse bgp_scan_init */ + bgp_scan_finish (); + + /* reverse access_list_init */ + access_list_add_hook (NULL); + access_list_delete_hook (NULL); + access_list_reset (); + + /* reverse bgp_filter_init */ + as_list_add_hook (NULL); + as_list_delete_hook (NULL); + bgp_filter_reset (); + + /* reverse prefix_list_init */ + prefix_list_add_hook (NULL); + prefix_list_delete_hook (NULL); + prefix_list_reset (); + + /* reverse community_list_init */ + community_list_terminate (bgp_clist); + + cmd_terminate (); + vty_terminate (); + if (zclient) + zclient_free (zclient); + if (zlookup) + zclient_free (zlookup); + + /* reverse bgp_master_init */ + if (master) + thread_master_free (master); + + if (zlog_default) + closezlog (zlog_default); + + if (CONF_BGP_DEBUG (normal, NORMAL)) + log_memstats_stderr ("bgpd"); + + exit (status); +} /* Main routine of bgpd. Treatment of argument and start bgp finite state machine is handled at here. */ diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 67a49f7a..0cde665e 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -65,7 +65,7 @@ static struct bgp_table *cache2_table[AFI_MAX]; static struct bgp_table *bgp_connected_table[AFI_MAX]; /* BGP nexthop lookup query client. */ -static struct zclient *zlookup = NULL; +struct zclient *zlookup = NULL; /* Add nexthop to the end of the list. */ static void @@ -1281,8 +1281,6 @@ bgp_scan_init (void) { zlookup = zclient_new (); zlookup->sock = -1; - zlookup->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); - zlookup->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; @@ -1314,3 +1312,27 @@ bgp_scan_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); } + +void +bgp_scan_finish (void) +{ + bgp_table_unlock (cache1_table[AFI_IP]); + cache1_table[AFI_IP] = NULL; + + bgp_table_unlock (cache2_table[AFI_IP]); + cache2_table[AFI_IP] = NULL; + + bgp_table_unlock (bgp_connected_table[AFI_IP]); + bgp_connected_table[AFI_IP] = NULL; + +#ifdef HAVE_IPV6 + bgp_table_unlock (cache1_table[AFI_IP6]); + cache1_table[AFI_IP6] = NULL; + + bgp_table_unlock (cache2_table[AFI_IP6]); + cache2_table[AFI_IP6] = NULL; + + bgp_table_unlock (bgp_connected_table[AFI_IP6]); + bgp_connected_table[AFI_IP6] = NULL; +#endif /* HAVE_IPV6 */ +} diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index a8b92df6..2dad742f 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -47,6 +47,7 @@ struct bgp_nexthop_cache }; extern void bgp_scan_init (void); +extern void bgp_scan_finish (void); extern int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, int *, int *); extern void bgp_connected_add (struct connected *c); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d98b689a..1c9a3c91 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2193,7 +2193,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) peer->afc_nego[afi][safi] = 0; if (peer_active_nego (peer)) - bgp_clear_route (peer, afi, safi); + bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); else BGP_EVENT_ADD (peer, BGP_Stop); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 87fe7f5c..8dafd181 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1464,11 +1464,9 @@ bgp_process_rsclient (struct work_queue *wq, void *data) struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; - struct attr attr; struct listnode *node, *nnode; struct peer *rsclient = rn->table->owner; - memset (&attr, 0, sizeof (struct attr)); /* Best path selection. */ bgp_best_selection (bgp, rn, &old_and_new); new_select = old_and_new.new; @@ -1476,23 +1474,25 @@ bgp_process_rsclient (struct work_queue *wq, void *data) if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) { - for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, rsclient)) - { - /* Nothing to do. */ - if (old_select && old_select == new_select) - if (!CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) - continue; - - if (old_select) - bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); - if (new_select) - { - bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); - bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); - } - - bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); - } + if (rsclient->group) + for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, rsclient)) + { + /* Nothing to do. */ + if (old_select && old_select == new_select) + if (!CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) + continue; + + if (old_select) + bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); + if (new_select) + { + bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); + bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); + } + + bgp_process_announce_selected (rsclient, new_select, rn, + afi, safi); + } } else { @@ -1509,8 +1509,6 @@ bgp_process_rsclient (struct work_queue *wq, void *data) if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); - bgp_attr_extra_free (&attr); - UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1593,9 +1591,11 @@ static void bgp_processq_del (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; + struct bgp_table *table = pq->rn->table; - bgp_unlock(pq->bgp); + bgp_unlock (pq->bgp); bgp_unlock_node (pq->rn); + bgp_table_unlock (table); XFREE (MTYPE_BGP_PROCESS_QUEUE, pq); } @@ -1641,10 +1641,12 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) sizeof (struct bgp_process_queue)); if (!pqnode) return; - - pqnode->rn = bgp_lock_node (rn); /* unlocked by bgp_processq_del */ + + /* all unlocked in bgp_processq_del */ + bgp_table_lock (rn->table); + pqnode->rn = bgp_lock_node (rn); pqnode->bgp = bgp; - bgp_lock(bgp); + bgp_lock (bgp); pqnode->afi = afi; pqnode->safi = safi; @@ -1805,8 +1807,6 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, const char *reason; char buf[SU_ADDRSTRLEN]; - //memset (new_attr, 0, sizeof (struct attr)); - /* Do not insert announces from a rsclient into its own 'bgp_table'. */ if (peer == rsclient) return; @@ -1894,10 +1894,10 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); - bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); + bgp_unlock_node (rn); + bgp_attr_unintern (attr_new); - return; + return; } /* Withdraw/Announce before we fully processed the withdraw */ @@ -1992,13 +1992,13 @@ static void bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct peer *peer, struct prefix *p, int type, int sub_type, struct prefix_rd *prd, u_char *tag) - { +{ struct bgp_node *rn; struct bgp_info *ri; char buf[SU_ADDRSTRLEN]; if (rsclient == peer) - return; + return; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); @@ -2017,8 +2017,8 @@ bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, p->prefixlen); /* Unlock bgp_node_get() lock. */ - bgp_unlock_node (rn); - } + bgp_unlock_node (rn); +} static int bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, @@ -2432,7 +2432,7 @@ void bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) { struct bgp *bgp; - struct attr attr; + struct attr attr = { 0 }; struct aspath *aspath = { 0 }; struct prefix p; struct bgp_info binfo; @@ -2521,9 +2521,7 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, { struct bgp_node *rn; struct bgp_info *ri; - struct attr attr; - - memset (&attr, 0, sizeof (struct attr)); + struct attr attr = { 0 }; if (! table) table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; @@ -2667,10 +2665,18 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) bgp_soft_reconfig_table (peer, afi, safi, table); } + +struct bgp_clear_node_queue +{ + struct bgp_node *rn; + enum bgp_clear_route_type purpose; +}; + static wq_item_status bgp_clear_route_node (struct work_queue *wq, void *data) { - struct bgp_node *rn = data; + struct bgp_clear_node_queue *cnq = data; + struct bgp_node *rn = cnq->rn; struct peer *peer = wq->spec.data; struct bgp_info *ri; afi_t afi = rn->table->afi; @@ -2679,7 +2685,7 @@ bgp_clear_route_node (struct work_queue *wq, void *data) assert (rn && peer); for (ri = rn->info; ri; ri = ri->next) - if (ri->peer == peer) + if (ri->peer == peer || cnq->purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { /* graceful restart STALE flag set. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) @@ -2697,9 +2703,13 @@ bgp_clear_route_node (struct work_queue *wq, void *data) static void bgp_clear_node_queue_del (struct work_queue *wq, void *data) { - struct bgp_node *rn = data; + struct bgp_clear_node_queue *cnq = data; + struct bgp_node *rn = cnq->rn; + struct bgp_table *table = rn->table; bgp_unlock_node (rn); + bgp_table_unlock (table); + XFREE (MTYPE_BGP_CLEAR_NODE_QUEUE, cnq); } static void @@ -2707,10 +2717,10 @@ bgp_clear_node_complete (struct work_queue *wq) { struct peer *peer = wq->spec.data; - peer_unlock (peer); /* bgp_clear_node_complete */ - /* Tickle FSM to start moving again */ BGP_EVENT_ADD (peer, Clearing_Completed); + + peer_unlock (peer); /* bgp_clear_route */ } static void @@ -2739,7 +2749,8 @@ bgp_clear_node_queue_init (struct peer *peer) static void bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, - struct bgp_table *table, struct peer *rsclient) + struct bgp_table *table, struct peer *rsclient, + enum bgp_clear_route_type purpose) { struct bgp_node *rn; @@ -2792,21 +2803,30 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, * problem at this time, */ for (ri = rn->info; ri; ri = ri->next) - if (ri->peer == peer) + if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { - bgp_lock_node (rn); /* unlocked: bgp_clear_node_queue_del */ - work_queue_add (peer->clear_node_queue, rn); + struct bgp_clear_node_queue *cnq; + + /* both unlocked in bgp_clear_node_queue_del */ + bgp_table_lock (rn->table); + bgp_lock_node (rn); + cnq = XCALLOC (MTYPE_BGP_CLEAR_NODE_QUEUE, + sizeof (struct bgp_clear_node_queue)); + cnq->rn = rn; + cnq->purpose = purpose; + work_queue_add (peer->clear_node_queue, cnq); + break; } for (ain = rn->adj_in; ain; ain = ain->next) - if (ain->peer == peer) + if (ain->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { bgp_adj_in_remove (rn, ain); bgp_unlock_node (rn); break; } for (aout = rn->adj_out; aout; aout = aout->next) - if (aout->peer == peer) + if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { bgp_adj_out_remove (rn, aout, peer, afi, safi); bgp_unlock_node (rn); @@ -2817,7 +2837,8 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, } void -bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) +bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, + enum bgp_clear_route_type purpose) { struct bgp_node *rn; struct bgp_table *table; @@ -2841,19 +2862,31 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) */ if (!peer->clear_node_queue->thread) peer_lock (peer); /* bgp_clear_node_complete */ - - if (safi != SAFI_MPLS_VPN) - bgp_clear_route_table (peer, afi, safi, NULL, NULL); - else - for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; - rn = bgp_route_next (rn)) - if ((table = rn->info) != NULL) - bgp_clear_route_table (peer, afi, safi, table, NULL); - for (ALL_LIST_ELEMENTS (peer->bgp->rsclient, node, nnode, rsclient)) + switch (purpose) { - if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) - bgp_clear_route_table (peer, afi, safi, NULL, rsclient); + case BGP_CLEAR_ROUTE_NORMAL: + if (safi != SAFI_MPLS_VPN) + bgp_clear_route_table (peer, afi, safi, NULL, NULL, purpose); + else + for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + if ((table = rn->info) != NULL) + bgp_clear_route_table (peer, afi, safi, table, NULL, purpose); + + for (ALL_LIST_ELEMENTS (peer->bgp->rsclient, node, nnode, rsclient)) + if (CHECK_FLAG(rsclient->af_flags[afi][safi], + PEER_FLAG_RSERVER_CLIENT)) + bgp_clear_route_table (peer, afi, safi, NULL, rsclient, purpose); + break; + + case BGP_CLEAR_ROUTE_MY_RSCLIENT: + bgp_clear_route_table (peer, afi, safi, NULL, peer, purpose); + break; + + default: + assert (0); + break; } /* If no routes were cleared, nothing was added to workqueue, the @@ -2887,7 +2920,7 @@ bgp_clear_route_all (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) - bgp_clear_route (peer, afi, safi); + bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); } void @@ -12276,3 +12309,10 @@ bgp_route_init (void) install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); } + +void +bgp_route_finish (void) +{ + bgp_table_unlock (bgp_distance_table); + bgp_distance_table = NULL; +} diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e5987972..5eed3486 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -61,7 +61,7 @@ struct bgp_info time_t uptime; /* reference count */ - unsigned int lock; + int lock; /* BGP information status. */ u_int16_t flags; @@ -160,8 +160,15 @@ struct bgp_static #define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) #define UNSUPPRESS_MAP(F) ((F)->usmap.map) +enum bgp_clear_route_type +{ + BGP_CLEAR_ROUTE_NORMAL, + BGP_CLEAR_ROUTE_MY_RSCLIENT +}; + /* Prototypes. */ extern void bgp_route_init (void); +extern void bgp_route_finish (void); extern void bgp_cleanup_routes (void); extern void bgp_announce_route (struct peer *, afi_t, safi_t); extern void bgp_announce_route_all (struct peer *); @@ -169,7 +176,8 @@ extern void bgp_default_originate (struct peer *, afi_t, safi_t, int); extern void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); extern void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t); extern void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi); -extern void bgp_clear_route (struct peer *, afi_t, safi_t); +extern void bgp_clear_route (struct peer *, afi_t, safi_t, + enum bgp_clear_route_type); extern void bgp_clear_route_all (struct peer *); extern void bgp_clear_adj_in (struct peer *, afi_t, safi_t); extern void bgp_clear_stale_route (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 66332567..5b8c6a49 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -38,6 +38,7 @@ bgp_table_init (afi_t afi, safi_t safi) rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); + bgp_table_lock(rt); rt->type = BGP_TABLE_MAIN; rt->afi = afi; rt->safi = safi; @@ -46,10 +47,29 @@ bgp_table_init (afi_t afi, safi_t safi) } void +bgp_table_lock (struct bgp_table *rt) +{ + rt->lock++; +} + +void +bgp_table_unlock (struct bgp_table *rt) +{ + assert (rt->lock > 0); + rt->lock--; + + if (rt->lock == 0) + bgp_table_free (rt); +} + +void bgp_table_finish (struct bgp_table **rt) { - bgp_table_free (*rt); - *rt = NULL; + if (*rt != NULL) + { + bgp_table_unlock(*rt); + *rt = NULL; + } } static struct bgp_node * @@ -91,6 +111,9 @@ bgp_table_free (struct bgp_table *rt) node = rt->top; + /* Bulk deletion of nodes remaining in this table. This function is not + called until workers have completed their dependency on this table. + A final bgp_unlock_node() will not be called for these nodes. */ while (node) { if (node->l_left) @@ -108,22 +131,31 @@ bgp_table_free (struct bgp_table *rt) tmp_node = node; node = node->parent; + tmp_node->table->count--; + tmp_node->lock = 0; /* to cause assert if unlocked after this */ + bgp_node_free (tmp_node); + if (node != NULL) { if (node->l_left == tmp_node) node->l_left = NULL; else node->l_right = NULL; - - bgp_node_free (tmp_node); } else { - bgp_node_free (tmp_node); break; } } + assert (rt->count == 0); + + if (rt->owner) + { + peer_unlock (rt->owner); + rt->owner = NULL; + } + XFREE (MTYPE_BGP_TABLE, rt); return; } @@ -217,6 +249,7 @@ bgp_lock_node (struct bgp_node *node) void bgp_unlock_node (struct bgp_node *node) { + assert (node->lock > 0); node->lock--; if (node->lock == 0) @@ -344,6 +377,7 @@ bgp_node_get (struct bgp_table *const table, struct prefix *p) if (new->p.prefixlen != p->prefixlen) { match = new; + bgp_lock_node (match); new = bgp_node_set (table, p); set_link (match, new); table->count++; diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index dfa7e1f3..53df0bc6 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -35,8 +35,10 @@ struct bgp_table afi_t afi; safi_t safi; + int lock; + /* The owner of this 'bgp_table' structure. */ - void *owner; + struct peer *owner; struct bgp_node *top; @@ -61,13 +63,15 @@ struct bgp_node struct bgp_node *prn; - unsigned int lock; + int lock; u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) }; extern struct bgp_table *bgp_table_init (afi_t, safi_t); +extern void bgp_table_lock (struct bgp_table *); +extern void bgp_table_unlock (struct bgp_table *); extern void bgp_table_finish (struct bgp_table **); extern void bgp_unlock_node (struct bgp_node *node); extern struct bgp_node *bgp_table_top (const struct bgp_table *const); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e97b4c97..13c37b57 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2074,6 +2074,7 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str, struct listnode *node, *nnode; struct bgp_filter *pfilter; struct bgp_filter *gfilter; + int locked_and_added = 0; bgp = vty->index; @@ -2089,15 +2090,25 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str, { peer = peer_lock (peer); /* rsclient peer list reference */ listnode_add_sort (bgp->rsclient, peer); + locked_and_added = 1; } ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) - return bgp_vty_return (vty, ret); + { + if (locked_and_added) + { + listnode_delete (bgp->rsclient, peer); + peer_unlock (peer); /* rsclient peer list reference */ + } + + return bgp_vty_return (vty, ret); + } peer->rib[afi][safi] = bgp_table_init (afi, safi); peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT; - peer->rib[afi][safi]->owner = peer; + /* RIB peer reference. Released when table is free'd in bgp_table_free. */ + peer->rib[afi][safi]->owner = peer_lock (peer); /* Check for existing 'network' and 'redistribute' routes. */ bgp_check_local_routes_rsclient (peer, afi, safi); @@ -2190,8 +2201,9 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str, if ( ! peer_rsclient_active (peer) ) { - peer_unlock (peer); /* peer bgp rsclient reference */ + bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); listnode_delete (bgp->rsclient, peer); + peer_unlock (peer); /* peer bgp rsclient reference */ } bgp_table_finish (&peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 0b6ab45a..49380cc3 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -39,7 +39,7 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_debug.h" /* All information about zebra. */ -static struct zclient *zclient = NULL; +struct zclient *zclient = NULL; struct in_addr router_id_zebra; /* Router-id update message from zebra. */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 86bf60ec..60722d27 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -727,7 +727,6 @@ struct peer * peer_lock (struct peer *peer) { assert (peer && (peer->lock >= 0)); - assert (peer->status != Deleted); peer->lock++; @@ -1109,7 +1108,7 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi) bgp_capability_send (peer, afi, safi, CAPABILITY_CODE_MP, CAPABILITY_ACTION_UNSET); - bgp_clear_route (peer, afi, safi); + bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); peer->pcount[afi][safi] = 0; } else @@ -1177,6 +1176,7 @@ peer_delete (struct peer *peer) safi_t safi; struct bgp *bgp; struct bgp_filter *filter; + struct listnode *pn; assert (peer->status != Deleted); @@ -1185,12 +1185,10 @@ peer_delete (struct peer *peer) if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); - /* If this peer belongs to peer group. Clearn up the + /* If this peer belongs to peer group, clear up the relationship. */ if (peer->group) { - struct listnode *pn; - if ((pn = listnode_lookup (peer->group->peer, peer))) { peer = peer_unlock (peer); /* group->peer list reference */ @@ -1220,22 +1218,25 @@ peer_delete (struct peer *peer) bgp_timer_set (peer); /* stops all timers for Deleted */ /* Delete from all peer list. */ - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && (pn = listnode_lookup (bgp->peer, peer))) { - struct listnode *pn; - - if ((pn = listnode_lookup (bgp->peer, peer))) - { - peer_unlock (peer); /* bgp peer list reference */ - list_delete_node (bgp->peer, pn); - } + peer_unlock (peer); /* bgp peer list reference */ + list_delete_node (bgp->peer, pn); + } - if (peer_rsclient_active (peer) - && (pn = listnode_lookup (bgp->rsclient, peer))) - { - peer_unlock (peer); /* rsclient list reference */ - list_delete_node (bgp->rsclient, pn); - } + if (peer_rsclient_active (peer) + && (pn = listnode_lookup (bgp->rsclient, peer))) + { + peer_unlock (peer); /* rsclient list reference */ + list_delete_node (bgp->rsclient, pn); + + /* Clear our own rsclient ribs. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_RSERVER_CLIENT)) + bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); } /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not @@ -1366,7 +1367,7 @@ peer_group_get (struct bgp *bgp, const char *name) group->conf = peer_new (bgp); if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; - group->conf->host = strdup (name); + group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; group->conf->ttl = 1; @@ -1822,6 +1823,9 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, { peer_unlock (peer); /* peer rsclient reference */ list_delete_node (bgp->rsclient, pn); + + /* Clear our own rsclient rib for this afi/safi. */ + bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); } bgp_table_finish (&peer->rib[afi][safi]); @@ -1914,7 +1918,7 @@ bgp_create (as_t *as, const char *name) bgp_lock (bgp); bgp->peer_self = peer_new (bgp); - bgp->peer_self->host = strdup ("Static announcement"); + bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement"); bgp->peer = list_new (); bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; @@ -2060,14 +2064,13 @@ bgp_delete (struct bgp *bgp) if (i != ZEBRA_ROUTE_BGP) bgp_redistribute_unset (bgp, afi, i); - for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) - peer_group_delete (group); - for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) peer_delete (peer); - for (ALL_LIST_ELEMENTS (bgp->rsclient, node, next, peer)) - peer_delete (peer); + for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) + peer_group_delete (group); + + assert (listcount (bgp->rsclient) == 0); if (bgp->peer_self) { peer_delete(bgp->peer_self); @@ -2095,6 +2098,7 @@ bgp_lock (struct bgp *bgp) void bgp_unlock(struct bgp *bgp) { + assert(bgp->lock > 0); if (--bgp->lock == 0) bgp_free (bgp); } @@ -2116,11 +2120,11 @@ bgp_free (struct bgp *bgp) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { if (bgp->route[afi][safi]) - XFREE (MTYPE_ROUTE_TABLE, bgp->route[afi][safi]); + bgp_table_finish (&bgp->route[afi][safi]); if (bgp->aggregate[afi][safi]) - XFREE (MTYPE_ROUTE_TABLE,bgp->aggregate[afi][safi]) ; + bgp_table_finish (&bgp->aggregate[afi][safi]) ; if (bgp->rib[afi][safi]) - XFREE (MTYPE_ROUTE_TABLE,bgp->rib[afi][safi]); + bgp_table_finish (&bgp->rib[afi][safi]); } XFREE (MTYPE_BGP, bgp); } |