Commit 0f100a6e authored by Robert Schmidt's avatar Robert Schmidt

Delay PDU session resource setup request if necessary

The next commit moves the UE Capability Enquiry after the first
reconfiguration. This has the effect that for some UEs (e.g., iPhone),
the Setup Requests come too close to each other, triggering RRC
Reconfigurations while previous transactions are ongoing.

I think the "true" solution would be to implement some tracking of
transactions across RRC, F1AP, E1AP, but this might require many
changes. For the moment, limit to delaying PDU session resource setups
to prevent above problem. Delaying is done using ITTI timers (to be able
to serve other UEs), waiting 10ms each time, up to 20 times (to not
deadlock the transaction -- after all, if the UE is unhappy, it will
drop the connection).
parent d6dd87ae
...@@ -308,6 +308,9 @@ typedef struct gNB_RRC_UE_s { ...@@ -308,6 +308,9 @@ typedef struct gNB_RRC_UE_s {
/* Nas Pdu */ /* Nas Pdu */
ngap_pdu_t nas_pdu; ngap_pdu_t nas_pdu;
/* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */
int max_delays_pdu_session;
} gNB_RRC_UE_t; } gNB_RRC_UE_t;
typedef struct rrc_gNB_ue_context_s { typedef struct rrc_gNB_ue_context_s {
......
...@@ -2246,9 +2246,10 @@ void *rrc_gnb_task(void *args_p) { ...@@ -2246,9 +2246,10 @@ void *rrc_gnb_task(void *args_p) {
break; break;
case TIMER_HAS_EXPIRED: case TIMER_HAS_EXPIRED:
/* only this one handled for now */ if (TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id)
DevAssert(TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id); write_rrc_stats(RC.nrrrc[0]);
write_rrc_stats(RC.nrrrc[0]); else
itti_send_msg_to_task(TASK_RRC_GNB, 0, TIMER_HAS_EXPIRED(msg_p).arg); /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */
break; break;
case F1AP_INITIAL_UL_RRC_MESSAGE: case F1AP_INITIAL_UL_RRC_MESSAGE:
......
...@@ -820,6 +820,28 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( ...@@ -820,6 +820,28 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(
return; return;
} }
/* \brief checks if any transaction is ongoing for any xid of this UE */
static bool transaction_ongoing(const gNB_RRC_UE_t *UE)
{
for (int xid = 0; xid < 4; ++xid)
if (UE->xids[xid] != RRC_ACTION_NONE)
return true;
return false;
}
/* \brief delays the ongoing transaction (in msg_p) by setting a timer to wait
* 10ms; upon expiry, delivers to RRC, which sends the message to itself */
static void delay_transaction(MessageDef *msg_p, int wait_us)
{
MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQ);
ngap_pdusession_setup_req_t *n = &NGAP_PDUSESSION_SETUP_REQ(new);
*n = NGAP_PDUSESSION_SETUP_REQ(msg_p);
int instance = msg_p->ittiMsgHeader.originInstance;
long timer_id;
timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance) void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
...@@ -845,6 +867,24 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins ...@@ -845,6 +867,24 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n"); AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n");
UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; UE->amf_ue_ngap_id = msg->amf_ue_ngap_id;
/* This is a hack. We observed that with some UEs, PDU session requests might
* come in quick succession, faster than the RRC reconfiguration for the PDU
* session requests can be carried out (UE is doing reconfig, and second PDU
* session request arrives). We don't have currently the means to "queue up"
* these transactions, which would probably involve some rework of the RRC.
* To still allow these requests to come in and succeed, we below check and delay transactions
* for 10ms. However, to not accidentally end up in infinite loops, the
* maximum number is capped on a per-UE basis as indicated in variable
* max_delays_pdu_session. */
if (UE->max_delays_pdu_session > 0 && transaction_ongoing(UE)) {
int wait_us = 10000;
LOG_D(RRC, "UE %d: delay PDU session setup by %d us, pending %d retries\n", UE->rrc_ue_id, wait_us, UE->max_delays_pdu_session);
delay_transaction(msg_p, wait_us);
UE->max_delays_pdu_session--;
return;
}
trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink); trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink);
return; return;
} }
......
...@@ -188,6 +188,7 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, ...@@ -188,6 +188,7 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id,
"UE F1 Context for ID %d already exists, logic bug\n", "UE F1 Context for ID %d already exists, logic bug\n",
ue->rrc_ue_id); ue->rrc_ue_id);
cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data); cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */
RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p); RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p);
LOG_I(NR_RRC, LOG_I(NR_RRC,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment