Free DU at CU on lost connection, store assoc ID
- store the assoc ID of a UE at the RRC - if F1 receives an SCTP shutdown, it removes the endpoint - F1 will also send an "F1 Lost Connection" message to the RRC - it is not yet possible to reconnect a DU after it had already been connected at the CU, since the CU F1AP task will try to rebind GTP, which fails
This commit is contained in:
@@ -32,6 +32,9 @@ MESSAGE_DEF(F1AP_SETUP_RESP , MESSAGE_PRIORITY_MED, f1ap_setup_resp_t
|
||||
MESSAGE_DEF(F1AP_SETUP_FAILURE , MESSAGE_PRIORITY_MED, f1ap_setup_failure_t , f1ap_setup_failure)
|
||||
MESSAGE_DEF(F1AP_GNB_CU_CONFIGURATION_UPDATE , MESSAGE_PRIORITY_MED, f1ap_gnb_cu_configuration_update_t , f1ap_gnb_cu_configuration_update)
|
||||
|
||||
/* F1AP -> RRC to inform about lost connection */
|
||||
MESSAGE_DEF(F1AP_LOST_CONNECTION, MESSAGE_PRIORITY_MED, f1ap_lost_connection_t, f1ap_lost_connection)
|
||||
|
||||
/* MAC -> F1AP messages */
|
||||
MESSAGE_DEF(F1AP_INITIAL_UL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_initial_ul_rrc_message_t , f1ap_initial_ul_rrc_message)
|
||||
MESSAGE_DEF(F1AP_UL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_ul_rrc_message_t , f1ap_ul_rrc_message)
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#define F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_gnb_cu_configuration_update_failure
|
||||
#define F1AP_SETUP_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_setup_failure
|
||||
|
||||
#define F1AP_LOST_CONNECTION(mSGpTR) (mSGpTR)->ittiMsg.f1ap_lost_connection
|
||||
|
||||
#define F1AP_INITIAL_UL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_initial_ul_rrc_message
|
||||
#define F1AP_UL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ul_rrc_message
|
||||
#define F1AP_UE_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_req
|
||||
@@ -405,4 +407,8 @@ typedef struct f1ap_paging_ind_s {
|
||||
uint8_t paging_drx;
|
||||
} f1ap_paging_ind_t;
|
||||
|
||||
typedef struct f1ap_lost_connection_t {
|
||||
int dummy;
|
||||
} f1ap_lost_connection_t;
|
||||
|
||||
#endif /* F1AP_MESSAGES_TYPES_H_ */
|
||||
|
||||
@@ -63,3 +63,13 @@ void createF1inst(instance_t instanceP, f1ap_setup_req_t *req, f1ap_net_config_t
|
||||
f1_inst[0]->net_config = *nc;
|
||||
pthread_mutex_unlock(&f1_inst_mtx);
|
||||
}
|
||||
|
||||
void destroyF1inst(instance_t instance)
|
||||
{
|
||||
DevAssert(instance == 0);
|
||||
pthread_mutex_lock(&f1_inst_mtx);
|
||||
AssertFatal(f1_inst[0] != NULL, "Attempted to free uninitialized F1 instances\n");
|
||||
free(f1_inst[instance]);
|
||||
f1_inst[instance] = NULL;
|
||||
pthread_mutex_unlock(&f1_inst_mtx);
|
||||
}
|
||||
|
||||
@@ -418,6 +418,7 @@ uint8_t F1AP_get_next_transaction_identifier(instance_t mod_idP, instance_t cu_m
|
||||
f1ap_cudu_inst_t *getCxt(instance_t instanceP);
|
||||
|
||||
void createF1inst(instance_t instanceP, f1ap_setup_req_t *req, f1ap_net_config_t *nc);
|
||||
void destroyF1inst(instance_t instance);
|
||||
|
||||
//lts: C struct type is not homogeneous, so we need macros instead of functions
|
||||
#define addnRCGI(nRCGi, servedCelL) \
|
||||
|
||||
@@ -94,6 +94,7 @@ int CU_handle_F1_SETUP_REQUEST(instance_t instance,
|
||||
}
|
||||
|
||||
MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_SETUP_REQ);
|
||||
message_p->ittiMsgHeader.originInstance = assoc_id;
|
||||
f1ap_setup_req_t *req = &F1AP_SETUP_REQ(message_p);
|
||||
/* gNB_DU_id */
|
||||
// this function exits if the ie is mandatory
|
||||
|
||||
@@ -71,6 +71,18 @@ static void cu_task_handle_sctp_association_ind(instance_t instance,
|
||||
static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
|
||||
DevAssert(sctp_new_association_resp != NULL);
|
||||
|
||||
if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) {
|
||||
f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance);
|
||||
AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n");
|
||||
LOG_I(F1AP, "Received SCTP shutdown for assoc_id %d, removing endpoint\n", sctp_new_association_resp->assoc_id);
|
||||
destroyF1inst(instance);
|
||||
/* inform RRC that the DU is gone */
|
||||
MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_LOST_CONNECTION);
|
||||
message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id;
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
||||
LOG_W(F1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n",
|
||||
sctp_new_association_resp->sctp_state,
|
||||
|
||||
@@ -369,6 +369,7 @@ typedef struct cucp_cuup_if_s {
|
||||
} cucp_cuup_if_t;
|
||||
|
||||
typedef struct nr_rrc_du_container_t {
|
||||
int assoc_id;
|
||||
f1ap_setup_req_t *setup_req;
|
||||
NR_MIB_t *mib;
|
||||
NR_SIB1_t *sib1;
|
||||
|
||||
@@ -1801,12 +1801,12 @@ static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell
|
||||
&& rrc->nr_cellid == info->nr_cellid;
|
||||
}
|
||||
|
||||
static void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req)
|
||||
static void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, int assoc_id)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[0];
|
||||
DevAssert(rrc);
|
||||
|
||||
LOG_I(NR_RRC, "Received F1 Setup Request from gNB_DU %lu (%s)\n", req->gNB_DU_id, req->gNB_DU_name);
|
||||
LOG_I(NR_RRC, "Received F1 Setup Request from gNB_DU %lu (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id);
|
||||
|
||||
// check:
|
||||
// - it is the first DU
|
||||
@@ -1876,6 +1876,7 @@ static void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req)
|
||||
// we accept the DU
|
||||
rrc->du = calloc(1, sizeof(*rrc->du));
|
||||
AssertFatal(rrc->du != NULL, "out of memory\n");
|
||||
rrc->du->assoc_id = assoc_id;
|
||||
|
||||
/* ITTI will free the setup request message via free(). So the memory
|
||||
* "inside" of the message will remain, but the "outside" container no, so
|
||||
@@ -2423,6 +2424,21 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
|
||||
prepare_and_send_ue_context_modification_f1(ue_context_p, resp);
|
||||
}
|
||||
|
||||
static void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, int assoc_id)
|
||||
{
|
||||
AssertFatal(rrc->du != NULL, "no DU connected, cannot received F1 lost connection\n");
|
||||
AssertFatal(rrc->du->assoc_id == assoc_id,
|
||||
"previously connected DU (%d) does not match DU for which connection has been lost (%d)\n",
|
||||
rrc->du->assoc_id,
|
||||
assoc_id);
|
||||
(void) lc; // unused for the moment
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, rrc->du->mib);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, rrc->du->sib1);
|
||||
free(rrc->du);
|
||||
rrc->du = NULL;
|
||||
LOG_I(RRC, "dropping DU with assoc_id %d (UE connections remain, if any)\n", assoc_id);
|
||||
}
|
||||
|
||||
static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults)
|
||||
{
|
||||
DevAssert(measresults->measResultServingMOList.list.count >= 1);
|
||||
@@ -2621,7 +2637,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
/* Messages from F1AP task */
|
||||
case F1AP_SETUP_REQ:
|
||||
AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n");
|
||||
rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p));
|
||||
rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p), msg_p->ittiMsgHeader.originInstance);
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_SETUP_RESP:
|
||||
@@ -2644,6 +2660,10 @@ void *rrc_gnb_task(void *args_p) {
|
||||
rrc_CU_process_ue_context_release_complete(msg_p);
|
||||
break;
|
||||
|
||||
case F1AP_LOST_CONNECTION:
|
||||
rrc_CU_process_f1_lost_connection(RC.nrrrc[0], &F1AP_LOST_CONNECTION(msg_p), msg_p->ittiMsgHeader.originInstance);
|
||||
break;
|
||||
|
||||
/* Messages from X2AP */
|
||||
case X2AP_ENDC_SGNB_ADDITION_REQ:
|
||||
LOG_I(NR_RRC, "Received ENDC sgNB addition request from X2AP \n");
|
||||
|
||||
Reference in New Issue
Block a user