Merge remote-tracking branch 'origin/fix-e1-pdu-handling' into integration_2025_w14_p2 (!3255)
Fixes for E1 and PDU session usage Fix a number of problems in E1 and PDU session handling: - For multiple PDU session setup reqs, we send a bearer context setup each time; fix an assert that was triggered on the second bearer context setup message - Add a log for E1 bearer context setup, as already done for modification and release - If we get a PDU session setup for an existing PDU session, reject it as required by the spec [actually, it says to reject individual PDU sessions; keep it simple for now and reject the entire message, which might not be correct if there is one new PDU session that does not exist] - Add a workaround to handle multiple PDU session setup requests that come in quick succession for different PDU sessions
This commit is contained in:
@@ -148,7 +148,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
|
||||
/* mirror the CU-CP UE ID for CU-UP */
|
||||
uint32_t cu_up_ue_id = req->gNB_cu_cp_ue_id;
|
||||
f1_ue_data_t ued = {.secondary_ue = req->gNB_cu_cp_ue_id};
|
||||
if (need_ue_id_mgmt) {
|
||||
if (need_ue_id_mgmt && !cu_exists_f1_ue_data(cu_up_ue_id)) {
|
||||
bool success = cu_add_f1_ue_data(cu_up_ue_id, &ued);
|
||||
DevAssert(success);
|
||||
LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, cu_up_ue_id);
|
||||
@@ -163,8 +163,10 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
|
||||
};
|
||||
resp.numPDUSessions = req->numPDUSessions;
|
||||
for (int i = 0; i < resp.numPDUSessions; ++i) {
|
||||
pdu_session_setup_t *resp_pdu = resp.pduSession + i;
|
||||
const pdu_session_to_setup_t *req_pdu = req->pduSession + i;
|
||||
LOG_I(E1AP, "UE %d: add PDU session ID %ld (%d bearers)\n", cu_up_ue_id, req_pdu->sessionId, req_pdu->numDRB2Setup);
|
||||
|
||||
pdu_session_setup_t *resp_pdu = resp.pduSession + i;
|
||||
resp_pdu->id = req_pdu->sessionId;
|
||||
|
||||
AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n");
|
||||
|
||||
@@ -255,6 +255,10 @@ typedef struct gNB_RRC_UE_s {
|
||||
/* Nas Pdu */
|
||||
ngap_pdu_t nas_pdu;
|
||||
|
||||
/* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */
|
||||
int max_delays_pdu_session;
|
||||
bool ongoing_pdusession_setup_request;
|
||||
|
||||
} gNB_RRC_UE_t;
|
||||
|
||||
typedef struct rrc_gNB_ue_context_s {
|
||||
|
||||
@@ -1666,6 +1666,10 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
|
||||
LOG_E(RRC, "UE %d: Received unexpected transaction type %d for xid %d\n", UE->rrc_ue_id, UE->xids[xid], xid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (UE->xids[xid] == RRC_PDUSESSION_ESTABLISH)
|
||||
UE->ongoing_pdusession_setup_request = false;
|
||||
|
||||
UE->xids[xid] = RRC_ACTION_NONE;
|
||||
for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) {
|
||||
if (UE->xids[i] != RRC_ACTION_NONE) {
|
||||
@@ -2554,9 +2558,10 @@ void *rrc_gnb_task(void *args_p) {
|
||||
break;
|
||||
|
||||
case TIMER_HAS_EXPIRED:
|
||||
/* only this one handled for now */
|
||||
DevAssert(TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id);
|
||||
write_rrc_stats(RC.nrrrc[0]);
|
||||
if (TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id)
|
||||
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;
|
||||
|
||||
case F1AP_INITIAL_UL_RRC_MESSAGE:
|
||||
|
||||
@@ -815,6 +815,29 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
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 < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fill PDU Session Resource Setup Response with a list of PDU Session Resources Failed to Setup
|
||||
* and send ITTI message to TASK_NGAP
|
||||
@@ -871,17 +894,52 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
|
||||
return;
|
||||
}
|
||||
|
||||
// Reject PDU session if at least one exists already with that ID.
|
||||
// At least one because marking one as existing, and setting up another, that
|
||||
// might be more work than is worth it. See 8.2.1.4 in 38.413
|
||||
for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) {
|
||||
const pdusession_t *p = &msg->pdusession_setup_params[i];
|
||||
rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */);
|
||||
if (exist) {
|
||||
LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES};
|
||||
send_ngap_pdu_session_setup_resp_fail(instance, msg, cause);
|
||||
rrc_forward_ue_nas_message(rrc, UE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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->ongoing_pdusession_setup_request)
|
||||
UE->max_delays_pdu_session = 100;
|
||||
|
||||
if (UE->max_delays_pdu_session > 0 && (transaction_ongoing(UE) || UE->ongoing_pdusession_setup_request)) {
|
||||
int wait_us = 10000;
|
||||
LOG_I(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;
|
||||
}
|
||||
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink)) {
|
||||
// Reject PDU Session Resource setup if there's no CU-UP associated
|
||||
LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE};
|
||||
send_ngap_pdu_session_setup_resp_fail(instance, msg, cause);
|
||||
rrc_forward_ue_nas_message(rrc, UE);
|
||||
} else {
|
||||
UE->ongoing_pdusession_setup_request = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session)
|
||||
|
||||
@@ -206,6 +206,8 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id,
|
||||
ue->rrc_ue_id);
|
||||
bool success = cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
|
||||
DevAssert(success);
|
||||
ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */
|
||||
ue->ongoing_pdusession_setup_request = false;
|
||||
|
||||
RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p);
|
||||
LOG_UE_EVENT(ue,
|
||||
|
||||
Reference in New Issue
Block a user