From 89b776925de8788a64af0890765a092e4d472cf9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 21 Nov 2023 13:02:21 +0100 Subject: [PATCH] E2 agent: fix memory leak by not allocating memory Prior to this commit, the RAN function for KPM is leaking memory: it allocates using calloc() but never frees it. The fix consists of not allocating this memory on the heap in the first place, but on the stack. Therefore, there are changes to pass in a pointer to various functions to the structure on the stack, instead of passing the "container" for the heap memory by value. Further, the MAC was allocating an excessive amount of memory (N times sizeof(NR_UE_info_t)). Instead of copying the entire struct, the present code stores a pointer to the MAC UE container (NR_UE_info_t *). For the RRC, there is a similar simplification that consists in not storing the entire struct f1_ue_data_t (which is not required), but only the RRC UE ID. Note that both MAC and RRC might suffer from race conditions. For the MAC, we should lock the scheduler for the time we read statistics. For the RRC, the problem is more delicate as no mutex exists; the RRC assumes everything is executed synchronously in the ITTI task loop. In both cases, this commit does not address this problem --- .../E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index 275e1a6d82..6ddd7560b1 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -35,56 +35,51 @@ typedef struct { - NR_UE_info_t *ue_list; - size_t num_ues; + NR_UE_info_t* ue_list[MAX_MOBILES_PER_GNB]; + size_t num_ues; } matched_ues_mac_t; - -static -matched_ues_mac_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condition, int64_t const value) +static size_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condition, + int64_t const value, + matched_ues_mac_t* matches) { - matched_ues_mac_t matched_ues = {.num_ues = 0, .ue_list = calloc(MAX_MOBILES_PER_GNB, sizeof(NR_UE_info_t)) }; - assert(matched_ues.ue_list != NULL && "Memory exhausted"); - - /* IMPORTANT: in the case of gNB-DU, it is not possible to filter UEs by S-NSSAI as the ngap context is stored in gNB-CU - instead, we take all connected UEs*/ + DevAssert(matches != NULL); AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented", condition); // Take MAC info + size_t i = 0; UE_iterator (RC.nrmac[0]->UE_info.list, ue) { - matched_ues.ue_list[matched_ues.num_ues] = *ue; - matched_ues.num_ues++; + matches->ue_list[i++] = ue; + AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); } - assert(matched_ues.num_ues >= 1 && "The number of filtered UEs must be at least equal to 1"); - - return matched_ues; + matches->num_ues = i; + assert(matches->num_ues >= 1 && "The number of filtered UEs must be at least equal to 1"); + return i; } typedef struct { - f1_ue_data_t * rrc_ue_id_list; // list of matched UEs on RRC level containing only rrc_ue_id (gNB CU UE ID) + uint32_t rrc_ue_id_list[MAX_MOBILES_PER_GNB]; // list of matched UEs on RRC level containing only rrc_ue_id (gNB CU UE ID) size_t num_ues; } matched_ues_rrc_t; -static -matched_ues_rrc_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, int64_t const value) +static size_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, int64_t const value, matched_ues_rrc_t* matches) { - matched_ues_rrc_t matched_ues = {.num_ues = 0, .rrc_ue_id_list = calloc(MAX_MOBILES_PER_GNB, sizeof(f1_ue_data_t)) }; - assert(matched_ues.rrc_ue_id_list != NULL && "Memory exhausted"); - + DevAssert(matches != NULL); AssertFatal(condition == EQUAL_TEST_COND, "Condition %d not yet implemented\n", condition); struct rrc_gNB_ue_context_s *ue_context_p1 = NULL; + size_t i = 0; RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) { - matched_ues.rrc_ue_id_list[matched_ues.num_ues].secondary_ue = ue_context_p1->ue_context.rrc_ue_id; - matched_ues.num_ues++; + matches->rrc_ue_id_list[i++] = ue_context_p1->ue_context.rrc_ue_id; + AssertFatal(i < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); } - - assert(matched_ues.num_ues >= 1 && "The number of filtered UEs must be at least equal to 1"); - - return matched_ues; + + matches->num_ues = i; + assert(matches->num_ues >= 1 && "The number of filtered UEs must be at least equal to 1"); + return i; } static @@ -382,8 +377,8 @@ kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, cons return msg_frm_1; } -static -kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_t matched_ues, const kpm_act_def_format_1_t * act_def_fr_1) +static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_t* matched_ues, + const kpm_act_def_format_1_t* act_def_fr_1) { assert(act_def_fr_1 != NULL); @@ -391,20 +386,20 @@ kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_t matc kpm_ind_msg_format_3_t msg_frm_3 = {0}; // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues.num_ues; + + msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); for (size_t i = 0; iue_list[i]->rnti); // get gNB CU UE ID as rrc_ue_id msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_DU_UE_ID_E2SM; msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb_du = fill_gnb_du_data(&rrc_ue_id); // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_du(&matched_ues.ue_list[i], i, act_def_fr_1); + msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_du(matched_ues->ue_list[i], i, act_def_fr_1); } @@ -465,8 +460,8 @@ kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_cu(const uint32_t rrc_ue_id, co return msg_frm_1; } -static -kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t matched_ues, const kpm_act_def_format_1_t * act_def_fr_1) +static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t* matched_ues, + const kpm_act_def_format_1_t* act_def_fr_1) { assert(act_def_fr_1 != NULL); @@ -474,20 +469,21 @@ kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t matc kpm_ind_msg_format_3_t msg_frm_3 = {0}; // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues.num_ues; + + msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); for (size_t i = 0; irrc_ue_id_list[i]); msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM; msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list); // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_cu(matched_ues.rrc_ue_id_list[i].secondary_ue, i, act_def_fr_1); + msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = + fill_kpm_ind_msg_frm_1_in_cu(matched_ues->rrc_ue_id_list[i], i, act_def_fr_1); } return msg_frm_3; @@ -555,8 +551,8 @@ kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_monolithic(const NR_UE_info_t* return msg_frm_1; } -static -kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_mac_t matched_ues, const kpm_act_def_format_1_t * act_def_fr_1) +static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_mac_t* matched_ues, + const kpm_act_def_format_1_t* act_def_fr_1) { assert(act_def_fr_1 != NULL); @@ -564,8 +560,8 @@ kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_ma kpm_ind_msg_format_3_t msg_frm_3 = {0}; // Fill UE Measurement Reports - - msg_frm_3.ue_meas_report_lst_len = matched_ues.num_ues; + + msg_frm_3.ue_meas_report_lst_len = matched_ues->num_ues; msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t)); assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted"); @@ -573,12 +569,13 @@ kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_ma for (size_t i = 0; iue_list[i]->rnti); msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM; msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list); // Fill UE related info - msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_monolithic(&matched_ues.ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1); + msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = + fill_kpm_ind_msg_frm_1_in_monolithic(matched_ues->ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1); } return msg_frm_3; @@ -736,14 +733,17 @@ void read_kpm_sm(void* data) int64_t const value = *frm_4->matching_cond_lst[i].test_info_lst.int_value; // Check E2 Node NG-RAN Type if (NODE_IS_DU(RC.nrrrc[0]->node_type)) { - matched_ues_mac_t matched_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, value); - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_du(matched_ues, &frm_4->action_def_format_1); + matched_ues_mac_t matched_ues = {0}; + matched_ues.num_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, value, &matched_ues); + kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_du(&matched_ues, &frm_4->action_def_format_1); } else if (NODE_IS_CU(RC.nrrrc[0]->node_type)) { - matched_ues_rrc_t matched_ues = filter_ues_by_s_nssai_in_cu(test_cond, value); - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cu(matched_ues, &frm_4->action_def_format_1); + matched_ues_rrc_t matched_ues = {0}; + matched_ues.num_ues = filter_ues_by_s_nssai_in_cu(test_cond, value, &matched_ues); + kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cu(&matched_ues, &frm_4->action_def_format_1); } else if (NODE_IS_MONOLITHIC(RC.nrrrc[0]->node_type)) { - matched_ues_mac_t matched_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, value); - kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_monolithic(matched_ues, &frm_4->action_def_format_1); + matched_ues_mac_t matched_ues = {0}; + matched_ues.num_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, value, &matched_ues); + kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_monolithic(&matched_ues, &frm_4->action_def_format_1); } else { assert(false && "NG-RAN Type not implemented"); }