From 6d0c7945c2b3891c1bde3801cb5e82a6ab740c4e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 6 Jan 2026 15:30:58 +0100 Subject: [PATCH] RRC multi-cell: extract DU management to cell management library Move DU tree management from rrc_gNB_du.c into rrc_cell_management so that DU and cell lookup logic live in one place, improving maintainability and testability (there is no DU lib). - rrc_cell_management: add du_compare(), RB_GENERATE(rrc_du_tree), get_du_by_assoc_id(), rrc_add_du(), rrc_rm_du(), rrc_cleanup_du(), rrc_free_du_container(); declare them in rrc_cell_management.h. - rrc_gNB_du: move du_compare(), RB_GENERATE, get_du_by_assoc_id() to rrc_cell_management --- openair2/RRC/NR/rrc_cell_management.c | 83 +++++++++++++++++++++++++++ openair2/RRC/NR/rrc_cell_management.h | 9 +++ openair2/RRC/NR/rrc_gNB.c | 1 + openair2/RRC/NR/rrc_gNB_du.c | 19 +----- openair2/RRC/NR/rrc_gNB_du.h | 1 - 5 files changed, 94 insertions(+), 19 deletions(-) diff --git a/openair2/RRC/NR/rrc_cell_management.c b/openair2/RRC/NR/rrc_cell_management.c index ebe8f78961..eac0f38260 100644 --- a/openair2/RRC/NR/rrc_cell_management.c +++ b/openair2/RRC/NR/rrc_cell_management.c @@ -32,6 +32,89 @@ #include "NR_SIB1.h" // for asn_DEF_NR_SIB1 #include "NR_MeasurementTimingConfiguration.h" // for asn_DEF_NR_MeasurementTimingConfiguration +/** @brief Comparison function for DU tree + * @param[in] a Pointer to first DU container + * @param[in] b Pointer to second DU container + * @return Comparison result */ +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 */ +} + +// Generate RB tree functions for DU tree +RB_GENERATE(rrc_du_tree, nr_rrc_du_container_t, entries, du_compare); + +/** @brief Find DU by SCTP association ID (uses DU RB-tree lookup) + * @param[in] rrc Pointer to RRC instance + * @param[in] assoc_id SCTP association ID + * @return Pointer to the DU container, or NULL if not found + * @note O(log N_DU) complexity using DU RB-tree lookup */ +nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, const sctp_assoc_t assoc_id) +{ + DevAssert(rrc != NULL); + nr_rrc_du_container_t e = {.assoc_id = assoc_id}; + return RB_FIND(rrc_du_tree, &rrc->dus, &e); +} + +/** @brief Add DU to RRC DU tree and increment rrc->num_dus on success + * @param[in] rrc Pointer to RRC instance + * @param[in] du Pointer to DU container to add + * @return NULL if inserted successfully; pointer to existing DU (collision) if duplicate assoc_id */ +nr_rrc_du_container_t *rrc_add_du(gNB_RRC_INST *rrc, nr_rrc_du_container_t *du) +{ + DevAssert(rrc != NULL); + DevAssert(du != NULL); + nr_rrc_du_container_t *collision = RB_INSERT(rrc_du_tree, &rrc->dus, du); + if (collision == NULL) + rrc->num_dus++; + return collision; +} + +/** @brief Free a DU container and its allocated fields (gNB_DU_name); free the DU itself + * @param[in] du Pointer to DU container to free + * @note Does NOT remove the DU from the tree or free du->cells; caller must do RB_REMOVE and seq_arr_free first */ +void rrc_free_du_container(nr_rrc_du_container_t *du) +{ + DevAssert(du != NULL); + free(du->gNB_DU_name); + free(du); +} + +/** @brief Remove DU from RRC DU tree, decrement rrc->num_dus, and free the DU and its resources + * @param[in] rrc Pointer to RRC instance + * @param[in] du Pointer to DU container to remove (caller must have removed and freed all cells first) */ +void rrc_rm_du(gNB_RRC_INST *rrc, nr_rrc_du_container_t *du) +{ + DevAssert(rrc != NULL); + DevAssert(du != NULL); + nr_rrc_du_container_t *removed = RB_REMOVE(rrc_du_tree, &rrc->dus, du); + AssertFatal(removed == du, "Failed to remove DU (assoc_id %d) from tree\n", du->assoc_id); + rrc->num_dus--; + seq_arr_free(&du->cells, NULL); + rrc_free_du_container(du); +} + +/** @brief Remove all cells from the DU (and from global cell tree), remove the DU from the tree, and free the DU + * @param[in] rrc Pointer to RRC instance + * @param[in] du Pointer to DU container to cleanup (removed from tree and freed) */ +void rrc_cleanup_du(gNB_RRC_INST *rrc, nr_rrc_du_container_t *du) +{ + DevAssert(rrc != NULL); + DevAssert(du != NULL); + for (size_t i = seq_arr_size(&du->cells); i > 0; i--) { + nr_rrc_cell_container_t **cell_ptr = seq_arr_at(&du->cells, i - 1); + nr_rrc_cell_container_t *cell = *cell_ptr; + LOG_I(NR_RRC, "Removing cell %lu from DU cells array\n", cell->info.cell_id); + seq_arr_erase(&du->cells, cell_ptr); + rrc_rm_cell(rrc, cell); + } + rrc_rm_du(rrc, du); +} + /** @brief Comparison function for cell tree * @param[in] a Pointer to first cell container * @param[in] b Pointer to second cell container diff --git a/openair2/RRC/NR/rrc_cell_management.h b/openair2/RRC/NR/rrc_cell_management.h index d083b3d174..76790fda4f 100644 --- a/openair2/RRC/NR/rrc_cell_management.h +++ b/openair2/RRC/NR/rrc_cell_management.h @@ -30,6 +30,15 @@ // Generate RB tree functions (prototypes) int rrc_cell_cmp(const struct nr_rrc_cell_container_t *a, const struct nr_rrc_cell_container_t *b); RB_PROTOTYPE(rrc_cell_tree, nr_rrc_cell_container_t, entries, rrc_cell_cmp); +int du_compare(const struct nr_rrc_du_container_t *a, const struct nr_rrc_du_container_t *b); +RB_PROTOTYPE(rrc_du_tree, nr_rrc_du_container_t, entries, du_compare); + +// DU management (global DU tree) +nr_rrc_du_container_t *rrc_add_du(gNB_RRC_INST *rrc, nr_rrc_du_container_t *du); +void rrc_rm_du(gNB_RRC_INST *rrc, nr_rrc_du_container_t *du); +void rrc_cleanup_du(gNB_RRC_INST *rrc, nr_rrc_du_container_t *du); +void rrc_free_du_container(nr_rrc_du_container_t *du); +nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, const sctp_assoc_t assoc_id); // Cell management (global cell tree) nr_rrc_cell_container_t *get_cell_by_cell_id(struct rrc_cell_tree *cells, const uint64_t cell_id); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6b914c27e9..fd92bca995 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -84,6 +84,7 @@ #include "rrc_gNB_du.h" #include "rrc_gNB_mobility.h" #include "rrc_gNB_radio_bearers.h" +#include "rrc_cell_management.h" #include "rrc_messages_types.h" #include "rrc_gNB_asn1.h" #include "seq_arr.h" diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 302b45cac0..83e158546d 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -20,6 +20,7 @@ */ #include "rrc_gNB_du.h" +#include "rrc_cell_management.h" #include #include #include @@ -84,18 +85,6 @@ int get_ssb_arfcn(const struct nr_rrc_du_container_t *du) return ssb_arfcn_mtc(du->mtc); } -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) { const gNB_RrcConfigurationReq *conf = &rrc->configuration; @@ -629,12 +618,6 @@ nr_rrc_du_container_t *get_du_for_ue(gNB_RRC_INST *rrc, uint32_t ue_id) return get_du_by_assoc_id(rrc, ue_data.du_assoc_id); } -nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id) -{ - nr_rrc_du_container_t e = {.assoc_id = assoc_id}; - return RB_FIND(rrc_du_tree, &rrc->dus, &e); -} - /* \brief find DU by cell ID. Note: currently the CU is limited to one cell per * DU, hence here, DU == cell. Modify this to look up a specific cell. */ nr_rrc_du_container_t *get_du_by_cell_id(gNB_RRC_INST *rrc, uint64_t cell_id) diff --git a/openair2/RRC/NR/rrc_gNB_du.h b/openair2/RRC/NR/rrc_gNB_du.h index 514416211f..4206096aa2 100644 --- a/openair2/RRC/NR/rrc_gNB_du.h +++ b/openair2/RRC/NR/rrc_gNB_du.h @@ -38,7 +38,6 @@ void rrc_CU_process_f1_lost_connection(struct gNB_RRC_INST_s *rrc, struct f1ap_l void rrc_gNB_process_f1_du_configuration_update(struct f1ap_gnb_du_configuration_update_s *conf_up, sctp_assoc_t assoc_id); struct nr_rrc_du_container_t *get_du_for_ue(struct gNB_RRC_INST_s *rrc, uint32_t ue_id); -struct nr_rrc_du_container_t *get_du_by_assoc_id(struct gNB_RRC_INST_s *rrc, sctp_assoc_t assoc_id); const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyCellId); struct nr_rrc_du_container_t *get_du_by_cell_id(struct gNB_RRC_INST_s *rrc, uint64_t cell_id);