From: Renato Westphal Date: Mon, 31 Oct 2016 17:15:16 +0000 (-0200) Subject: zebra: plug more memory leaks X-Git-Tag: frr-2.0-rc1~34^2~1 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=5a8dfcd891fd12bb9db8f504bf3a083cea4f3cbd;p=matthieu%2Ffrr.git zebra: plug more memory leaks Try to free all memory explicitly on exit. This should help to detect new memory leaks in the future with tools like valgrind. Signed-off-by: Renato Westphal --- diff --git a/zebra/main.c b/zebra/main.c index 1b41f8deff..4fea0104f5 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -182,17 +182,27 @@ sighup (void) static void sigint (void) { + struct vrf *vrf; + struct zebra_vrf *zvrf; struct zebra_ns *zns; zlog_notice ("Terminating on signal"); - if (!retain_mode) - rib_close (); #ifdef HAVE_IRDP irdp_finish(); #endif zebra_ptm_finish(); + list_delete_all_node (zebrad.client_list); + + if (retain_mode) + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + { + zvrf = vrf->info; + if (zvrf) + SET_FLAG (zvrf->flags, ZEBRA_VRF_RETAIN); + } + vrf_terminate (); zns = zebra_ns_lookup (NS_DEFAULT); zebra_ns_disable (0, (void **)&zns); @@ -204,6 +214,10 @@ sigint (void) vty_terminate (); zprivs_terminate (&zserv_privs); list_delete (zebrad.client_list); + work_queue_free (zebrad.ribq); + if (zebrad.lsp_process_q) + work_queue_free (zebrad.lsp_process_q); + meta_queue_free (zebrad.mq); thread_master_free (zebrad.master); if (zlog_default) closezlog (zlog_default); diff --git a/zebra/rib.h b/zebra/rib.h index c95a9ba0c3..30929f1beb 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -366,13 +366,14 @@ extern void rib_update (vrf_id_t, rib_update_event_t); extern void rib_weed_tables (void); extern void rib_sweep_route (void); extern void rib_close_table (struct route_table *); -extern void rib_close (void); extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto, u_short instance); extern void rib_queue_add (struct route_node *rn); +extern void meta_queue_free (struct meta_queue *mq); extern struct route_table *rib_table_ipv6; +extern void rib_unlink (struct route_node *, struct rib *); extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 54caeba892..e29307be27 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1304,8 +1304,6 @@ rib_uninstall (struct route_node *rn, struct rib *rib) } } -static void rib_unlink (struct route_node *, struct rib *); - /* * rib_can_delete_dest * @@ -2216,6 +2214,17 @@ meta_queue_new (void) return new; } +void +meta_queue_free (struct meta_queue *mq) +{ + unsigned i; + + for (i = 0; i < MQ_SIZE; i++) + list_delete (mq->subq[i]); + + XFREE (MTYPE_WORK_QUEUE, mq); +} + /* initialise zebra rib work queue */ static void rib_queue_init (struct zebra_t *zebra) @@ -2351,7 +2360,7 @@ rib_addnode (struct route_node *rn, struct rib *rib, int process) * rib_gc_dest() at some point. This allows a rib_dest_t that is no * longer required to be deleted. */ -static void +void rib_unlink (struct route_node *rn, struct rib *rib) { rib_dest_t *dest; @@ -3153,43 +3162,6 @@ rib_close_table (struct route_table *table) } } -/* Close all RIB tables. */ -void -rib_close (void) -{ - struct vrf *vrf; - struct zebra_vrf *zvrf; - struct listnode *node; - struct interface *ifp; - u_int32_t table_id; - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) - { - if ((zvrf = vrf->info) != NULL) - { - rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); - rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); - } - for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp)) - if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); - } - - /* If we do multiple tables per vrf, need to move this to loop above */ - zvrf = vrf_info_lookup (VRF_DEFAULT); - - for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++) - { - if (zvrf->other_table[AFI_IP][table_id]) - rib_close_table (zvrf->other_table[AFI_IP][table_id]); - - if (zvrf->other_table[AFI_IP6][table_id]) - rib_close_table (zvrf->other_table[AFI_IP6][table_id]); - } - - zebra_mpls_close_tables(zvrf); - -} - /* Routing information base initialize. */ void rib_init (void) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 7df759030d..c6fc404bed 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -163,6 +163,16 @@ zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type) return (rn->info); } +void +zebra_free_rnh (struct rnh *rnh) +{ + rnh->flags |= ZEBRA_NHT_DELETED; + list_free (rnh->client_list); + list_free (rnh->zebra_static_route_list); + free_state (rnh->vrf_id, rnh->state, rnh->node); + XFREE (MTYPE_RNH, rnh); +} + void zebra_delete_rnh (struct rnh *rnh, rnh_type_t type) { @@ -178,14 +188,9 @@ zebra_delete_rnh (struct rnh *rnh, rnh_type_t type) rnh->vrf_id, rnh_str(rnh, buf, sizeof (buf)), type); } - rnh->flags |= ZEBRA_NHT_DELETED; - list_free(rnh->client_list); - list_free(rnh->zebra_static_route_list); - free_state(rnh->vrf_id, rnh->state, rn); - XFREE(MTYPE_RNH, rn->info); + zebra_free_rnh (rnh); rn->info = NULL; route_unlock_node (rn); - return; } void diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 3a57ef1bc6..4394fde4f3 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -59,6 +59,7 @@ extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type); extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type); +extern void zebra_free_rnh (struct rnh *rnh); extern void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type); extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vrfid); diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c index eecb8519d5..a97ae1a612 100644 --- a/zebra/zebra_rnh_null.c +++ b/zebra/zebra_rnh_null.c @@ -26,6 +26,10 @@ int zebra_rnh_ip_default_route = 0; int zebra_rnh_ipv6_default_route = 0; +void +zebra_free_rnh (struct rnh *rnh) +{} + void zebra_evaluate_rnh (vrf_id_t vrfid, int family, int force, rnh_type_t type, struct prefix *p) {} diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 13010bfdcd..b1c5e4dd35 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -30,9 +30,11 @@ #include "zebra/zserv.h" #include "zebra/rib.h" #include "zebra/zebra_vrf.h" +#include "zebra/zebra_rnh.h" #include "zebra/router-id.h" #include "zebra/zebra_memory.h" #include "zebra/zebra_static.h" +#include "zebra/interface.h" #include "zebra/zebra_mpls.h" extern struct zebra_t zebrad; @@ -214,18 +216,84 @@ static int zebra_vrf_delete (struct vrf *vrf) { struct zebra_vrf *zvrf = vrf->info; + struct route_table *table; + u_int32_t table_id; + afi_t afi; + safi_t safi; + unsigned i; assert (zvrf); zebra_vrf_delete_update (zvrf); - rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); - rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); + /* uninstall everything */ + if (! CHECK_FLAG (zvrf->flags, ZEBRA_VRF_RETAIN)) + { + struct listnode *node; + struct interface *ifp; + + for (afi = AFI_IP; afi <= AFI_IP6; afi++) + { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + rib_close_table (zvrf->table[afi][safi]); + + if (vrf->vrf_id == VRF_DEFAULT) + for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++) + if (zvrf->other_table[afi][table_id]) + rib_close_table (zvrf->other_table[afi][table_id]); + } + + zebra_mpls_close_tables (zvrf); + + for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp)) + if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp); + } + + /* clean-up work queues */ + for (i = 0; i < MQ_SIZE; i++) + { + struct listnode *lnode, *nnode; + struct route_node *rnode; + rib_dest_t *dest; + + for (ALL_LIST_ELEMENTS (zebrad.mq->subq[i], lnode, nnode, rnode)) + { + dest = rib_dest_from_rnode (rnode); + if (dest && rib_dest_vrf (dest) == zvrf) + { + route_unlock_node (rnode); + list_delete_node (zebrad.mq->subq[i], lnode); + } + } + } + + /* release allocated memory */ + for (afi = AFI_IP; afi <= AFI_IP6; afi++) + { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + { + table = zvrf->table[afi][safi]; + XFREE (MTYPE_RIB_TABLE_INFO, table->info); + route_table_finish (table); + + table = zvrf->stable[afi][safi]; + route_table_finish (table); + } + for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++) + if (zvrf->other_table[afi][table_id]) + { + table = zvrf->other_table[afi][table_id]; + XFREE (MTYPE_RIB_TABLE_INFO, table->info); + route_table_finish (table); + } + + route_table_finish (zvrf->rnh_table[afi]); + route_table_finish (zvrf->import_check_table[afi]); + } list_delete_all_node (zvrf->rid_all_sorted_list); list_delete_all_node (zvrf->rid_lo_sorted_list); - - vrf->vrf_id = VRF_UNKNOWN; + XFREE (MTYPE_ZEBRA_VRF, zvrf); vrf->info = NULL; return 0; @@ -257,6 +325,62 @@ zebra_vrf_table_with_table_id (afi_t afi, safi_t safi, return table; } +static void +zebra_rtable_node_destroy (route_table_delegate_t *delegate, + struct route_table *table, struct route_node *node) +{ + struct rib *rib, *next; + + RNODE_FOREACH_RIB_SAFE (node, rib, next) + rib_unlink (node, rib); + + if (node->info) + XFREE (MTYPE_RIB_DEST, node->info); + + route_node_destroy (delegate, table, node); +} + +static void +zebra_stable_node_destroy (route_table_delegate_t *delegate, + struct route_table *table, struct route_node *node) +{ + struct static_route *si, *next; + + if (node->info) + for (si = node->info; si; si = next) + { + next = si->next; + XFREE (MTYPE_STATIC_ROUTE, si); + } + + route_node_destroy (delegate, table, node); +} + +static void +zebra_rnhtable_node_destroy (route_table_delegate_t *delegate, + struct route_table *table, struct route_node *node) +{ + if (node->info) + zebra_free_rnh (node->info); + + route_node_destroy (delegate, table, node); +} + +route_table_delegate_t zebra_rtable_delegate = { + .create_node = route_node_create, + .destroy_node = zebra_rtable_node_destroy +}; + +route_table_delegate_t zebra_stable_delegate = { + .create_node = route_node_create, + .destroy_node = zebra_stable_node_destroy +}; + +route_table_delegate_t zebra_rnhtable_delegate = { + .create_node = route_node_create, + .destroy_node = zebra_rnhtable_node_destroy +}; + /* * Create a routing table for the specific AFI/SAFI in the given VRF. */ @@ -268,7 +392,7 @@ zebra_vrf_table_create (struct zebra_vrf *zvrf, afi_t afi, safi_t safi) assert (!zvrf->table[afi][safi]); - table = route_table_init (); + table = route_table_init_with_delegate (&zebra_rtable_delegate); zvrf->table[afi][safi] = table; info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); @@ -283,24 +407,25 @@ struct zebra_vrf * zebra_vrf_alloc (void) { struct zebra_vrf *zvrf; + afi_t afi; + safi_t safi; zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf)); - /* Allocate routing table and static table. */ - zebra_vrf_table_create (zvrf, AFI_IP, SAFI_UNICAST); - zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_UNICAST); - zvrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); - zvrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); - zebra_vrf_table_create (zvrf, AFI_IP, SAFI_MULTICAST); - zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_MULTICAST); - zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); - zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); - - zvrf->rnh_table[AFI_IP] = route_table_init(); - zvrf->rnh_table[AFI_IP6] = route_table_init(); - - zvrf->import_check_table[AFI_IP] = route_table_init(); - zvrf->import_check_table[AFI_IP6] = route_table_init(); + for (afi = AFI_IP; afi <= AFI_IP6; afi++) + { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + { + zebra_vrf_table_create (zvrf, afi, safi); + zvrf->stable[afi][safi] = + route_table_init_with_delegate (&zebra_stable_delegate); + } + + zvrf->rnh_table[afi] = + route_table_init_with_delegate (&zebra_rnhtable_delegate); + zvrf->import_check_table[afi] = + route_table_init_with_delegate (&zebra_rnhtable_delegate); + } zebra_mpls_init_tables (zvrf); diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 8c4f0b4a28..96d631d646 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -40,6 +40,7 @@ struct zebra_vrf /* Flags. */ u_int16_t flags; #define ZEBRA_VRF_RIB_SCHEDULED (1 << 0) +#define ZEBRA_VRF_RETAIN (2 << 0) u_int32_t table_id;