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
@@ -143,7 +143,6 @@ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t asso
message_p->ittiMsgHeader.originInstance = assoc_id;
f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); // RRC thread will free it
*req = msg; // copy F1 message to ITTI
free_f1ap_du_configuration_update(&msg);
LOG_D(F1AP, "Sending F1AP_GNB_DU_CONFIGURATION_UPDATE ITTI message \n");
itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p);
return 0;
+3 -6
View File
@@ -262,12 +262,9 @@ int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance,
free_f1ap_du_configuration_update_acknowledge(&in);
return -1;
}
// Allocate and send an ITTI message
MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE);
f1ap_gnb_du_configuration_update_acknowledge_t *msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_p);
// Copy the decoded message to the ITTI message (RRC thread will free it)
*msg = in; // Copy the decoded message to the ITTI message (RRC thread will free it)
itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p);
gnb_du_configuration_update_acknowledge(&in);
free_f1ap_du_configuration_update_acknowledge(&in);
return 0;
}
+3 -2
View File
@@ -34,9 +34,10 @@
#ifndef F1AP_DU_RRC_MESSAGE_TRANSFER_H_
#define F1AP_DU_RRC_MESSAGE_TRANSFER_H_
#include "f1ap_common.h"
#include <openair2/RRC/NR/MESSAGES/asn1_msg.h>
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
struct F1AP_F1AP_PDU;
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, struct F1AP_F1AP_PDU *pdu);
int DU_send_UL_NR_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_ul_rrc_message_t *msg);
+69 -69
View File
@@ -173,7 +173,7 @@ static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1
OCTET_STRING_TO_INT24(in->fiveGS_TAC, *info->tac);
}
// NR CGI (M)
TBCD_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
PLMNID_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
// NR Cell Identity (M)
BIT_STRING_TO_NR_CELL_IDENTITY(&in->nRCGI.nRCellIdentity, info->nr_cellid);
// NR PCI (M)
@@ -310,7 +310,7 @@ static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP
"in->value.present != F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item\n");
const F1AP_Cells_to_be_Activated_List_Item_t *cell = &in->value.choice.Cells_to_be_Activated_List_Item;
// NR CGI (M)
TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
PLMNID_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, out->nr_cellid);
// NR PCI (O)
if (cell->nRPCI != NULL)
@@ -534,20 +534,56 @@ bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out
return true;
}
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *dest, const f1ap_served_cell_info_t *src)
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src)
{
// shallow copy
*dest = *src;
// tac
f1ap_served_cell_info_t dst = {
.plmn = src->plmn,
.nr_cellid = src->nr_cellid,
.nr_pci = src->nr_pci,
.num_ssi = src->num_ssi,
.mode = src->mode,
};
for (int i = 0; i < src->num_ssi; ++i)
dst.nssai[i] = src->nssai[i];
if (src->mode == F1AP_MODE_TDD)
dst.tdd = src->tdd;
else
dst.fdd = src->fdd;
if (src->tac) {
dest->tac = malloc_or_fail(sizeof(*dest->tac));
*dest->tac = *src->tac;
dst.tac = malloc_or_fail(sizeof(*dst.tac));
*dst.tac = *src->tac;
}
// measurement timing config
if (src->measurement_timing_config_len) {
dest->measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dest->measurement_timing_config));
memcpy(dest->measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
if (src->measurement_timing_config_len > 0) {
dst.measurement_timing_config_len = src->measurement_timing_config_len;
dst.measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dst.measurement_timing_config));
memcpy(dst.measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
}
return dst;
}
static f1ap_gnb_du_system_info_t *copy_f1ap_gnb_du_system_info(const f1ap_gnb_du_system_info_t *src)
{
if (!src)
return NULL;
f1ap_gnb_du_system_info_t *dst = calloc_or_fail(1, sizeof(*dst));
if (src->mib_length > 0) {
dst->mib_length = src->mib_length;
dst->mib = calloc_or_fail(src->mib_length, sizeof(*src->mib));
memcpy(dst->mib, src->mib, dst->mib_length);
}
if (src->sib1_length > 0) {
dst->sib1_length = src->sib1_length;
dst->sib1 = calloc_or_fail(src->sib1_length, sizeof(*dst->sib1));
memcpy(dst->sib1, src->sib1, dst->sib1_length);
}
return dst;
}
/**
@@ -567,25 +603,9 @@ f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg)
cp.num_cells_available = msg->num_cells_available;
for (int n = 0; n < msg->num_cells_available; n++) {
/* cell.info */
f1ap_served_cell_info_t *sci = &cp.cell[n].info;
const f1ap_served_cell_info_t *msg_sci = &msg->cell[n].info;
copy_f1ap_served_cell_info(sci, msg_sci);
cp.cell[n].info = copy_f1ap_served_cell_info(&msg->cell[n].info);
/* cell.sys_info */
if (msg->cell[n].sys_info) {
f1ap_gnb_du_system_info_t *orig_sys_info = msg->cell[n].sys_info;
f1ap_gnb_du_system_info_t *copy_sys_info = calloc_or_fail(1, sizeof(*copy_sys_info));
cp.cell[n].sys_info = copy_sys_info;
if (orig_sys_info->mib_length > 0) {
copy_sys_info->mib = calloc_or_fail(orig_sys_info->mib_length, sizeof(*copy_sys_info->mib));
copy_sys_info->mib_length = orig_sys_info->mib_length;
memcpy(copy_sys_info->mib, orig_sys_info->mib, copy_sys_info->mib_length);
}
if (orig_sys_info->sib1_length > 0) {
copy_sys_info->sib1 = calloc_or_fail(orig_sys_info->sib1_length, sizeof(*copy_sys_info->sib1));
copy_sys_info->sib1_length = orig_sys_info->sib1_length;
memcpy(copy_sys_info->sib1, orig_sys_info->sib1, copy_sys_info->sib1_length);
}
}
cp.cell[n].sys_info = copy_f1ap_gnb_du_system_info(msg->cell[n].sys_info);
}
for (int i = 0; i < sizeofArray(msg->rrc_ver); i++)
cp.rrc_ver[i] = msg->rrc_ver[i];
@@ -1002,7 +1022,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
/* mandatory */
/* c2. Served_Cells_To_Add */
if (msg->num_cells_to_add > 0) {
AssertFatal(false, "code for adding cells not tested\n");
asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List;
ie2->criticality = F1AP_Criticality_reject;
@@ -1060,7 +1079,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List;
ie4->criticality = F1AP_Criticality_reject;
ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List;
AssertFatal(msg->num_cells_to_delete == 0, "code for deleting cells not tested\n");
for (int i = 0; i < msg->num_cells_to_delete; i++) {
asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list,
F1AP_Served_Cells_To_Delete_ItemIEs_t,
@@ -1114,8 +1132,8 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
} break;
case F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List: {
/* Served Cells To Add List */
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
out->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count;
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
for (int i = 0; i < out->num_cells_to_add; i++) {
F1AP_Served_Cells_To_Add_Item_t *served_cells_item =
&((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i])
@@ -1142,7 +1160,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
/* Old NR CGI (M) */
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn;
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
/* Old NR CGI Cell ID */
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid);
/* Served Cell Information (M) */
@@ -1166,7 +1184,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn;
/* Old NR CGI (M) */
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
// NR cellID
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_delete[i].nr_cellid);
}
@@ -1216,10 +1234,8 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
for (int i = 0; i < a->num_cells_to_add; i++) {
if (!eq_f1ap_cell_info(&a->cell_to_add[i].info, &b->cell_to_add[i].info))
return false;
if (a->cell_to_add[i].sys_info && b->cell_to_add[i].sys_info) {
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
return false;
}
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
return false;
}
/* to delete */
_F1_EQ_CHECK_INT(a->num_cells_to_delete, b->num_cells_to_delete);
@@ -1231,12 +1247,13 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
/* to modify */
_F1_EQ_CHECK_INT(a->num_cells_to_modify, b->num_cells_to_modify);
for (int i = 0; i < a->num_cells_to_modify; i++) {
if (!eq_f1ap_plmn(&a->cell_to_modify[i].old_plmn, &b->cell_to_modify[i].old_plmn))
return false;
_F1_EQ_CHECK_LONG(a->cell_to_modify[i].old_nr_cellid, b->cell_to_modify[i].old_nr_cellid);
if (!eq_f1ap_cell_info(&a->cell_to_modify[i].info, &b->cell_to_modify[i].info))
return false;
if (a->cell_to_modify[i].sys_info && b->cell_to_modify[i].sys_info) {
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
return false;
}
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
return false;
}
return true;
}
@@ -1256,6 +1273,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
cp.transaction_id = msg->transaction_id;
/* to add */
cp.num_cells_to_add = msg->num_cells_to_add;
for (int i = 0; i < cp.num_cells_to_add; ++i) {
cp.cell_to_add[i].info = copy_f1ap_served_cell_info(&msg->cell_to_add[i].info);
cp.cell_to_add[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_add[i].sys_info);
}
/* to delete */
cp.num_cells_to_delete = msg->num_cells_to_delete;
for (int i = 0; i < cp.num_cells_to_delete; i++) {
@@ -1265,31 +1286,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
/* to modify */
cp.num_cells_to_modify = msg->num_cells_to_modify;
for (int i = 0; i < cp.num_cells_to_modify; i++) {
cp.cell_to_modify[i].info = msg->cell_to_modify[i].info;
f1ap_served_cell_info_t *info = &cp.cell_to_modify[i].info;
if (info->measurement_timing_config_len > 0) {
info->measurement_timing_config = malloc_or_fail(info->measurement_timing_config_len * sizeof(*info->measurement_timing_config));
for (int j = 0; j < info->measurement_timing_config_len; j++)
info->measurement_timing_config[j] = msg->cell_to_modify[i].info.measurement_timing_config[j];
}
/* TAC */
info->tac = calloc_or_fail(1, sizeof(*info->tac));
*info->tac = *msg->cell_to_modify[i].info.tac;
/* System information */
cp.cell_to_modify[i].sys_info = malloc_or_fail(sizeof(*cp.cell_to_modify[i].sys_info));
f1ap_gnb_du_system_info_t *sys_info = cp.cell_to_modify[i].sys_info;
if (msg->cell_to_modify[i].sys_info->mib_length > 0) {
sys_info->mib_length = msg->cell_to_modify[i].sys_info->mib_length;
sys_info->mib = calloc_or_fail(msg->cell_to_modify[i].sys_info->mib_length, sizeof(*sys_info->mib));
for (int j = 0; j < sys_info->mib_length; j++)
sys_info->mib[j] = msg->cell_to_modify[i].sys_info->mib[j];
}
if (msg->cell_to_modify[i].sys_info->sib1_length > 0) {
sys_info->sib1_length = msg->cell_to_modify[i].sys_info->sib1_length;
sys_info->sib1 = calloc_or_fail(msg->cell_to_modify[i].sys_info->sib1_length, sizeof(*sys_info->sib1));
for (int j = 0; j < sys_info->sib1_length; j++)
sys_info->sib1[j] = msg->cell_to_modify[i].sys_info->sib1[j];
}
cp.cell_to_modify[i].old_plmn = msg->cell_to_modify[i].old_plmn;
cp.cell_to_modify[i].old_nr_cellid = msg->cell_to_modify[i].old_nr_cellid;
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);
}
return cp;
}
@@ -1521,7 +1521,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu,
const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item;
// NR CGI (M)
f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn;
TBCD_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid);
// Cause (M)
switch (item->cause.present) {
@@ -32,7 +32,7 @@ bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t
f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg);
bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b);
void free_f1ap_setup_request(const f1ap_setup_req_t *msg);
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b);
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src);
void free_f1ap_cell(const f1ap_served_cell_info_t *info, const f1ap_gnb_du_system_info_t *sys_info);
/* F1 Setup Response */
+11 -1
View File
@@ -53,7 +53,10 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
{
_F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid);
_F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci);
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
if ((!a->tac) ^ (!b->tac))
return false;
if (a->tac)
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
_F1_EQ_CHECK_INT(a->mode, b->mode);
if (a->mode == F1AP_MODE_TDD) {
/* TDD */
@@ -81,6 +84,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b)
{
if (!a && !b)
return true;
/* will fail if not both a/b NULL or set */
if ((!a) ^ (!b))
return false;
/* MIB */
_F1_EQ_CHECK_INT(a->mib_length, b->mib_length);
for (int i = 0; i < a->mib_length; i++)
+27 -1
View File
@@ -420,12 +420,38 @@ static void test_f1ap_du_configuration_update(void)
.plmn.mnc_digit_length = 3,
.tac = tac,
};
char *mtc2_data = "mtc2";
uint8_t *mtc2 = (void*)strdup(mtc2_data);
int mtc2_len = strlen(mtc2_data);
f1ap_served_cell_info_t info2 = {
.mode = F1AP_MODE_FDD,
.fdd.ul_freqinfo.arfcn = 640000,
.fdd.ul_freqinfo.band = 78,
.fdd.dl_freqinfo.arfcn = 600000,
.fdd.dl_freqinfo.band = 78,
.fdd.ul_tbw.nrb = 66,
.fdd.ul_tbw.scs = 1,
.fdd.dl_tbw.nrb = 66,
.fdd.dl_tbw.scs = 1,
.measurement_timing_config_len = mtc2_len,
.measurement_timing_config = mtc2,
.nr_cellid = 123456,
.plmn.mcc = 2,
.plmn.mnc = 2,
.plmn.mnc_digit_length = 2,
};
/* create message */
f1ap_gnb_du_configuration_update_t orig = {
.transaction_id = 2,
.num_cells_to_add = 1,
.cell_to_add[0].info = info2,
.num_cells_to_modify = 1,
.cell_to_modify[0].info = info,
.num_cells_to_delete = 0,
.cell_to_modify[0].old_nr_cellid = 1235UL,
.cell_to_modify[0].old_plmn.mcc = 208,
.cell_to_modify[0].old_plmn.mnc = 88,
.cell_to_modify[0].old_plmn.mnc_digit_length = 2,
.num_cells_to_delete = 1,
.cell_to_delete[0].nr_cellid = 1234UL,
.cell_to_delete[0].plmn.mcc = 1,
.cell_to_delete[0].plmn.mnc = 1,
-4
View File
@@ -238,10 +238,6 @@ void *gNB_app_task(void *args_p)
break;
case F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
LOG_E(GNB_APP, "[gNB %ld] Handling of %s message not implemented yet\n", instance, msg_name);
break;
case NGAP_DEREGISTERED_GNB_IND:
LOG_W(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name,
NGAP_DEREGISTERED_GNB_IND(msg_p).nb_amf);
+23 -20
View File
@@ -1166,7 +1166,7 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
return 1;
}
static f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
{
const NR_FrequencyInfoDL_t *dl = scc->downlinkConfigCommon->frequencyInfoDL;
f1ap_tdd_info_t tdd = {
@@ -1195,7 +1195,27 @@ static f1ap_fdd_info_t read_fdd_config(const NR_ServingCellConfigCommon_t *scc)
return fdd;
}
static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1)
{
int buf_len = 3;
f1ap_gnb_du_system_info_t *sys_info = calloc_or_fail(1, sizeof(*sys_info));
sys_info->mib = calloc_or_fail(buf_len, sizeof(*sys_info->mib));
DevAssert(mib != NULL);
sys_info->mib_length = encode_MIB_NR(mib, 0, sys_info->mib, buf_len);
DevAssert(sys_info->mib_length == buf_len);
DevAssert(sib1 != NULL);
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
sys_info->sib1 = calloc_or_fail(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
return sys_info;
}
f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
const char *name,
const f1ap_served_cell_info_t *info,
const NR_ServingCellConfigCommon_t *scc,
@@ -1244,24 +1264,7 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
if (IS_SA_MODE(get_softmodem_params())) {
// in NSA we don't transmit SIB1, so cannot fill DU system information
// so cannot send MIB either
int buf_len = 3; // this is what we assume in monolithic
req->cell[0].sys_info = calloc(1, sizeof(*req->cell[0].sys_info));
AssertFatal(req->cell[0].sys_info != NULL, "out of memory\n");
f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib));
DevAssert(sys_info->mib != NULL);
DevAssert(mib != NULL);
// encode only the mib message itself
sys_info->mib_length = encode_MIB_NR_setup(mib->message.choice.mib, 0, sys_info->mib, buf_len);
DevAssert(sys_info->mib_length == buf_len);
DevAssert(sib1 != NULL);
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
sys_info->sib1 = calloc(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
req->cell[0].sys_info = get_sys_info(mib, sib1);
}
int num = read_version(TO_STRING(NR_RRC_VERSION), &req->rrc_ver[0], &req->rrc_ver[1], &req->rrc_ver[2]);
+8
View File
@@ -95,6 +95,14 @@ gNB_RRC_INST *RCconfig_NRRRC();
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i);
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
void wait_f1_setup_response(void);
f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
const char *name,
const f1ap_served_cell_info_t *info,
const NR_ServingCellConfigCommon_t *scc,
NR_BCCH_BCH_Message_t *mib,
const NR_BCCH_DL_SCH_Message_t *sib1);
f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc);
f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1);
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update);
MessageDef *RCconfig_NR_CU_E1(const E1_t *entity);
ngran_node_t get_node_type(void);
@@ -1941,7 +1941,8 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
NR_UE_info_t *UE = find_nr_UE(&nr_mac->UE_info, ra->rnti);
if (!UE) {
LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table\n", ra_type_str, ra->rnti);
LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table. Abort RA\n", ra_type_str, ra->rnti);
nr_clear_ra_proc(ra);
return;
}
@@ -938,6 +938,9 @@ void nr_schedule_ue_spec(module_id_t module_id,
NR_UEs_t *UE_info = &gNB_mac->UE_info;
nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body;
const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE);
UE_iterator(UE_info->list, UE) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
@@ -1252,6 +1255,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti),
T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock, TBS));
UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize;
gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize;
} else { /* initial transmission */
LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot);
uint8_t *buf = (uint8_t *) harq->transportBlock;
@@ -1369,6 +1373,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
UE->mac_stats.dl.num_mac_sdu += sdus;
UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize;
UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes;
gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize;
/* save retransmission information */
harq->sched_pdsch = *sched_pdsch;
@@ -3319,7 +3319,7 @@ bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti)
.gNB_CU_ue_id = ue_data.secondary_ue,
.gNB_DU_ue_id = rnti,
.cause = F1AP_CAUSE_RADIO_NETWORK,
.cause_value = F1AP_CauseRadioNetwork_rl_failure_others,
.cause_value = F1AP_CauseRadioNetwork_rl_failure_rlc,
};
nrmac->mac_rrc.ue_context_release_request(&request);
return true;
@@ -99,7 +99,8 @@ static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
}
static void du_clear_all_ue_states()
/* not static, so we can call it from the outside (in telnet) */
void du_clear_all_ue_states()
{
gNB_MAC_INST *mac = RC.nrmac[0];
NR_SCHED_LOCK(&mac->sched_lock);
+1 -3
View File
@@ -82,10 +82,8 @@ static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_upd
f1ap_gnb_du_configuration_update_t cp = cp_f1ap_du_configuration_update(upd);
/* transfer to ITTI message */
F1AP_GNB_DU_CONFIGURATION_UPDATE(msg) = cp;
/* free after copy */
free_f1ap_du_configuration_update(upd);
/* send to RRC task */
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
itti_send_msg_to_task(TASK_DU_F1, 0, msg);
}
static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp)
+7
View File
@@ -807,6 +807,11 @@ typedef struct {
int8_t nvipc_poll_core;
} nvipc_params_t;
typedef struct {
uint64_t total_prb_aggregate;
uint64_t used_prb_aggregate;
} mac_stats_t;
/*! \brief top level eNB MAC structure */
typedef struct gNB_MAC_INST_s {
/// Ethernet parameters for northbound midhaul interface
@@ -930,6 +935,8 @@ typedef struct gNB_MAC_INST_s {
pthread_mutex_t sched_lock;
mac_stats_t mac_stats;
} gNB_MAC_INST;
#endif /*__LAYER2_NR_MAC_GNB_H__ */
+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)