From 83d56fe40df2fc9bd8044acfa25a0c5b7bf9fccb Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Mon, 31 Jan 2022 22:58:52 +0900 Subject: [PATCH] [ALL] Fix the memory leak (#1282) --- lib/gtp/xact.h | 1 + lib/pfcp/context.c | 4 +++ src/amf/context.c | 28 ++++++++++++++++++++ src/amf/gmm-handler.c | 7 ++--- src/amf/gmm-sm.c | 4 +-- src/mme/mme-context.c | 56 ++++++++++++++++++++++++++++++++------- src/mme/mme-context.h | 1 + src/mme/mme-s11-handler.c | 6 +++++ src/mme/s1ap-handler.c | 2 ++ 9 files changed, 94 insertions(+), 15 deletions(-) diff --git a/lib/gtp/xact.h b/lib/gtp/xact.h index 2eafefb8c..8af470bf4 100644 --- a/lib/gtp/xact.h +++ b/lib/gtp/xact.h @@ -92,6 +92,7 @@ typedef struct ogs_gtp_xact_s { #define OGS_GTP_DELETE_SEND_DEACTIVATE_BEARER_CONTEXT_REQUEST 3 #define OGS_GTP_DELETE_SEND_UE_CONTEXT_RELEASE_COMMAND 4 #define OGS_GTP_DELETE_HANDLE_PDN_CONNECTIVITY_REQUEST 5 +#define OGS_GTP_DELETE_UE_CONTEXT_REMOVE 6 int delete_action; #define OGS_GTP_RELEASE_SEND_UE_CONTEXT_RELEASE_COMMAND 1 diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index 019846675..d45f89d3c 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -1210,6 +1210,10 @@ void ogs_pfcp_far_remove(ogs_pfcp_far_t *far) ogs_list_remove(&sess->far_list, far); + if (far->hash.teid.len) + ogs_hash_set(self.far_teid_hash, + &far->hash.teid.key, far->hash.teid.len, NULL); + if (far->hash.f_teid.len) ogs_hash_set(self.far_f_teid_hash, &far->hash.f_teid.key, far->hash.f_teid.len, NULL); diff --git a/src/amf/context.c b/src/amf/context.c index 65db16ca5..dd619610f 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -924,6 +924,8 @@ int amf_gnb_set_gnb_id(amf_gnb_t *gnb, uint32_t gnb_id) { ogs_assert(gnb); + ogs_hash_set(self.gnb_id_hash, &gnb_id, sizeof(gnb_id), NULL); + gnb->gnb_id = gnb_id; ogs_hash_set(self.gnb_id_hash, &gnb->gnb_id, sizeof(gnb->gnb_id), gnb); @@ -1508,6 +1510,7 @@ void amf_ue_set_suci(amf_ue_t *amf_ue, ogs_nas_5gs_mobile_identity_t *mobile_identity) { amf_ue_t *old_amf_ue = NULL; + amf_sess_t *old_sess = NULL; char *suci = NULL; ogs_assert(amf_ue); @@ -1531,6 +1534,31 @@ void amf_ue_set_suci(amf_ue_t *amf_ue, (long long)old_amf_ue->ran_ue->amf_ue_ngap_id); ran_ue_remove(old_amf_ue->ran_ue); } + + /* + * We should delete the AMF-Session Context in the AMF-UE Context. + * Otherwise, all unnecessary SESSIONs remain in SMF/UPF. + * + * In order to do this, AMF-Session Context should be moved + * from OLD AMF-UE Context to NEW AMF-UE Context. + * + * If needed, The Session deletion process in NEW-AMF UE context will work. + * + * Note that we should not send Session-Release to the SMF at this point. + * Another SBI Transaction can cause fatal errors. + */ + + /* Phase-1 : Change AMF-UE Context in Session Context */ + ogs_list_for_each(&old_amf_ue->sess_list, old_sess) + old_sess->amf_ue = amf_ue; + + /* Phase-2 : Move Session Context from OLD to NEW AMF-UE Context */ + memcpy(&amf_ue->sess_list, + &old_amf_ue->sess_list, sizeof(amf_ue->sess_list)); + + /* Phase-3 : Clear Session Context in OLD AMF-UE Context */ + memset(&old_amf_ue->sess_list, 0, sizeof(old_amf_ue->sess_list)); + amf_ue_remove(old_amf_ue); } } diff --git a/src/amf/gmm-handler.c b/src/amf/gmm-handler.c index 5118c7b96..55ac03eae 100644 --- a/src/amf/gmm-handler.c +++ b/src/amf/gmm-handler.c @@ -413,7 +413,7 @@ int gmm_handle_registration_update(amf_ue_t *amf_ue, if ((psimask & (1 << sess->psi)) == 0) { if (SESSION_CONTEXT_IN_SMF(sess)) amf_sbi_send_release_session( - sess, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT); + sess, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT); } } } @@ -622,7 +622,7 @@ int gmm_handle_service_update(amf_ue_t *amf_ue, if ((psimask & (1 << sess->psi)) == 0) { if (SESSION_CONTEXT_IN_SMF(sess)) amf_sbi_send_release_session( - sess, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT); + sess, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT); } } } @@ -694,7 +694,8 @@ int gmm_handle_deregistration_request(amf_ue_t *amf_ue, ogs_info("[%s] SUCI", amf_ue->suci); - amf_sbi_send_release_all_sessions(amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_sbi_send_release_all_sessions( + amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); if (ogs_list_count(&amf_ue->sess_list) == 0) ogs_assert(OGS_OK == diff --git a/src/amf/gmm-sm.c b/src/amf/gmm-sm.c index 5b23b676c..9145f9798 100644 --- a/src/amf/gmm-sm.c +++ b/src/amf/gmm-sm.c @@ -261,7 +261,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) } amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); if (amf_sess_xact_count(amf_ue) == xact_count) { ogs_assert(true == amf_ue_sbi_discover_and_send( @@ -1135,7 +1135,7 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e) } amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); if (amf_sess_xact_count(amf_ue) == xact_count) { ogs_assert(true == amf_ue_sbi_discover_and_send( diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index c7fe0c903..a4e3849bb 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -26,6 +26,7 @@ #include "s1ap-path.h" #include "s1ap-handler.h" #include "mme-sm.h" +#include "mme-gtp-path.h" #define MAX_CELL_PER_ENB 8 @@ -1870,6 +1871,8 @@ int mme_enb_set_enb_id(mme_enb_t *enb, uint32_t enb_id) { ogs_assert(enb); + ogs_hash_set(self.enb_id_hash, &enb_id, sizeof(enb_id), NULL); + enb->enb_id = enb_id; ogs_hash_set(self.enb_id_hash, &enb->enb_id, sizeof(enb->enb_id), enb); @@ -2151,6 +2154,19 @@ mme_ue_t *mme_ue_add(enb_ue_t *enb_ue) return mme_ue; } +void mme_ue_hash_remove(mme_ue_t *mme_ue) +{ + ogs_assert(mme_ue); + + if (mme_ue->imsi_len != 0) + ogs_hash_set(mme_self()->imsi_ue_hash, + mme_ue->imsi, mme_ue->imsi_len, NULL); + + if (mme_ue->current.m_tmsi) + ogs_hash_set(self.guti_ue_hash, + &mme_ue->current.guti, sizeof(ogs_nas_eps_guti_t), NULL); +} + void mme_ue_remove(mme_ue_t *mme_ue) { ogs_assert(mme_ue); @@ -2159,17 +2175,12 @@ void mme_ue_remove(mme_ue_t *mme_ue) mme_ue_fsm_fini(mme_ue); - if (mme_ue->current.m_tmsi) { - ogs_hash_set(self.guti_ue_hash, - &mme_ue->current.guti, sizeof(ogs_nas_eps_guti_t), NULL); + if (mme_ue->current.m_tmsi) ogs_assert(mme_m_tmsi_free(mme_ue->current.m_tmsi) == OGS_OK); - } - if (mme_ue->next.m_tmsi) { + + if (mme_ue->next.m_tmsi) ogs_assert(mme_m_tmsi_free(mme_ue->next.m_tmsi) == OGS_OK); - } - if (mme_ue->imsi_len != 0) - ogs_hash_set(self.imsi_ue_hash, mme_ue->imsi, mme_ue->imsi_len, NULL); - + /* Clear the saved PDN Connectivity Request */ OGS_NAS_CLEAR_DATA(&mme_ue->pdn_connectivity_request); @@ -2212,6 +2223,7 @@ void mme_ue_remove_all(void) if (enb_ue) enb_ue_remove(enb_ue); + mme_ue_hash_remove(mme_ue); mme_ue_remove(mme_ue); } } @@ -2463,10 +2475,34 @@ int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd) old_mme_ue->enb_ue->mme_ue_s1ap_id); enb_ue_remove(old_mme_ue->enb_ue); } - mme_ue_remove(old_mme_ue); + + /* + * We should delete the MME-Session Context in the MME-UE Context. + * Otherwise, all unnecessary SESSIONs remain in SMF/SGW-C/SGW-U/UPF. + * + * Hash deletion is separated from mme_ue_remove(). Otherwise, + * hash deletion occurs simultaneously in mme_ue_remove() + * after mme_gtp_send_delete_all_session(). This will delete the Hash + * we added immediately below, so we can't find this IMSI. + * + * Note that we should not use the session movement method in AMF. + * This is because the MME-S11-TEID in the Delete Session Response + * uses the OLD MME. + */ + mme_ue_hash_remove(old_mme_ue); + + if (SESSION_CONTEXT_IS_AVAILABLE(old_mme_ue)) { + ogs_warn("[%s] Trigger OLD Session Remove", mme_ue->imsi_bcd); + mme_gtp_send_delete_all_sessions(old_mme_ue, + OGS_GTP_DELETE_UE_CONTEXT_REMOVE); + } } } + if (mme_ue->imsi_len != 0) + ogs_hash_set(mme_self()->imsi_ue_hash, + mme_ue->imsi, mme_ue->imsi_len, NULL); + ogs_hash_set(self.imsi_ue_hash, mme_ue->imsi, mme_ue->imsi_len, mme_ue); return OGS_OK; diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index 43edda6d5..d92ddd07a 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -704,6 +704,7 @@ void mme_ue_new_guti(mme_ue_t *mme_ue); void mme_ue_confirm_guti(mme_ue_t *mme_ue); mme_ue_t *mme_ue_add(enb_ue_t *enb_ue); +void mme_ue_hash_remove(mme_ue_t *mme_ue); void mme_ue_remove(mme_ue_t *mme_ue); void mme_ue_remove_all(void); diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index 48686077f..840e45448 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -406,6 +406,12 @@ void mme_s11_handle_delete_session_response( } } + } else if (action == OGS_GTP_DELETE_UE_CONTEXT_REMOVE) { + + /* Remove MME-UE Context with Session Context since IMSI duplicated */ + mme_ue_remove(mme_ue); + return; + } else { ogs_fatal("Invalid action = %d", action); ogs_assert_if_reached(); diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index d871a34d4..c6dfd4e16 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -1477,6 +1477,8 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue) ogs_debug(" Action: UE context remove"); enb_ue_remove(enb_ue); ogs_expect_or_return(mme_ue); + + mme_ue_hash_remove(mme_ue); mme_ue_remove(mme_ue); break; case S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE: