change S1 release scheme with holding timer(30sec)

This commit is contained in:
Sukchan Lee 2018-02-02 19:37:36 +09:00
parent 57f3baa273
commit b97597ae7c
6 changed files with 121 additions and 26 deletions

View File

@ -76,6 +76,7 @@ status_t mme_context_init()
/* Timer value */
self.t3413_value = 2; /* Paging retry timer: 2 secs */
self.s1_holding_timer_value = 30; /* S1 holding timer: 30 secs */
context_initialized = 1;
@ -1767,6 +1768,12 @@ enb_ue_t* enb_ue_add(mme_enb_t *enb)
sizeof(enb_ue->mme_ue_s1ap_id), enb_ue);
list_append(&enb->enb_ue_list, enb_ue);
/* Create S1 holding timer */
enb_ue->holding_timer = timer_create(&self.tm_service,
MME_EVT_S1AP_S1_HOLDING_TIMER, self.s1_holding_timer_value * 1000);
d_assert(enb_ue->holding_timer, return NULL, "Null param");
timer_set_param1(enb_ue->holding_timer, enb_ue->index);
return enb_ue;
}
@ -1789,6 +1796,9 @@ status_t enb_ue_remove(enb_ue_t *enb_ue)
rv = enb_ue_deassociate(enb_ue);
d_assert(rv == CORE_OK,,);
/* Delete All Timers */
tm_delete(enb_ue->holding_timer);
list_remove(&enb_ue->enb->enb_ue_list, enb_ue);
hash_set(self.mme_ue_s1ap_id_hash, &enb_ue->mme_ue_s1ap_id,
sizeof(enb_ue->mme_ue_s1ap_id), NULL);

View File

@ -109,6 +109,7 @@ typedef struct _mme_context_t {
/* Timer value */
c_uint32_t t3413_value; /* Paging retry timer value */
c_uint32_t s1_holding_timer_value; /* S1 holding timer value */
/* Generator for unique identification */
c_uint32_t mme_ue_s1ap_id; /* mme_ue_s1ap_id generator */
@ -180,6 +181,24 @@ struct _enb_ue_t {
#define S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 4
c_uint8_t ue_ctx_rel_action;
/*
* S1 holding timer
*
* When eNodeB sends Attach Request, TAU Request, Service Request repeatly,
* S1(enb_ue_t) context is repeatly created.
*
* NAS(mme_ue_t) context is associated with last created S1(enb_ue_t)
* context, and older S1(enb_ue_t) context might not be freed.
*
* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context, the holding timer(30secs) is started.
* Newly associated S1(enb_ue_t) context holding timer is stopped.
*
* If the holding timer expires,
* S1(enb_ue_t) context will be implicitly deleted.
*/
tm_block_id holding_timer;
/* Related Context */
mme_enb_t *enb;
mme_ue_t *mme_ue;

View File

@ -24,6 +24,8 @@ char* mme_event_get_name(event_t *e)
return "MME_EVT_S1AP_LO_ACCEPT";
case MME_EVT_S1AP_LO_CONNREFUSED:
return "MME_EVT_S1AP_LO_CONNREFUSED";
case MME_EVT_S1AP_S1_HOLDING_TIMER:
return "MME_EVT_S1AP_S1_HOLDING_TIMER";
case MME_EVT_EMM_MESSAGE:
return "MME_EVT_EMM_MESSAGE";

View File

@ -17,6 +17,7 @@ typedef enum {
MME_EVT_S1AP_DELAYED_SEND,
MME_EVT_S1AP_LO_ACCEPT,
MME_EVT_S1AP_LO_CONNREFUSED,
MME_EVT_S1AP_S1_HOLDING_TIMER,
MME_EVT_EMM_MESSAGE,
MME_EVT_EMM_T3413,

View File

@ -213,6 +213,20 @@ void mme_state_operational(fsm_t *s, event_t *e)
tm_delete(timer);
break;
}
case MME_EVT_S1AP_S1_HOLDING_TIMER:
{
enb_ue_t *enb_ue = NULL;
enb_ue = enb_ue_find(event_get_param1(e));
d_assert(enb_ue, break, "No ENB UE context");
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,,);
break;
}
case MME_EVT_EMM_MESSAGE:
{
nas_message_t message;
@ -260,27 +274,46 @@ void mme_state_operational(fsm_t *s, event_t *e)
}
/* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context, send UE context release command
* to older S1 context. */
* older S1(enb_ue_t) context */
if (mme_ue->enb_ue)
{
#if NOT_WORKING
#if SEND_UE_CTX_REL_CMD_IMMEDIATELY
/* Send UE context release command to
* older S1 context immediately. */
d_trace(5, "OLD ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = s1ap_send_ue_context_release_command(mme_ue->enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
#else
d_assert(rv == CORE_OK, return, "s1ap send error");
#elif IMPLICIT_S1_RELEASE
/* Implcit S1 release */
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#else /* Use Holding Timer */
/* Previous S1(enb_ue_t) context the holding timer(30secs)
* is started.
* Newly associated S1(enb_ue_t) context holding timer
* is stopped. */
d_trace(5, "Start S1 Holding Timer\n");
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
tm_start(mme_ue->enb_ue->holding_timer);
/* De-associate S1 with NAS/EMM */
rv = enb_ue_deassociate(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#endif
}
tm_stop(enb_ue->holding_timer);
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}

View File

@ -160,11 +160,12 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
? mme_ue->imsi_bcd : "Unknown");
/* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context, send UE context release command
* to older S1 context. */
* older S1(enb_ue_t) context */
if (mme_ue->enb_ue)
{
#if NOT_WORKING
#if SEND_UE_CTX_REL_CMD_IMMEDIATELY
/* Send UE context release command to
* older S1 context immediately. */
d_trace(5, "OLD ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
@ -172,15 +173,34 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
#else
#elif IMPLICIT_S1_RELEASE
/* Implcit S1 release */
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#else /* Use Holding Timer */
/* Previous S1(enb_ue_t) context the holding timer(30secs)
* is started.
* Newly associated S1(enb_ue_t) context holding timer
* is stopped. */
d_trace(5, "Start S1 Holding Timer\n");
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
/* De-associate S1 with NAS/EMM */
rv = enb_ue_deassociate(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
tm_start(mme_ue->enb_ue->holding_timer);
#endif
}
tm_stop(enb_ue->holding_timer);
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}
}
@ -538,7 +558,6 @@ void s1ap_handle_ue_context_release_request(
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
d_assert(enb_ue, return, "No ENB UE Context : MME_UE_S1AP_ID[%d]",
ies->mme_ue_s1ap_id);
mme_ue = enb_ue->mme_ue;
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
@ -559,31 +578,42 @@ void s1ap_handle_ue_context_release_request(
break;
}
d_assert(mme_ue,,);
if (mme_ue && FSM_CHECK(&mme_ue->sm, emm_state_registered))
mme_ue = enb_ue->mme_ue;
if (mme_ue)
{
d_trace(5, " EMM-Registered\n");
if (ECM_CONNECTED(mme_ue))
if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
d_trace(5, " ECM-Connected\n");
rv = mme_gtp_send_release_access_bearers_request(mme_ue);
d_assert(rv == CORE_OK, return, "gtp send failed");
d_trace(5, " EMM-Registered\n");
if (ECM_CONNECTED(mme_ue))
{
d_trace(5, " ECM-Connected\n");
rv = mme_gtp_send_release_access_bearers_request(mme_ue);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
else
{
d_trace(5, " ECM-Idle\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
}
else
{
d_trace(5, " ECM-Idle\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
d_trace(5, " NOT EMM-Registered\n");
rv = mme_send_ue_context_release_command(mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_ue_context_release_command failed");
}
}
else
{
d_trace(5, " NOT EMM-Registered\n");
rv = mme_send_ue_context_release_command(mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_ue_context_release_command failed");
d_trace(5, " S1 Context Not Associated\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
}