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
+3
View File
@@ -145,6 +145,9 @@ f1ap_cudu_inst_t *getCxt(instance_t instanceP)
return &fake;
}
configmodule_interface_t *uniqCfg = NULL;
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id) { };
int main(int argc, char **argv)
{
/// static configuration for NR at the moment
+7 -3
View File
@@ -383,12 +383,16 @@ void init_gNB_Tpool(int inst) {
void term_gNB_Tpool(int inst) {
PHY_VARS_gNB *gNB = RC.gNB[inst];
abortTpool(&gNB->threadPool);
abortNotifiedFIFO(&gNB->respDecode);
abortNotifiedFIFO(&gNB->resp_L1);
pthread_join(gNB->L1_rx_thread, NULL);
abortNotifiedFIFO(&gNB->L1_tx_out);
pthread_join(gNB->L1_tx_thread, NULL);
abortTpool(&gNB->threadPool);
abortNotifiedFIFO(&gNB->respPuschSymb);
abortNotifiedFIFO(&gNB->respDecode);
abortNotifiedFIFO(&gNB->L1_tx_free);
abortNotifiedFIFO(&gNB->L1_tx_filled);
abortNotifiedFIFO(&gNB->L1_tx_out);
abortNotifiedFIFO(&gNB->L1_rx_out);
gNB_L1_proc_t *proc = &gNB->proc;
+6
View File
@@ -1443,6 +1443,12 @@ void kill_NR_RU_proc(int inst) {
RU_t *ru = RC.ru[inst];
RU_proc_t *proc = &ru->proc;
if (ru->if_south != REMOTE_IF4p5) {
abortTpool(ru->threadPool);
abortNotifiedFIFO(ru->respfeprx);
abortNotifiedFIFO(ru->respfeptx);
}
/* Note: it seems pthread_FH and and FEP thread below both use
* mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do
* the same for FEP thread below again (using broadcast() to ensure both
+101 -24
View File
@@ -401,6 +401,105 @@ void terminate_task(task_id_t task_id, module_id_t mod_id) {
//extern void free_transport(PHY_VARS_gNB *);
extern void nr_phy_free_RU(RU_t *);
int stop_L1(module_id_t gnb_id)
{
RU_t *ru = RC.ru[gnb_id];
if (!ru) {
LOG_W(GNB_APP, "no RU configured\n");
return -1;
}
if (!RC.gNB[gnb_id]->configured) {
LOG_W(GNB_APP, "L1 already stopped\n");
return -1;
}
LOG_I(GNB_APP, "stopping nr-softmodem\n");
oai_exit = 1;
/* these tasks/layers need to pick up new configuration */
if (RC.nb_nr_L1_inst > 0)
stop_gNB(RC.nb_nr_L1_inst);
if (RC.nb_RU > 0)
stop_RU(RC.nb_RU);
/* stop trx devices, multiple carrier currently not supported by RU */
if (ru->rfdevice.trx_stop_func) {
ru->rfdevice.trx_stop_func(&ru->rfdevice);
LOG_I(GNB_APP, "turned off RU rfdevice\n");
}
if (ru->ifdevice.trx_stop_func) {
ru->ifdevice.trx_stop_func(&ru->ifdevice);
LOG_I(GNB_APP, "turned off RU ifdevice\n");
}
/* release memory used by the RU/gNB threads (incomplete), after all
* threads have been stopped (they partially use the same memory) */
for (int inst = 0; inst < RC.nb_RU; inst++) {
nr_phy_free_RU(RC.ru[inst]);
}
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
phy_free_nr_gNB(RC.gNB[inst]);
}
RC.gNB[gnb_id]->configured = 0;
return 0;
}
/*
* Restart the nr-softmodem after it has been soft-stopped with stop_L1L2()
*/
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
int start_L1L2(module_id_t gnb_id)
{
LOG_I(GNB_APP, "starting nr-softmodem\n");
/* block threads */
oai_exit = 0;
sync_var = -1;
extern void init_sched_response(void);
init_sched_response();
/* update config */
gNB_MAC_INST *mac = RC.nrmac[0];
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
nr_mac_config_scc(mac, scc, &mac->radio_config);
NR_BCCH_BCH_Message_t *mib = mac->common_channels[0].mib;
const NR_BCCH_DL_SCH_Message_t *sib1 = mac->common_channels[0].sib1;
/* update existing config in F1 Setup request structures */
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;
DevAssert(info->mode == F1AP_MODE_TDD);
DevAssert(scc->tdd_UL_DL_ConfigurationCommon != NULL);
info->tdd = read_tdd_config(scc); /* updates radio config */
/* send gNB-DU configuration update to RRC */
f1ap_gnb_du_configuration_update_t update = {
.transaction_id = 1,
.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);
mac->mac_rrc.gnb_du_configuration_update(&update);
init_NR_RU(config_get_if(), NULL);
start_NR_RU();
wait_RUs();
init_eNB_afterRU();
LOG_I(GNB_APP, "Sending sync to all threads\n");
pthread_mutex_lock(&sync_mutex);
sync_var=0;
pthread_cond_broadcast(&sync_cond);
pthread_mutex_unlock(&sync_mutex);
return 0;
}
static void wait_nfapi_init(char *thread_name)
{
pthread_mutex_lock( &nfapi_sync_mutex );
@@ -629,37 +728,15 @@ int main( int argc, char **argv ) {
printf("TYPE <CTRL-C> TO TERMINATE\n");
itti_wait_tasks_end(NULL);
printf("Returned from ITTI signal handler\n");
oai_exit=1;
// cleanup
if (RC.nb_nr_L1_inst > 0)
stop_gNB(RC.nb_nr_L1_inst);
if (RC.nb_RU > 0)
stop_RU(RC.nb_RU);
/* release memory used by the RU/gNB threads (incomplete), after all
* threads have been stopped (they partially use the same memory) */
for (int inst = 0; inst < RC.nb_RU; inst++) {
nr_phy_free_RU(RC.ru[inst]);
}
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
phy_free_nr_gNB(RC.gNB[inst]);
}
if (RC.nb_nr_L1_inst > 0 || RC.nb_RU > 0)
stop_L1(0);
pthread_cond_destroy(&sync_cond);
pthread_mutex_destroy(&sync_mutex);
pthread_cond_destroy(&nfapi_sync_cond);
pthread_mutex_destroy(&nfapi_sync_mutex);
// *** Handle per CC_id openair0
for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
if (RC.ru[ru_id]->ifdevice.trx_end_func)
RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
}
free(pckg);
logClean();
printf("Bye.\n");
+1 -1
View File
@@ -52,7 +52,7 @@ extern void stop_RU(int nb_ru);
extern void kill_NR_RU_proc(int inst);
extern void set_function_spec_param(RU_t *ru);
void init_gNB_afterRU(void);
void init_eNB_afterRU(void);
void init_pdcp(void);