Merge remote-tracking branch 'origin/telnet-o1' into integration_2024_w50 (!3125)

Add support for O1 in O-DU via telnet

This change set adds a simple telnet interface to nr-softmodem. Together
with oai/o1-adapter>, this implements a part of the O1 interface, for
the DU only. Currently supported uses cases:

- some stats are send to an SMO (such as bandwidth, PLMN, frequency, ...)
- re-configuration of bandwidth, frequency
- stop/start of the softmodem, while keeping the CU and L2 running
- the o1-adapter implements two alarms, load overload and base station
  offline, using this interface.

It is possible to use the telnet interface by itself (i.e., "o1" without
the o1-adapter). To do this, compile with telnet support (./build_oai
--build-lib telnetsrv) and start the nr-softmodem with O1 module
(./nr-softmodem --telnetsrv --telnetsrv.shrmod o1). You can then do the
following:

- see some statistics as exposed to o1-adapter, in JSON: echo o1 stats | nc 127.0.0.1 9090 && echo
- stop the L1: echo o1 stop_modem | nc 127.0.0.1 9090 && echo
- reconfigure bandwidth: e.g., echo o1 bwconfig 20 | nc 127.0.0.1 9090 && echo (also supported: 40, 60, 100)
- start the L1: echo o1 start_modem | nc 127.0.0.1 9090 && echo

Note that the reconfiguration works with split-8 radios. Notably, it
does not work yet out-of-the-box with 7.2 radios, because they have to
be manually reconfigured on bandwith/frequency switch. The planned
M-plane should allow such use case, though.

To help with the above, this branch also includes fixes (for more
information, refer to the corresponding commits):

- fixes for stopping the L1, notably stop threads in right order, stop
  thread pool of RU
- collect some general MAC metrics, fix some bugs in MAC
- fix problems in F1AP gNB-DU configuration update message, update test
- fix some problems in RRC
This commit is contained in:
Robert Schmidt
2024-12-16 19:42:28 +01:00
35 changed files with 944 additions and 168 deletions
+6 -2
View File
@@ -920,10 +920,14 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc
}
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay)
{
//TODO change to accomodate for SRS
const NR_PUSCH_TimeDomainResourceAllocationList_t *tda =
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n");
frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
const int k2 = min_fb_delay;
+28 -16
View File
@@ -106,6 +106,21 @@ extern RAN_CONTEXT_t RC;
mui_t rrc_gNB_mui = 0;
typedef struct deliver_ue_ctxt_release_data_t {
gNB_RRC_INST *rrc;
f1ap_ue_context_release_cmd_t *release_cmd;
sctp_assoc_t assoc_id;
} deliver_ue_ctxt_release_data_t;
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data != NULL);
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
data->release_cmd->rrc_container = (uint8_t*) buf;
data->release_cmd->rrc_container_length = size;
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
}
///---------------------------------------------------------------------------------------------------------------///
///---------------------------------------------------------------------------------------------------------------///
@@ -1974,8 +1989,18 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id);
// TODO what happens if no AMF connected? should also handle, set an_release true
if (!ue_context_p) {
LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", req->gNB_CU_ue_id);
// TODO just request the DU to release to make it happy
LOG_W(RRC, "could not find UE context for CU UE ID %u: auto-generate release command\n", req->gNB_CU_ue_id);
uint8_t buffer[RRC_BUF_SIZE] = {0};
int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(0));
f1ap_ue_context_release_cmd_t ue_context_release_cmd = {
.gNB_CU_ue_id = req->gNB_CU_ue_id,
.gNB_DU_ue_id = req->gNB_DU_ue_id,
.cause = F1AP_CAUSE_RADIO_NETWORK,
.cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release
.srb_id = DCCH,
};
deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd};
nr_pdcp_data_req_srb(req->gNB_CU_ue_id, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data);
return;
}
@@ -2473,6 +2498,7 @@ void *rrc_gnb_task(void *args_p) {
switch (ITTI_MSG_ID(msg_p)) {
case TERMINATE_MESSAGE:
LOG_W(NR_RRC, " *** Exiting NR_RRC thread\n");
timer_remove(stats_timer_id);
itti_exit_task();
break;
@@ -2645,20 +2671,6 @@ void rrc_gNB_generate_SecurityModeCommand(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size);
}
typedef struct deliver_ue_ctxt_release_data_t {
gNB_RRC_INST *rrc;
f1ap_ue_context_release_cmd_t *release_cmd;
sctp_assoc_t assoc_id;
} deliver_ue_ctxt_release_data_t;
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data != NULL);
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
data->release_cmd->rrc_container = (uint8_t*) buf;
data->release_cmd->rrc_container_length = size;
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
}
//-----------------------------------------------------------------------------
/*
* Generate the RRC Connection Release to UE.
+4 -4
View File
@@ -448,7 +448,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i
f1ap_served_cell_info_t *ci = &du->setup_req->cell[0].info;
// make sure no memory is allocated
free_f1ap_cell(ci, NULL);
copy_f1ap_served_cell_info(ci, new_ci);
*ci = copy_f1ap_served_cell_info(new_ci);
NR_MeasurementTimingConfiguration_t *new_mtc =
extract_mtc(new_ci->measurement_timing_config, new_ci->measurement_timing_config_len);
@@ -505,8 +505,10 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
// MIB is mandatory, so will be overwritten. SIB1 is optional, so will
// only be overwritten if present in sys_info
ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib);
if (sys_info->sib1 != NULL)
if (sys_info->sib1 != NULL) {
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
du->sib1 = NULL;
}
NR_MIB_t *mib = NULL;
if (!extract_sys_info(sys_info, &mib, &du->sib1)) {
@@ -531,8 +533,6 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
/* Send DU Configuration Acknowledgement */
f1ap_gnb_du_configuration_update_acknowledge_t ack = {.transaction_id = conf_up->transaction_id};
rrc->mac_rrc.gnb_du_configuration_update_acknowledge(assoc_id, &ack);
/* free F1AP message after use */
free_f1ap_du_configuration_update(conf_up);
}
void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)