Multiple DUs in a tree
This commit is contained in:
@@ -366,6 +366,9 @@ typedef struct cucp_cuup_if_s {
|
|||||||
} cucp_cuup_if_t;
|
} cucp_cuup_if_t;
|
||||||
|
|
||||||
typedef struct nr_rrc_du_container_t {
|
typedef struct nr_rrc_du_container_t {
|
||||||
|
/* Tree-related data */
|
||||||
|
RB_ENTRY(nr_rrc_du_container_t) entries;
|
||||||
|
|
||||||
sctp_assoc_t assoc_id;
|
sctp_assoc_t assoc_id;
|
||||||
f1ap_setup_req_t *setup_req;
|
f1ap_setup_req_t *setup_req;
|
||||||
NR_MIB_t *mib;
|
NR_MIB_t *mib;
|
||||||
@@ -408,7 +411,9 @@ typedef struct gNB_RRC_INST_s {
|
|||||||
nr_mac_rrc_dl_if_t mac_rrc;
|
nr_mac_rrc_dl_if_t mac_rrc;
|
||||||
cucp_cuup_if_t cucp_cuup;
|
cucp_cuup_if_t cucp_cuup;
|
||||||
|
|
||||||
nr_rrc_du_container_t *du;
|
RB_HEAD(rrc_du_tree, nr_rrc_du_container_t) dus; // DUs, indexed by assoc_id
|
||||||
|
size_t num_dus;
|
||||||
|
|
||||||
RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id
|
RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id
|
||||||
size_t num_cuups;
|
size_t num_cuups;
|
||||||
|
|
||||||
|
|||||||
@@ -345,6 +345,7 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c
|
|||||||
uid_linear_allocator_init(&rrc->uid_allocator);
|
uid_linear_allocator_init(&rrc->uid_allocator);
|
||||||
RB_INIT(&rrc->rrc_ue_head);
|
RB_INIT(&rrc->rrc_ue_head);
|
||||||
RB_INIT(&rrc->cuups);
|
RB_INIT(&rrc->cuups);
|
||||||
|
RB_INIT(&rrc->dus);
|
||||||
rrc->configuration = *configuration;
|
rrc->configuration = *configuration;
|
||||||
/// System Information INIT
|
/// System Information INIT
|
||||||
init_NR_SI(rrc);
|
init_NR_SI(rrc);
|
||||||
|
|||||||
@@ -28,6 +28,18 @@
|
|||||||
#include "executables/softmodem-common.h"
|
#include "executables/softmodem-common.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_t *b)
|
||||||
|
{
|
||||||
|
if (a->assoc_id > b->assoc_id)
|
||||||
|
return 1;
|
||||||
|
if (a->assoc_id == b->assoc_id)
|
||||||
|
return 0;
|
||||||
|
return -1; /* a->assoc_id < b->assoc_id */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tree management functions */
|
||||||
|
RB_GENERATE/*_STATIC*/(rrc_du_tree, nr_rrc_du_container_t, entries, du_compare);
|
||||||
|
|
||||||
static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *info)
|
static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *info)
|
||||||
{
|
{
|
||||||
const gNB_RrcConfigurationReq *conf = &rrc->configuration;
|
const gNB_RrcConfigurationReq *conf = &rrc->configuration;
|
||||||
@@ -46,17 +58,10 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
|||||||
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);
|
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:
|
// check:
|
||||||
// - it is the first DU
|
|
||||||
// - it is one cell
|
// - it is one cell
|
||||||
// - PLMN and Cell ID matches
|
// - PLMN and Cell ID matches
|
||||||
|
// - no previous DU with the same ID
|
||||||
// else reject
|
// else reject
|
||||||
if (rrc->du != NULL) {
|
|
||||||
const f1ap_setup_req_t *other = rrc->du->setup_req;
|
|
||||||
LOG_E(NR_RRC, "can only handle one DU, but already serving DU %ld (%s)\n", other->gNB_DU_id, other->gNB_DU_name);
|
|
||||||
f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_gNB_CU_Cell_Capacity_Exceeded};
|
|
||||||
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (req->num_cells_available != 1) {
|
if (req->num_cells_available != 1) {
|
||||||
LOG_E(NR_RRC, "can only handle on DU cell, but gNB_DU %ld has %d\n", req->gNB_DU_id, req->num_cells_available);
|
LOG_E(NR_RRC, "can only handle on DU cell, but gNB_DU %ld has %d\n", req->gNB_DU_id, req->num_cells_available);
|
||||||
f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_gNB_CU_Cell_Capacity_Exceeded};
|
f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_gNB_CU_Cell_Capacity_Exceeded};
|
||||||
@@ -77,6 +82,20 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
|||||||
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
|
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
nr_rrc_du_container_t *it = NULL;
|
||||||
|
RB_FOREACH(it, rrc_du_tree, &rrc->dus) {
|
||||||
|
if (it->setup_req->gNB_DU_id == req->gNB_DU_id) {
|
||||||
|
LOG_E(NR_RRC,
|
||||||
|
"gNB-DU ID: existing DU %s on assoc_id %d already has ID %ld, rejecting requesting gNB-DU\n",
|
||||||
|
it->setup_req->gNB_DU_name,
|
||||||
|
it->assoc_id,
|
||||||
|
it->setup_req->gNB_DU_id);
|
||||||
|
f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified};
|
||||||
|
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if there is no system info or no SIB1 and we run in SA mode, we cannot handle it
|
// if there is no system info or no SIB1 and we run in SA mode, we cannot handle it
|
||||||
const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
|
const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
|
||||||
if (sys_info == NULL || sys_info->mib == NULL || (sys_info->sib1 == NULL && get_softmodem_params()->sa)) {
|
if (sys_info == NULL || sys_info->mib == NULL || (sys_info->sib1 == NULL && get_softmodem_params()->sa)) {
|
||||||
@@ -116,20 +135,22 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
|||||||
LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
|
LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
|
||||||
|
|
||||||
// we accept the DU
|
// we accept the DU
|
||||||
rrc->du = calloc(1, sizeof(*rrc->du));
|
nr_rrc_du_container_t *du = calloc(1, sizeof(*du));
|
||||||
AssertFatal(rrc->du != NULL, "out of memory\n");
|
AssertFatal(du != NULL, "out of memory\n");
|
||||||
rrc->du->assoc_id = assoc_id;
|
du->assoc_id = assoc_id;
|
||||||
|
|
||||||
/* ITTI will free the setup request message via free(). So the memory
|
/* ITTI will free the setup request message via free(). So the memory
|
||||||
* "inside" of the message will remain, but the "outside" container no, so
|
* "inside" of the message will remain, but the "outside" container no, so
|
||||||
* allocate memory and copy it in */
|
* allocate memory and copy it in */
|
||||||
rrc->du->setup_req = malloc(sizeof(*rrc->du->setup_req));
|
du->setup_req = malloc(sizeof(*du->setup_req));
|
||||||
AssertFatal(rrc->du->setup_req != NULL, "out of memory\n");
|
AssertFatal(du->setup_req != NULL, "out of memory\n");
|
||||||
*rrc->du->setup_req = *req;
|
*du->setup_req = *req;
|
||||||
rrc->du->mib = mib->message.choice.mib;
|
du->mib = mib->message.choice.mib;
|
||||||
mib->message.choice.mib = NULL;
|
mib->message.choice.mib = NULL;
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_MessageType, mib);
|
ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_MessageType, mib);
|
||||||
rrc->du->sib1 = sib1;
|
du->sib1 = sib1;
|
||||||
|
RB_INSERT(rrc_du_tree, &rrc->dus, du);
|
||||||
|
rrc->num_dus++;
|
||||||
|
|
||||||
served_cells_to_activate_t cell = {
|
served_cells_to_activate_t cell = {
|
||||||
.plmn = cell_info->plmn,
|
.plmn = cell_info->plmn,
|
||||||
@@ -187,21 +208,23 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
|||||||
void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
|
void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
|
||||||
{
|
{
|
||||||
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
|
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
|
||||||
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
|
(void) lc; // unused for the moment
|
||||||
|
|
||||||
nr_rrc_du_container_t *du = rrc->du;
|
nr_rrc_du_container_t e = {.assoc_id = assoc_id};
|
||||||
|
nr_rrc_du_container_t *du = RB_FIND(rrc_du_tree, &rrc->dus, &e);
|
||||||
|
if (du == NULL) {
|
||||||
|
LOG_W(NR_RRC, "no DU connected or not found for assoc_id %d: F1 Setup Failed?\n", assoc_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
f1ap_setup_req_t *req = du->setup_req;
|
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(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_MIB, du->mib);
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
|
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
|
||||||
/* TODO: free setup request */
|
/* TODO: free setup request */
|
||||||
free(rrc->du);
|
nr_rrc_du_container_t *removed = RB_REMOVE(rrc_du_tree, &rrc->dus, du);
|
||||||
rrc->du = NULL;
|
DevAssert(removed != NULL);
|
||||||
|
rrc->num_dus--;
|
||||||
|
|
||||||
int num = invalidate_du_connections(rrc, assoc_id);
|
int num = invalidate_du_connections(rrc, assoc_id);
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
@@ -211,14 +234,12 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t
|
|||||||
|
|
||||||
nr_rrc_du_container_t *get_du_for_ue(gNB_RRC_INST *rrc, uint32_t ue_id)
|
nr_rrc_du_container_t *get_du_for_ue(gNB_RRC_INST *rrc, uint32_t ue_id)
|
||||||
{
|
{
|
||||||
nr_rrc_du_container_t *du = rrc->du;
|
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
|
||||||
if (du == NULL)
|
return get_du_by_assoc_id(rrc, ue_data.du_assoc_id);
|
||||||
return NULL;
|
|
||||||
return du;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||||
{
|
{
|
||||||
AssertFatal(assoc_id == rrc->du->assoc_id, "cannot handle multiple DUs yet\n");
|
nr_rrc_du_container_t e = {.assoc_id = assoc_id};
|
||||||
return rrc->du;
|
return RB_FIND(rrc_du_tree, &rrc->dus, &e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user