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:
Robert Schmidt
2025-04-04 07:16:41 +02:00
5 changed files with 78 additions and 7 deletions
+4 -2
View File
@@ -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");
+4
View File
@@ -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 {
+8 -3
View File
@@ -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:
+60 -2
View File
@@ -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)
+2
View File
@@ -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,