Signed-off-by: Lou Berger <lber...@labn.net> Signed-off-by: David Lamparter <equi...@opensourcerouting.org> --- bgpd/bgp_nexthop.c | 21 ++++++++++++ bgpd/bgp_nexthop.h | 2 ++ bgpd/bgp_route.c | 99 ++++++++++++++++++++++++++++++++++++++++++++--------- bgpd/bgp_route.h | 3 ++ bgpd/bgp_routemap.c | 3 ++ bgpd/bgp_zebra.c | 10 ++++++ bgpd/bgp_zebra.h | 1 + bgpd/bgpd.c | 19 ++++++++++ bgpd/bgpd.h | 1 + 9 files changed, 142 insertions(+), 17 deletions(-)
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 145a1d8..7dbaf3c 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -589,6 +589,14 @@ bgp_address_init (void) bgp_address_hash_cmp); } +void +bgp_address_destroy (void) +{ + hash_clean(bgp_address_hash, NULL); + hash_free(bgp_address_hash); + bgp_address_hash = NULL; +} + static void bgp_address_add (struct prefix *p) { @@ -1465,3 +1473,16 @@ bgp_scan_finish (void) bgp_connected_table[AFI_IP6] = NULL; #endif /* HAVE_IPV6 */ } + +void +bgp_scan_destroy (void) +{ + if (zlookup == NULL) + return; + THREAD_OFF(bgp_import_thread); + THREAD_OFF(bgp_scan_thread); + THREAD_OFF(zlookup->t_connect); + bgp_scan_finish(); + zclient_free (zlookup); + zlookup = NULL; +} diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index c8aef58..85c5a5d 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -66,5 +66,7 @@ extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (struct attr *); extern void bgp_address_init (void); +extern void bgp_address_destroy (void); +extern void bgp_scan_destroy (void); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9866e37..7a80ee0 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3035,6 +3035,53 @@ bgp_clear_route_all (struct peer *peer) bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); } +/* + * 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) + 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); + bgp_drain_workqueue_immediate(bm->process_rsclient_queue); +} + void bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi) { @@ -3075,35 +3122,53 @@ 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) + 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) - 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]; + /* + * 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); + } - 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) - bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3e7f6f5..c92d405 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -241,4 +241,7 @@ extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); +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 */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 20bf2eb..0991955 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2295,6 +2295,9 @@ bgp_route_map_update (const char *unused) struct bgp_node *bn; struct bgp_static *bgp_static; + if (bm->bgp == NULL) /* may be called during cleanup */ + return; + /* For neighbor route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 186657b..e454c2e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1080,3 +1080,13 @@ bgp_zebra_init (struct thread_master *master) bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } + +void +bgp_zebra_destroy(void) +{ + if (zclient == NULL) + return; + zclient_stop(zclient); + zclient_free(zclient); + zclient = NULL; +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 50f727d..ff9b375 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA. */ extern struct stream *bgp_nexthop_buf; 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 *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d9c32ce..8401e9f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1377,6 +1377,9 @@ peer_delete (struct peer *peer) } } + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETING)) + bgp_peer_clear_node_queue_drain_immediate(peer); + peer_unlock (peer); /* initial reference */ return 0; @@ -2165,6 +2168,8 @@ bgp_delete (struct bgp *bgp) afi_t afi; int i; + SET_FLAG(bgp->flags, BGP_FLAG_DELETING); + THREAD_OFF (bgp->t_startup); /* Delete static route. */ @@ -2206,7 +2211,21 @@ bgp_delete (struct bgp *bgp) peer_delete(bgp->peer_self); bgp->peer_self = NULL; } + + /* + * 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(); + + bgp_zebra_destroy(); + bgp_scan_destroy(); + bgp_address_destroy(); + /* Remove visibility via the master list - there may however still be * routes to be processed still referencing the struct bgp. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d4c8dbd..1a00a0c 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -123,6 +123,7 @@ struct bgp #define BGP_FLAG_GRACEFUL_RESTART (1 << 12) #define BGP_FLAG_ASPATH_CONFED (1 << 13) #define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14) +#define BGP_FLAG_DELETING (1 << 15) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; -- 2.1.3 _______________________________________________ Quagga-dev mailing list Quagga-dev@lists.quagga.net https://lists.quagga.net/mailman/listinfo/quagga-dev