bgpd: improve cleanup in bgp_delete()

Signed-off-by: Lou Berger <lberger@labn.net>
(cherry picked from commit 82dd707988b7481e203cab058c92f0b3041dd558)

Conflicts:
	bgpd/bgp_nexthop.h
	bgpd/bgp_route.c
	bgpd/bgp_routemap.c
	bgpd/bgp_zebra.h
	bgpd/bgpd.c
	bgpd/bgpd.h
This commit is contained in:
Lou Berger 2016-01-12 13:41:57 -05:00 committed by vivek
parent 4f87aceb78
commit bb86c6017e
10 changed files with 130 additions and 25 deletions

View File

@ -145,6 +145,14 @@ bgp_address_init (struct bgp *bgp)
bgp_address_hash_cmp);
}
void
bgp_address_destroy (struct bgp *bgp)
{
hash_clean(bgp->address_hash, NULL);
hash_free(bgp->address_hash);
bgp->address_hash = NULL;
}
static void
bgp_address_add (struct bgp *bgp, struct prefix *p)
{

View File

@ -73,7 +73,6 @@ extern void bgp_connected_delete (struct bgp *bgp, struct connected *c);
extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *);
extern int bgp_config_write_scan_time (struct vty *);
extern int bgp_nexthop_self (struct bgp *, struct attr *);
extern void bgp_address_init (struct bgp *);
extern struct bgp_nexthop_cache *bnc_new(void);
extern void bnc_free(struct bgp_nexthop_cache *bnc);
extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
@ -81,5 +80,7 @@ extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
extern void bgp_scan_init(struct bgp *bgp);
extern void bgp_scan_finish(struct bgp *bgp);
extern void bgp_scan_vty_init(void);
extern void bgp_address_init (struct bgp *bgp);
extern void bgp_address_destroy (struct bgp *bgp);
#endif /* _QUAGGA_BGP_NEXTHOP_H */

View File

@ -2997,6 +2997,56 @@ bgp_clear_route_all (struct peer *peer)
bgp_clear_route (peer, afi, safi);
}
/*
* Finish freeing things when exiting
*/
static void
bgp_drain_workqueue_immediate (struct work_queue *wq)
{
if (!wq)
return;
if (!wq->thread)
{
/*
* no thread implies no queued items
*/
assert(!wq->items->count);
return;
}
while (wq->items->count)
{
if (wq->thread)
thread_cancel(wq->thread);
work_queue_run(wq->thread);
}
}
/*
* Special function to process clear node queue when bgpd is exiting
* and the thread scheduler is no longer running.
*/
void
bgp_peer_clear_node_queue_drain_immediate(struct peer *peer)
{
if (!peer)
return;
bgp_drain_workqueue_immediate(peer->clear_node_queue);
}
/*
* The work queues are not specific to a BGP instance, but the
* items in them refer to BGP instances, so this should be called
* before each BGP instance is deleted.
*/
void
bgp_process_queues_drain_immediate(void)
{
bgp_drain_workqueue_immediate(bm->process_main_queue);
}
void
bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
{
@ -3050,37 +3100,54 @@ bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
}
}
static void
bgp_cleanup_table(struct bgp_table *table, safi_t safi)
{
struct bgp_node *rn;
struct bgp_info *ri;
struct bgp_info *next;
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (ri = rn->info; ri; ri = next)
{
next = ri->next;
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& (ri->sub_type == BGP_ROUTE_NORMAL ||
ri->sub_type == BGP_ROUTE_AGGREGATE))
bgp_zebra_withdraw (&rn->p, ri, safi);
}
}
/* Delete all kernel routes. */
void
bgp_cleanup_routes (void)
{
struct bgp *bgp;
struct listnode *node, *nnode;
struct bgp_node *rn;
struct bgp_table *table;
struct bgp_info *ri;
afi_t afi;
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
{
table = bgp->rib[AFI_IP][SAFI_UNICAST];
for (afi = AFI_IP; afi < AFI_MAX; ++afi)
{
struct bgp_node *rn;
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->type == ZEBRA_ROUTE_BGP
&& (ri->sub_type == BGP_ROUTE_NORMAL ||
ri->sub_type == BGP_ROUTE_AGGREGATE))
bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST);
table = bgp->rib[AFI_IP6][SAFI_UNICAST];
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->type == ZEBRA_ROUTE_BGP
&& (ri->sub_type == BGP_ROUTE_NORMAL ||
ri->sub_type == BGP_ROUTE_AGGREGATE))
bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
/*
* VPN and ENCAP tables are two-level (RD is top level)
*/
for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn;
rn = bgp_route_next (rn))
if (rn->info)
{
bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN);
bgp_table_finish ((struct bgp_table **)&(rn->info));
rn->info = NULL;
bgp_unlock_node(rn);
}
}
}
}

View File

@ -306,4 +306,7 @@ extern int subgroup_announce_check(struct bgp_info *ri,
struct update_subgroup *subgrp,
struct prefix *p, struct attr *attr);
extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
extern void bgp_process_queues_drain_immediate (void);
#endif /* _QUAGGA_BGP_ROUTE_H */

View File

@ -14801,9 +14801,9 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd);
/* "neighbor maximum-prefix" commands. */
install_element (BGP_NODE, &neighbor_maximum_prefix_cmd);

View File

@ -2094,3 +2094,13 @@ bgp_zebra_init (struct thread_master *master)
bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
}
void
bgp_zebra_destroy(void)
{
if (zclient == NULL)
return;
zclient_stop(zclient);
zclient_free(zclient);
zclient = NULL;
}

View File

@ -27,7 +27,8 @@ Boston, MA 02111-1307, USA. */
extern struct stream *bgp_nexthop_buf;
extern struct stream *bgp_ifindices_buf;
extern void bgp_zebra_init(struct thread_master *master);
extern void bgp_zebra_init (struct thread_master *master);
extern void bgp_zebra_destroy (void);
extern int bgp_if_update_all (void);
extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
safi_t, int *);

View File

@ -2034,6 +2034,9 @@ peer_delete (struct peer *peer)
XFREE(MTYPE_HOST, peer->domainname);
peer->domainname = NULL;
}
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETING))
bgp_peer_clear_node_queue_drain_immediate(peer);
peer_unlock (peer); /* initial reference */
@ -3044,6 +3047,8 @@ bgp_delete (struct bgp *bgp)
afi_t afi;
int i;
SET_FLAG(bgp->flags, BGP_FLAG_DELETING);
THREAD_OFF (bgp->t_startup);
if (BGP_DEBUG (zebra, ZEBRA))
@ -3095,6 +3100,15 @@ bgp_delete (struct bgp *bgp)
/* TODO - Other memory may need to be freed - e.g., NHT */
/*
* Free pending deleted routes. Unfortunately, it also has to process
* all the pending activity for other instances of struct bgp.
*
* This call was added to achieve clean memory allocation at exit,
* for the sake of valgrind.
*/
bgp_process_queues_drain_immediate();
/* Remove visibility via the master list - there may however still be
* routes to be processed still referencing the struct bgp.
*/

View File

@ -281,6 +281,7 @@ struct bgp
#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1 << 17)
#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 18)
#define BGP_FLAG_SHOW_HOSTNAME (1 << 19)
#define BGP_FLAG_DELETING (1 << 20)
/* BGP Per AF flags */
u_int16_t af_flags[AFI_MAX][SAFI_MAX];

View File

@ -361,7 +361,7 @@ vtysh_execute_func (const char *line, int pager)
* to move into node in the vtysh where it succeeded. */
if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING)
{
if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE
if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE
|| saved_node == BGP_IPV4_NODE
|| saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
|| saved_node == BGP_IPV6M_NODE)