Merge remote-tracking branch 'origin/gnb-du-config-cell-status' into integration_2025_w18 (!3416)
Signal gNB-DU config update CellStatus from DU to CU Add the cell status to gNB-DU configuration update message, including test. Use the gNB-DU configuration update to signal the cell status in the stack. This IE was not included in a previous refactoring round, but is at least necessary to be decoded when interoperating with the OSC O-DU.
This commit is contained in:
@@ -262,6 +262,13 @@ typedef struct f1ap_gnb_cu_configuration_update_failure_s {
|
||||
uint16_t criticality_diagnostics;
|
||||
} f1ap_gnb_cu_configuration_update_failure_t;
|
||||
|
||||
typedef struct f1ap_cell_status_t {
|
||||
// NR CGI
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
enum { F1AP_STATE_IN_SERVICE, F1AP_STATE_OUT_OF_SERVICE} service_state;
|
||||
} f1ap_cell_status_t;
|
||||
|
||||
/*DU configuration messages*/
|
||||
typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
/*TODO UPDATE TO SUPPORT DU CONFIG*/
|
||||
@@ -291,6 +298,10 @@ typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
} cell_to_delete[F1AP_MAX_NB_CELLS];
|
||||
|
||||
f1ap_cell_status_t status[F1AP_MAX_NB_CELLS];
|
||||
int num_status;
|
||||
|
||||
/// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1)
|
||||
uint64_t *gNB_DU_ID;
|
||||
} f1ap_gnb_du_configuration_update_t;
|
||||
|
||||
@@ -1455,6 +1455,28 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->num_status > 0) {
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie4);
|
||||
ie4->id = F1AP_ProtocolIE_ID_id_Cells_Status_List;
|
||||
ie4->criticality = F1AP_Criticality_reject;
|
||||
ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Cells_Status_List;
|
||||
for (int i = 0; i < msg->num_status; i++) {
|
||||
const f1ap_cell_status_t *cs = &msg->status[i];
|
||||
asn1cSequenceAdd(ie4->value.choice.Cells_Status_List.list, F1AP_Cells_Status_ItemIEs_t, cell_status);
|
||||
cell_status->id = F1AP_ProtocolIE_ID_id_Cells_Status_Item;
|
||||
cell_status->criticality = F1AP_Criticality_reject;
|
||||
cell_status->value.present = F1AP_Cells_Status_ItemIEs__value_PR_Cells_Status_Item;
|
||||
F1AP_Cells_Status_Item_t *cell_status_item = &cell_status->value.choice.Cells_Status_Item;
|
||||
|
||||
F1AP_NRCGI_t *nrcgi = &cell_status_item->nRCGI;
|
||||
MCC_MNC_TO_PLMNID(cs->plmn.mcc, cs->plmn.mnc, cs->plmn.mnc_digit_length, &nrcgi->pLMN_Identity);
|
||||
NR_CELL_ID_TO_BIT_STRING(cs->nr_cellid, &nrcgi->nRCellIdentity);
|
||||
F1AP_Service_Status_t *ss = &cell_status_item->service_status;
|
||||
ss->service_state =
|
||||
cs->service_state == F1AP_STATE_IN_SERVICE ? F1AP_Service_State_in_service : F1AP_Service_State_out_of_service;
|
||||
}
|
||||
}
|
||||
|
||||
/* optional */
|
||||
/* c5. GNB_DU_ID (integer value) */
|
||||
if (msg->gNB_DU_ID != NULL) {
|
||||
@@ -1551,7 +1573,21 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
} break;
|
||||
case F1AP_ProtocolIE_ID_id_Cells_Status_List:
|
||||
/* Cells Status List (O) */
|
||||
AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_Cells_Status_List is not supported");
|
||||
out->num_status = ie->value.choice.Cells_Status_List.list.count;
|
||||
for (int i = 0; i < out->num_status; ++i) {
|
||||
const F1AP_Cells_Status_ItemIEs_t *csi_ie =
|
||||
(F1AP_Cells_Status_ItemIEs_t *)ie->value.choice.Cells_Status_List.list.array[i];
|
||||
AssertError(csi_ie->value.present == F1AP_Cells_Status_ItemIEs__value_PR_Cells_Status_Item,
|
||||
return false,
|
||||
"CellStatus_ItemIE has no cell status\n");
|
||||
const F1AP_Cells_Status_Item_t *f1ap_cell_status = &csi_ie->value.choice.Cells_Status_Item;
|
||||
const F1AP_NRCGI_t *nrcgi = &f1ap_cell_status->nRCGI;
|
||||
f1ap_cell_status_t *cs = &out->status[i];
|
||||
PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, cs->plmn.mcc, cs->plmn.mnc, cs->plmn.mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, cs->nr_cellid);
|
||||
F1AP_Service_State_t state = f1ap_cell_status->service_status.service_state;
|
||||
cs->service_state = state == F1AP_Service_State_in_service ? F1AP_STATE_IN_SERVICE : F1AP_STATE_OUT_OF_SERVICE;
|
||||
}
|
||||
break;
|
||||
case F1AP_ProtocolIE_ID_id_Dedicated_SIDelivery_NeededUE_List:
|
||||
/* Dedicated SI Delivery Needed UE List (O) */
|
||||
@@ -1618,6 +1654,16 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
/* cell status */
|
||||
_F1_EQ_CHECK_INT(a->num_status, b->num_status);
|
||||
for (int i = 0; i < a->num_status; ++i) {
|
||||
const f1ap_cell_status_t *astatus = &a->status[i];
|
||||
const f1ap_cell_status_t *bstatus = &b->status[i];
|
||||
if (!eq_f1ap_plmn(&astatus->plmn, &bstatus->plmn))
|
||||
return false;
|
||||
_F1_EQ_CHECK_LONG(astatus->nr_cellid, bstatus->nr_cellid);
|
||||
_F1_EQ_CHECK_INT(astatus->service_state, bstatus->service_state);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1654,6 +1700,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
cp.cell_to_modify[i].info = copy_f1ap_served_cell_info(&msg->cell_to_modify[i].info);
|
||||
cp.cell_to_modify[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_modify[i].sys_info);
|
||||
}
|
||||
/* cell status */
|
||||
cp.num_status = msg->num_status;
|
||||
for (int i = 0; i < cp.num_status; ++i)
|
||||
cp.status[i] = msg->status[i];
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
@@ -564,6 +564,17 @@ static void test_f1ap_du_configuration_update(void)
|
||||
.cell_to_delete[0].plmn.mcc = 1,
|
||||
.cell_to_delete[0].plmn.mnc = 1,
|
||||
.cell_to_delete[0].plmn.mnc_digit_length = 3,
|
||||
.num_status = 2,
|
||||
.status[0].nr_cellid = 542UL,
|
||||
.status[0].plmn.mcc = 1,
|
||||
.status[0].plmn.mnc = 2,
|
||||
.status[0].plmn.mnc_digit_length = 3,
|
||||
.status[0].service_state = F1AP_STATE_IN_SERVICE,
|
||||
.status[1].nr_cellid = 33UL,
|
||||
.status[1].plmn.mcc = 5,
|
||||
.status[1].plmn.mnc = 13,
|
||||
.status[1].plmn.mnc_digit_length = 2,
|
||||
.status[1].service_state = F1AP_STATE_OUT_OF_SERVICE,
|
||||
};
|
||||
orig.cell_to_modify[0].sys_info = calloc_or_fail(1, sizeof(*orig.cell_to_modify[0].sys_info));
|
||||
*orig.cell_to_modify[0].sys_info = sys_info;
|
||||
|
||||
@@ -942,11 +942,17 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac,
|
||||
/* send gNB-DU configuration update to RRC */
|
||||
f1ap_gnb_du_configuration_update_t update = {
|
||||
.transaction_id = 1,
|
||||
.num_cells_to_modify = 1,
|
||||
.num_status = 1,
|
||||
.status[0].plmn = info->plmn,
|
||||
.status[0].nr_cellid = info->nr_cellid,
|
||||
.status[0].service_state = F1AP_STATE_IN_SERVICE,
|
||||
};
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1, NULL);
|
||||
if (mib && sib1) {
|
||||
update.num_cells_to_modify = 1,
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1, NULL);
|
||||
}
|
||||
mac->mac_rrc.gnb_du_configuration_update(&update);
|
||||
}
|
||||
|
||||
|
||||
@@ -168,18 +168,25 @@ void f1_setup_response(const f1ap_setup_resp_t *resp)
|
||||
|
||||
// we can configure other SIB only after having received the ones generated by CU
|
||||
bool update = nr_mac_configure_other_sib(mac, cu_cell->num_SI, cu_cell->SI_msg);
|
||||
/* only if we have to update SIB1, set mib and sib1 to non-NULL to indicate
|
||||
* in du_config_update that it has changed (otherwise, gNB-DU config update
|
||||
* indicates only cell status */
|
||||
NR_BCCH_BCH_Message_t *mib = NULL;
|
||||
NR_BCCH_DL_SCH_Message_t *sib1 = NULL;
|
||||
if (update) {
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
f1ap_served_cell_info_t *info = &sr->cell[0].info;
|
||||
NR_COMMON_channels_t *cc = &mac->common_channels[0];
|
||||
prepare_du_configuration_update(mac, info, cc->mib, cc->sib1);
|
||||
mib = cc->mib;
|
||||
sib1 = cc->sib1;
|
||||
}
|
||||
|
||||
mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp));
|
||||
AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n");
|
||||
// Copy F1AP message
|
||||
*mac->f1_config.setup_resp = cp_f1ap_setup_response(resp);
|
||||
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
prepare_du_configuration_update(mac, &sr->cell[0].info, mib, sib1);
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
// NOTE: Before accepting any UEs, we should initialize the UE states.
|
||||
|
||||
@@ -111,7 +111,7 @@ static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t
|
||||
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_MIB, (void **)mib, sys_info->mib, sys_info->mib_length);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_E(RRC, "Failed to decode NR_MIB (%zu bits) of DU\n", dec_rval.consumed);
|
||||
LOG_E(NR_RRC, "Failed to decode NR_MIB (%zu bits) of DU\n", dec_rval.consumed);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, *mib);
|
||||
return false;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t
|
||||
if (dec_rval.code != RC_OK) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, *mib);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, *sib1);
|
||||
LOG_E(RRC, "Failed to decode NR_SIB1 (%zu bits), rejecting DU\n", dec_rval.consumed);
|
||||
LOG_E(NR_RRC, "Failed to decode NR_SIB1 (%zu bits), rejecting DU\n", dec_rval.consumed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ static NR_MeasurementTimingConfiguration_t *extract_mtc(uint8_t *buf, int buf_le
|
||||
|| mtc->criticalExtensions.choice.c1->choice.measTimingConf == NULL
|
||||
|| mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming == NULL
|
||||
|| mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming->list.count == 0) {
|
||||
LOG_E(RRC, "error: measurementTimingConfiguration does not have expected format (at least one measTiming entry\n");
|
||||
LOG_E(NR_RRC, "error: measurementTimingConfiguration does not have expected format (at least one measTiming entry\n");
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
@@ -370,15 +370,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
|
||||
if (sys_info != NULL && sys_info->mib != NULL && !(sys_info->sib1 == NULL && IS_SA_MODE(get_softmodem_params()))) {
|
||||
if (!extract_sys_info(sys_info, &mib, &sib1)) {
|
||||
LOG_W(RRC, "rejecting DU ID %ld\n", req->gNB_DU_id);
|
||||
LOG_W(NR_RRC, "rejecting DU ID %ld\n", req->gNB_DU_id);
|
||||
fail.cause = F1AP_CauseProtocol_semantic_error;
|
||||
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
|
||||
LOG_I(RRC, "DU uses RRC version %u.%u.%u\n", req->rrc_ver[0], req->rrc_ver[1], req->rrc_ver[2]);
|
||||
LOG_I(NR_RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
|
||||
LOG_I(NR_RRC, "DU uses RRC version %u.%u.%u\n", req->rrc_ver[0], req->rrc_ver[1], req->rrc_ver[2]);
|
||||
|
||||
// we accept the DU
|
||||
nr_rrc_du_container_t *du = calloc(1, sizeof(*du));
|
||||
@@ -497,7 +497,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc);
|
||||
du->mtc = new_mtc;
|
||||
} else {
|
||||
LOG_E(RRC, "error decoding MeasurementTimingConfiguration during cell update, ignoring new config\n");
|
||||
LOG_E(NR_RRC, "error decoding MeasurementTimingConfiguration during cell update, ignoring new config\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, new_mtc);
|
||||
}
|
||||
}
|
||||
@@ -520,7 +520,7 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
const f1ap_served_cell_info_t *info = &du->setup_req->cell[0].info;
|
||||
if (conf_up->num_cells_to_add > 0) {
|
||||
// Here we check if the number of cell limit is respectet, otherwise send failure
|
||||
LOG_W(RRC, "du_configuration_update->cells_to_add_list is not supported yet");
|
||||
LOG_W(NR_RRC, "du_configuration_update->cells_to_add_list is not supported yet");
|
||||
}
|
||||
|
||||
if (conf_up->num_cells_to_modify > 0) {
|
||||
@@ -528,13 +528,13 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
AssertFatal(conf_up->num_cells_to_modify == 1, "cannot handle more than one cell!\n");
|
||||
|
||||
if (info->nr_cellid != conf_up->cell_to_modify[0].old_nr_cellid) {
|
||||
LOG_W(RRC, "no cell with ID %ld found, ignoring gNB-DU configuration update\n", conf_up->cell_to_modify[0].old_nr_cellid);
|
||||
LOG_W(NR_RRC, "no cell with ID %ld found, ignoring gNB-DU configuration update\n", conf_up->cell_to_modify[0].old_nr_cellid);
|
||||
return;
|
||||
}
|
||||
|
||||
// verify the new plmn of the cell
|
||||
if (!rrc_gNB_plmn_matches(rrc, &conf_up->cell_to_modify[0].info)) {
|
||||
LOG_W(RRC, "PLMN does not match, ignoring gNB-DU configuration update\n");
|
||||
LOG_W(NR_RRC, "PLMN does not match, ignoring gNB-DU configuration update\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -553,11 +553,11 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
|
||||
NR_MIB_t *mib = NULL;
|
||||
if (!extract_sys_info(sys_info, &mib, &du->sib1)) {
|
||||
LOG_W(RRC, "cannot update sys_info for DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
LOG_W(NR_RRC, "cannot update sys_info for DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
} else {
|
||||
DevAssert(mib != NULL);
|
||||
du->mib = mib;
|
||||
LOG_I(RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
LOG_I(NR_RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
}
|
||||
}
|
||||
if (du->mib != NULL && du->sib1 != NULL) {
|
||||
@@ -568,7 +568,14 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
|
||||
if (conf_up->num_cells_to_delete > 0) {
|
||||
// delete the cell and send cell to desactive IE in the response.
|
||||
LOG_W(RRC, "du_configuration_update->cells_to_delete_list is not supported yet");
|
||||
LOG_W(NR_RRC, "du_configuration_update->cells_to_delete_list is not supported yet");
|
||||
}
|
||||
|
||||
for (int i = 0; i < conf_up->num_status; ++i) {
|
||||
const f1ap_cell_status_t *cs = &conf_up->status[i];
|
||||
const char *status = cs->service_state == F1AP_STATE_IN_SERVICE ? "in service" : "out of service";
|
||||
const plmn_id_t *p = &cs->plmn;
|
||||
LOG_I(NR_RRC, "cell PLMN %03d.%0*d Cell ID %ld is %s\n", p->mcc, p->mnc_digit_length, p->mnc, cs->nr_cellid, status);
|
||||
}
|
||||
|
||||
/* Send DU Configuration Acknowledgement */
|
||||
@@ -589,7 +596,7 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t
|
||||
}
|
||||
|
||||
f1ap_setup_req_t *req = du->setup_req;
|
||||
LOG_I(RRC, "releasing DU ID %ld (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id);
|
||||
LOG_I(NR_RRC, "releasing DU ID %ld (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc);
|
||||
|
||||
Reference in New Issue
Block a user