Commit c812cea1 authored by Robert Schmidt's avatar Robert Schmidt

Multiple DUs in a tree

parent e155080e
...@@ -366,6 +366,9 @@ typedef struct cucp_cuup_if_s { ...@@ -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 { ...@@ -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 ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment