From 6f49e4244eadee54cde1b3bbfe6eec5756ca22be Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Mon, 23 Sep 2024 22:34:51 +0200 Subject: [PATCH 01/32] sched: remove num_slots_per_frame from sched metrics --- lib/scheduler/config/sched_config_manager.cpp | 3 +-- lib/scheduler/logging/scheduler_metric_handler.cpp | 9 ++------- lib/scheduler/logging/scheduler_metrics_handler.h | 7 +------ .../logging/scheduler_metrics_ue_configurator.h | 6 +----- lib/scheduler/ue_scheduling/ue_event_manager.cpp | 5 ++++- .../scheduler/scheduler_metrics_handler_test.cpp | 3 +-- .../unittests/scheduler/test_utils/config_generators.cpp | 8 +------- .../scheduler/test_utils/dummy_test_components.h | 8 +------- 8 files changed, 12 insertions(+), 37 deletions(-) diff --git a/lib/scheduler/config/sched_config_manager.cpp b/lib/scheduler/config/sched_config_manager.cpp index 98396444d1..f19bfcefcc 100644 --- a/lib/scheduler/config/sched_config_manager.cpp +++ b/lib/scheduler/config/sched_config_manager.cpp @@ -199,8 +199,7 @@ void sched_config_manager::handle_ue_config_complete(du_ue_index_t ue_index, std cell_metrics.handle_ue_creation(ue_index, next_cfg->crnti, next_cfg->pcell_common_cfg().pci, - next_cfg->pcell_common_cfg().nof_dl_prbs, - next_cfg->pcell_common_cfg().nof_slots_per_frame); + next_cfg->pcell_common_cfg().nof_dl_prbs); } else { // Reconfiguration case. cell_metrics.handle_ue_reconfiguration(ue_index); diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index fea92c7e4e..1f1b14b381 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -21,18 +21,13 @@ cell_metrics_handler::cell_metrics_handler(msecs metrics_report_period, schedule next_report.events.reserve(MAX_NOF_DU_UES); } -void cell_metrics_handler::handle_ue_creation(du_ue_index_t ue_index, - rnti_t rnti, - pci_t pcell_pci, - unsigned num_prbs, - unsigned num_slots_per_frame) +void cell_metrics_handler::handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) { ues.emplace(ue_index); ues[ue_index].rnti = rnti; ues[ue_index].ue_index = ue_index; ues[ue_index].pci = pcell_pci; ues[ue_index].nof_prbs = num_prbs; - ues[ue_index].num_slots_per_frame = num_slots_per_frame; rnti_to_ue_index_lookup.emplace(rnti, ue_index); nof_prbs = num_prbs; @@ -296,7 +291,7 @@ void cell_metrics_handler::handle_slot_result(const sched_result& slot_res void cell_metrics_handler::handle_ul_delay(du_ue_index_t ue_index, double delay) { if (ues.contains(ue_index)) { - ues[ue_index].data.sum_ul_delay_ms += delay * (10 / (ues[ue_index].num_slots_per_frame)); + ues[ue_index].data.sum_ul_delay_ms += delay; } } diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index 3f71363af0..85e7f6bc4f 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -62,7 +62,6 @@ class cell_metrics_handler final : public harq_timeout_handler, public sched_met pci_t pci; unsigned nof_prbs; - unsigned num_slots_per_frame; du_ue_index_t ue_index; rnti_t rnti; unsigned last_bsr = 0; @@ -109,11 +108,7 @@ class cell_metrics_handler final : public harq_timeout_handler, public sched_met explicit cell_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); /// \brief Register creation of a UE. - void handle_ue_creation(du_ue_index_t ue_index, - rnti_t rnti, - pci_t pcell_pci, - unsigned num_prbs, - unsigned num_slots_per_frame) override; + void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override; /// \brief Register UE reconfiguration. void handle_ue_reconfiguration(du_ue_index_t ue_index) override; diff --git a/lib/scheduler/logging/scheduler_metrics_ue_configurator.h b/lib/scheduler/logging/scheduler_metrics_ue_configurator.h index b5049e0237..8436e83ef7 100644 --- a/lib/scheduler/logging/scheduler_metrics_ue_configurator.h +++ b/lib/scheduler/logging/scheduler_metrics_ue_configurator.h @@ -23,11 +23,7 @@ class sched_metrics_ue_configurator virtual ~sched_metrics_ue_configurator() = default; /// Adds a new UE to the reported metrics. - virtual void handle_ue_creation(du_ue_index_t ue_index, - rnti_t rnti, - pci_t pcell_pci, - unsigned num_prbs, - unsigned num_slots_per_frame) = 0; + virtual void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) = 0; /// Handle a reconfiguration of an existing UE. virtual void handle_ue_reconfiguration(du_ue_index_t ue_index) = 0; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 0f880a55a1..915851990c 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -359,6 +359,9 @@ void ue_event_manager::handle_crc_indication(const ul_crc_indication& crc_ind) if (not cell_specific_events[crc_ind.cell_index].try_push(cell_event_t{ crc_ind.crcs[i].ue_index, [this, sl_rx = crc_ind.sl_rx, crc = crc_ind.crcs[i]](ue_cell& ue_cc) { + double delay_ms = + static_cast(last_sl - sl_rx) * (10 / du_cells[ue_cc.cell_index].cfg->nof_slots_per_frame); + const int tbs = ue_cc.handle_crc_pdu(sl_rx, crc); if (tbs < 0) { return; @@ -376,7 +379,7 @@ void ue_event_manager::handle_crc_indication(const ul_crc_indication& crc_ind) // Notify metrics handler. du_cells[ue_cc.cell_index].metrics->handle_crc_indication(crc, units::bytes{(unsigned)tbs}); - du_cells[ue_cc.cell_index].metrics->handle_ul_delay(crc.ue_index, last_sl - sl_rx); + du_cells[ue_cc.cell_index].metrics->handle_ul_delay(crc.ue_index, delay_ms); }, "CRC", true})) { diff --git a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp index 3b87476321..667642e31e 100644 --- a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp +++ b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp @@ -29,7 +29,7 @@ class scheduler_metrics_handler_tester : public ::testing::Test std::chrono::milliseconds period = std::chrono::milliseconds{test_rgen::uniform_int(2, 100)}) : report_period(period), metrics(period, metrics_notif) { - metrics.handle_ue_creation(test_ue_index, to_rnti(0x4601), pci_t{0}, nof_prbs, num_slots_per_frame); + metrics.handle_ue_creation(test_ue_index, to_rnti(0x4601), pci_t{0}, nof_prbs); } void run_slot(const sched_result& sched_res, std::chrono::microseconds latency = std::chrono::microseconds{0}) @@ -58,7 +58,6 @@ class scheduler_metrics_handler_tester : public ::testing::Test slot_point next_sl_tx{0, test_rgen::uniform_int(0, 10239)}; unsigned slot_count = 0; unsigned nof_prbs = 100; - unsigned num_slots_per_frame = 10; }; TEST_F(scheduler_metrics_handler_tester, metrics_sent_with_defined_periodicity) diff --git a/tests/unittests/scheduler/test_utils/config_generators.cpp b/tests/unittests/scheduler/test_utils/config_generators.cpp index 16246ed4bb..8ee3b0e071 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.cpp +++ b/tests/unittests/scheduler/test_utils/config_generators.cpp @@ -32,13 +32,7 @@ class dummy_scheduler_ue_metrics_notifier : public scheduler_metrics_notifier class dummy_sched_metrics_ue_configurator : public sched_metrics_ue_configurator { public: - void handle_ue_creation(du_ue_index_t ue_index, - rnti_t rnti, - pci_t pcell_pci, - unsigned num_prbs, - unsigned num_slots_per_frame) override - { - } + void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override {} void handle_ue_reconfiguration(du_ue_index_t ue_index) override {} void handle_ue_deletion(du_ue_index_t ue_index) override {} }; diff --git a/tests/unittests/scheduler/test_utils/dummy_test_components.h b/tests/unittests/scheduler/test_utils/dummy_test_components.h index 2b08be93b1..4e47601e65 100644 --- a/tests/unittests/scheduler/test_utils/dummy_test_components.h +++ b/tests/unittests/scheduler/test_utils/dummy_test_components.h @@ -185,13 +185,7 @@ class scheduler_harq_timeout_dummy_notifier : public harq_timeout_notifier class scheduler_ue_metrics_dummy_configurator : public sched_metrics_ue_configurator { public: - void handle_ue_creation(du_ue_index_t ue_index, - rnti_t rnti, - pci_t pcell_pci, - unsigned num_prbs, - unsigned num_slots_per_frame) override - { - } + void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override {} void handle_ue_reconfiguration(du_ue_index_t ue_index) override {} void handle_ue_deletion(du_ue_index_t ue_index) override {} }; From a344fdc02f5841fc2f11d3eb7196981b29abc58c Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Tue, 24 Sep 2024 13:13:35 +0200 Subject: [PATCH 02/32] sched,metrics: use cell_cfg instead of passing num_prbs during ue creation --- lib/scheduler/config/sched_config_manager.cpp | 5 +--- .../logging/scheduler_metric_handler.cpp | 28 +++++++++---------- .../logging/scheduler_metrics_handler.h | 13 ++++----- .../scheduler_metrics_ue_configurator.h | 2 +- .../scheduler_metrics_handler_test.cpp | 13 ++++++--- .../test_utils/config_generators.cpp | 2 +- .../test_utils/dummy_test_components.h | 2 +- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/lib/scheduler/config/sched_config_manager.cpp b/lib/scheduler/config/sched_config_manager.cpp index f19bfcefcc..731462cbc4 100644 --- a/lib/scheduler/config/sched_config_manager.cpp +++ b/lib/scheduler/config/sched_config_manager.cpp @@ -196,10 +196,7 @@ void sched_config_manager::handle_ue_config_complete(du_ue_index_t ue_index, std cell_metrics_handler& cell_metrics = metrics_handler.at(next_cfg->pcell_common_cfg().cell_index); if (ue_cfg_list[ue_index] == nullptr) { // UE creation case. - cell_metrics.handle_ue_creation(ue_index, - next_cfg->crnti, - next_cfg->pcell_common_cfg().pci, - next_cfg->pcell_common_cfg().nof_dl_prbs); + cell_metrics.handle_ue_creation(ue_index, next_cfg->crnti, next_cfg->pcell_common_cfg().pci); } else { // Reconfiguration case. cell_metrics.handle_ue_reconfiguration(ue_index); diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 1f1b14b381..cc64e22e7e 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -14,22 +14,22 @@ using namespace srsran; -cell_metrics_handler::cell_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier_) : - notifier(notifier_), report_period(metrics_report_period) +cell_metrics_handler::cell_metrics_handler(msecs metrics_report_period, + scheduler_metrics_notifier& notifier_, + const cell_configuration& cell_cfg_) : + notifier(notifier_), report_period(metrics_report_period), cell_cfg(cell_cfg_) { next_report.ue_metrics.reserve(MAX_NOF_DU_UES); next_report.events.reserve(MAX_NOF_DU_UES); } -void cell_metrics_handler::handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) +void cell_metrics_handler::handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci) { ues.emplace(ue_index); - ues[ue_index].rnti = rnti; - ues[ue_index].ue_index = ue_index; - ues[ue_index].pci = pcell_pci; - ues[ue_index].nof_prbs = num_prbs; + ues[ue_index].rnti = rnti; + ues[ue_index].ue_index = ue_index; + ues[ue_index].pci = pcell_pci; rnti_to_ue_index_lookup.emplace(rnti, ue_index); - nof_prbs = num_prbs; next_report.events.push_back(scheduler_cell_event{last_slot_tx, rnti, scheduler_cell_event::event_type::ue_add}); } @@ -209,7 +209,7 @@ void cell_metrics_handler::report_metrics() next_report.nof_error_indications = error_indication_counter; next_report.average_decision_latency = decision_latency_sum / report_period_slots; next_report.latency_histogram = decision_latency_hist; - next_report.nof_prbs = nof_prbs; + next_report.nof_prbs = cell_cfg.nof_dl_prbs; // TODO: to be removed from the report. next_report.nof_dl_slots = nof_dl_slots; next_report.nof_ul_slots = nof_ul_slots; @@ -248,8 +248,8 @@ void cell_metrics_handler::handle_slot_result(const sched_result& slot_res } if (dl_grant.pdsch_cfg.rbs.is_type0()) { u.data.tot_dl_prbs_used += full_dl_slot ? convert_rbgs_to_prbs(dl_grant.pdsch_cfg.rbs.type0(), - {0, u.nof_prbs}, - get_nominal_rbg_size(u.nof_prbs, true)) + {0, cell_cfg.nof_dl_prbs}, + get_nominal_rbg_size(cell_cfg.nof_dl_prbs, true)) .count() : 0; } else if (dl_grant.pdsch_cfg.rbs.is_type1()) { @@ -266,8 +266,8 @@ void cell_metrics_handler::handle_slot_result(const sched_result& slot_res if (ul_grant.pusch_cfg.rbs.is_type0()) { ues[it->second].data.tot_ul_prbs_used += full_ul_slot ? convert_rbgs_to_prbs(ul_grant.pusch_cfg.rbs.type0(), - {0, ues[it->second].nof_prbs}, - get_nominal_rbg_size(ues[it->second].nof_prbs, true)) + {0, cell_cfg.nof_dl_prbs}, + get_nominal_rbg_size(cell_cfg.nof_dl_prbs, true)) .count() : 0; } else if (ul_grant.pusch_cfg.rbs.is_type1()) { @@ -376,7 +376,7 @@ cell_metrics_handler* scheduler_metrics_handler::add_cell(const cell_configurati return nullptr; } - cells.emplace(cell_cfg.cell_index, report_period, notifier); + cells.emplace(cell_cfg.cell_index, report_period, notifier, cell_cfg); return &cells[cell_cfg.cell_index]; } diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index 85e7f6bc4f..4b1b0eec68 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -61,7 +61,6 @@ class cell_metrics_handler final : public harq_timeout_handler, public sched_met ue_metric_context() {} pci_t pci; - unsigned nof_prbs; du_ue_index_t ue_index; rnti_t rnti; unsigned last_bsr = 0; @@ -76,7 +75,8 @@ class cell_metrics_handler final : public harq_timeout_handler, public sched_met scheduler_metrics_notifier& notifier; const std::chrono::milliseconds report_period; - // Derived value. + const cell_configuration& cell_cfg; + /// Derived value. unsigned report_period_slots = 0; slot_point last_slot_tx; @@ -88,9 +88,6 @@ class cell_metrics_handler final : public harq_timeout_handler, public sched_met slotted_id_table ues; std::unordered_map rnti_to_ue_index_lookup; - /// Number of the cell PRBs. - unsigned nof_prbs = 0; - /// Number of full downlink slots. unsigned nof_dl_slots = 0; @@ -105,10 +102,12 @@ class cell_metrics_handler final : public harq_timeout_handler, public sched_met public: /// \brief Creates a scheduler UE metrics handler for a given cell. In case the metrics_report_period is zero, /// no metrics are reported. - explicit cell_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); + explicit cell_metrics_handler(msecs metrics_report_period, + scheduler_metrics_notifier& notifier, + const cell_configuration& cell_cfg_); /// \brief Register creation of a UE. - void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override; + void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci) override; /// \brief Register UE reconfiguration. void handle_ue_reconfiguration(du_ue_index_t ue_index) override; diff --git a/lib/scheduler/logging/scheduler_metrics_ue_configurator.h b/lib/scheduler/logging/scheduler_metrics_ue_configurator.h index 8436e83ef7..cf057161f3 100644 --- a/lib/scheduler/logging/scheduler_metrics_ue_configurator.h +++ b/lib/scheduler/logging/scheduler_metrics_ue_configurator.h @@ -23,7 +23,7 @@ class sched_metrics_ue_configurator virtual ~sched_metrics_ue_configurator() = default; /// Adds a new UE to the reported metrics. - virtual void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) = 0; + virtual void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci) = 0; /// Handle a reconfiguration of an existing UE. virtual void handle_ue_reconfiguration(du_ue_index_t ue_index) = 0; diff --git a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp index 667642e31e..47ecd1f182 100644 --- a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp +++ b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp @@ -8,7 +8,9 @@ * */ +#include "lib/scheduler/config/cell_configuration.h" #include "lib/scheduler/logging/scheduler_metrics_handler.h" +#include "tests/unittests/scheduler/test_utils/config_generators.h" #include "srsran/support/test_utils.h" #include @@ -27,9 +29,12 @@ class scheduler_metrics_handler_tester : public ::testing::Test protected: scheduler_metrics_handler_tester( std::chrono::milliseconds period = std::chrono::milliseconds{test_rgen::uniform_int(2, 100)}) : - report_period(period), metrics(period, metrics_notif) + report_period(period), + cell_cfg(config_helpers::make_default_scheduler_expert_config(), + test_helpers::make_default_sched_cell_configuration_request()), + metrics(period, metrics_notif, cell_cfg) { - metrics.handle_ue_creation(test_ue_index, to_rnti(0x4601), pci_t{0}, nof_prbs); + metrics.handle_ue_creation(test_ue_index, to_rnti(0x4601), pci_t{0}); } void run_slot(const sched_result& sched_res, std::chrono::microseconds latency = std::chrono::microseconds{0}) @@ -52,12 +57,12 @@ class scheduler_metrics_handler_tester : public ::testing::Test std::chrono::milliseconds report_period; test_scheduler_ue_metrics_notifier metrics_notif; + cell_configuration cell_cfg; cell_metrics_handler metrics; du_ue_index_t test_ue_index = to_du_ue_index(test_rgen::uniform_int(0, MAX_NOF_DU_UES - 1)); slot_point next_sl_tx{0, test_rgen::uniform_int(0, 10239)}; - unsigned slot_count = 0; - unsigned nof_prbs = 100; + unsigned slot_count = 0; }; TEST_F(scheduler_metrics_handler_tester, metrics_sent_with_defined_periodicity) diff --git a/tests/unittests/scheduler/test_utils/config_generators.cpp b/tests/unittests/scheduler/test_utils/config_generators.cpp index 8ee3b0e071..3707fb7495 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.cpp +++ b/tests/unittests/scheduler/test_utils/config_generators.cpp @@ -32,7 +32,7 @@ class dummy_scheduler_ue_metrics_notifier : public scheduler_metrics_notifier class dummy_sched_metrics_ue_configurator : public sched_metrics_ue_configurator { public: - void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override {} + void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci) override {} void handle_ue_reconfiguration(du_ue_index_t ue_index) override {} void handle_ue_deletion(du_ue_index_t ue_index) override {} }; diff --git a/tests/unittests/scheduler/test_utils/dummy_test_components.h b/tests/unittests/scheduler/test_utils/dummy_test_components.h index 4e47601e65..10dc5dafda 100644 --- a/tests/unittests/scheduler/test_utils/dummy_test_components.h +++ b/tests/unittests/scheduler/test_utils/dummy_test_components.h @@ -185,7 +185,7 @@ class scheduler_harq_timeout_dummy_notifier : public harq_timeout_notifier class scheduler_ue_metrics_dummy_configurator : public sched_metrics_ue_configurator { public: - void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override {} + void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci) override {} void handle_ue_reconfiguration(du_ue_index_t ue_index) override {} void handle_ue_deletion(du_ue_index_t ue_index) override {} }; From f75b1a5587b27793bb1387e918325369da97e6c6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 27 Sep 2024 19:24:41 +0200 Subject: [PATCH 03/32] sched: use lockfree MPMC queue for pending CRCs in ra_scheduler --- .../common_scheduling/ra_scheduler.cpp | 18 +++++++++++++----- lib/scheduler/common_scheduling/ra_scheduler.h | 11 +++++++---- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/scheduler/common_scheduling/ra_scheduler.cpp b/lib/scheduler/common_scheduling/ra_scheduler.cpp index 93b5a6f355..42411c6ba0 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.cpp +++ b/lib/scheduler/common_scheduling/ra_scheduler.cpp @@ -85,6 +85,12 @@ class ra_scheduler::msg3_harq_timeout_notifier final : public harq_timeout_notif std::vector& pending_msg3s; }; +// (Implementation-defined) limit for maximum number of concurrent Msg3s. +static constexpr size_t MAX_NOF_MSG3 = 1024; + +// (Implementation-defined) limit for maximum number of pending CRC indications. +static constexpr size_t CRC_IND_QUEUE_SIZE = MAX_PUCCH_PDUS_PER_SLOT; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_, @@ -105,6 +111,7 @@ ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_, cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->rach_cfg_generic.prach_config_index) .format)), msg3_harqs(MAX_NOF_MSG3, 1, std::make_unique(pending_msg3s)), + pending_crcs(CRC_IND_QUEUE_SIZE), pending_msg3s(MAX_NOF_MSG3) { // Precompute RAR PDSCH and DCI PDUs. @@ -277,16 +284,17 @@ void ra_scheduler::handle_rach_indication_impl(const rach_indication_message& ms void ra_scheduler::handle_crc_indication(const ul_crc_indication& crc_ind) { - pending_crcs.push(crc_ind); + if (not pending_crcs.try_push(crc_ind)) { + logger.warning( + "cell={}: CRC indication for slot={} discarded. Cause: Event queue is full", crc_ind.cell_index, crc_ind.sl_rx); + } } void ra_scheduler::handle_pending_crc_indications_impl(cell_resource_allocator& res_alloc) { // Pop pending CRCs and process them. - pending_crcs.slot_indication(); - const span new_crc_inds = pending_crcs.get_events(); - - for (const ul_crc_indication& crc_ind : new_crc_inds) { + ul_crc_indication crc_ind; + while (pending_crcs.try_pop(crc_ind)) { for (const ul_crc_pdu_indication& crc : crc_ind.crcs) { srsran_assert(crc.ue_index == INVALID_DU_UE_INDEX, "Msg3 HARQ CRCs cannot have a ue index assigned yet"); auto& pending_msg3 = pending_msg3s[to_value(crc.rnti) % MAX_NOF_MSG3]; diff --git a/lib/scheduler/common_scheduling/ra_scheduler.h b/lib/scheduler/common_scheduling/ra_scheduler.h index a74d896d6b..205ee80027 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.h +++ b/lib/scheduler/common_scheduling/ra_scheduler.h @@ -15,6 +15,8 @@ #include "../pdcch_scheduling/pdcch_resource_allocator.h" #include "../support/prbs_calculator.h" #include "../support/slot_event_list.h" +#include "srsran/adt/concurrent_queue.h" +#include "srsran/adt/mpmc_queue.h" #include "srsran/ran/prach/prach_configuration.h" #include "srsran/scheduler/config/scheduler_expert_config.h" #include "srsran/srslog/srslog.h" @@ -41,9 +43,6 @@ uint16_t get_ra_rnti(unsigned slot_index, unsigned symbol_index, unsigned freque /// Scheduler for PRACH occasions, RAR PDSCHs and Msg3 PUSCH grants. class ra_scheduler { - /// Implementation-defined limit for maximum number of concurrent Msg3s. - static constexpr size_t MAX_NOF_MSG3 = 1024; - public: explicit ra_scheduler(const scheduler_ra_expert_config& sched_cfg_, const cell_configuration& cfg_, @@ -85,6 +84,10 @@ class ra_scheduler crb_interval crbs; }; + using crc_indication_queue = concurrent_queue; + const bwp_configuration& get_dl_bwp_cfg() const { return cell_cfg.dl_cfg_common.init_dl_bwp.generic_params; } const pdsch_config_common& get_pdsch_cfg() const { return cell_cfg.dl_cfg_common.init_dl_bwp.pdsch_common; } const bwp_configuration& get_ul_bwp_cfg() const { return cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; } @@ -175,7 +178,7 @@ class ra_scheduler // variables cell_harq_manager msg3_harqs; slot_event_list pending_rachs; - slot_event_list pending_crcs; + crc_indication_queue pending_crcs; std::deque pending_rars; std::vector pending_msg3s; }; From 837a89f1386ebbb43ddac8e23914dea557d8b716 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 27 Sep 2024 19:32:16 +0200 Subject: [PATCH 04/32] sched: use lockfree MPMC queue for pending RACH indications in ra_scheduler --- lib/scheduler/common_scheduling/ra_scheduler.cpp | 16 +++++++++++----- lib/scheduler/common_scheduling/ra_scheduler.h | 16 +++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/scheduler/common_scheduling/ra_scheduler.cpp b/lib/scheduler/common_scheduling/ra_scheduler.cpp index 42411c6ba0..547aebd971 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.cpp +++ b/lib/scheduler/common_scheduling/ra_scheduler.cpp @@ -88,8 +88,11 @@ class ra_scheduler::msg3_harq_timeout_notifier final : public harq_timeout_notif // (Implementation-defined) limit for maximum number of concurrent Msg3s. static constexpr size_t MAX_NOF_MSG3 = 1024; +// (Implementation-defined) limit for maximum number of pending RACH indications. +static constexpr size_t RACH_IND_QUEUE_SIZE = MAX_PRACH_OCCASIONS_PER_SLOT * 2; + // (Implementation-defined) limit for maximum number of pending CRC indications. -static constexpr size_t CRC_IND_QUEUE_SIZE = MAX_PUCCH_PDUS_PER_SLOT; +static constexpr size_t CRC_IND_QUEUE_SIZE = MAX_PUCCH_PDUS_PER_SLOT * 2; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -111,6 +114,7 @@ ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_, cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->rach_cfg_generic.prach_config_index) .format)), msg3_harqs(MAX_NOF_MSG3, 1, std::make_unique(pending_msg3s)), + pending_rachs(RACH_IND_QUEUE_SIZE), pending_crcs(CRC_IND_QUEUE_SIZE), pending_msg3s(MAX_NOF_MSG3) { @@ -208,7 +212,10 @@ void ra_scheduler::precompute_msg3_pdus() void ra_scheduler::handle_rach_indication(const rach_indication_message& msg) { // Buffer detected RACHs to be handled in next slot. - pending_rachs.push(msg); + if (not pending_rachs.try_push(msg)) { + logger.warning( + "cell={}: Discarding RACH indication for slot={}. Cause: Event queue is full", msg.cell_index, msg.slot_rx); + } } void ra_scheduler::handle_rach_indication_impl(const rach_indication_message& msg) @@ -345,9 +352,8 @@ void ra_scheduler::run_slot(cell_resource_allocator& res_alloc) handle_pending_crc_indications_impl(res_alloc); // Pop pending RACHs and process them. - pending_rachs.slot_indication(); - const span new_rachs = pending_rachs.get_events(); - for (const rach_indication_message& rach : new_rachs) { + rach_indication_message rach; + while (pending_rachs.try_pop(rach)) { handle_rach_indication_impl(rach); } diff --git a/lib/scheduler/common_scheduling/ra_scheduler.h b/lib/scheduler/common_scheduling/ra_scheduler.h index 205ee80027..2d5163cca4 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.h +++ b/lib/scheduler/common_scheduling/ra_scheduler.h @@ -14,7 +14,6 @@ #include "../cell/resource_grid.h" #include "../pdcch_scheduling/pdcch_resource_allocator.h" #include "../support/prbs_calculator.h" -#include "../support/slot_event_list.h" #include "srsran/adt/concurrent_queue.h" #include "srsran/adt/mpmc_queue.h" #include "srsran/ran/prach/prach_configuration.h" @@ -84,7 +83,10 @@ class ra_scheduler crb_interval crbs; }; - using crc_indication_queue = concurrent_queue; + using crc_indication_queue = concurrent_queue; @@ -176,11 +178,11 @@ class ra_scheduler sch_mcs_description msg3_mcs_config; // variables - cell_harq_manager msg3_harqs; - slot_event_list pending_rachs; - crc_indication_queue pending_crcs; - std::deque pending_rars; - std::vector pending_msg3s; + cell_harq_manager msg3_harqs; + rach_indication_queue pending_rachs; + crc_indication_queue pending_crcs; + std::deque pending_rars; + std::vector pending_msg3s; }; } // namespace srsran From 65adf0b75ba6b8d5c5211627bbda78bae105410a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 27 Sep 2024 19:34:25 +0200 Subject: [PATCH 05/32] sched: remove slot_event_list dependency from fallback scheduler --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.h | 1 - lib/scheduler/ue_scheduling/ue_scheduler_impl.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 7758fba092..7bf5c2852b 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -12,7 +12,6 @@ #include "../policy/ue_allocator.h" #include "../support/sch_pdu_builder.h" -#include "../support/slot_event_list.h" #include "ue_repository.h" #include "srsran/scheduler/scheduler_configurator.h" #include diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h index 6db4a009f0..e59f88cd07 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h @@ -22,6 +22,7 @@ #include "ue_repository.h" #include "ue_scheduler.h" #include "srsran/scheduler/config/scheduler_expert_config.h" +#include namespace srsran { From 570537803d6d84ca916378f57bedd41d13a44134 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 27 Sep 2024 20:11:29 +0200 Subject: [PATCH 06/32] sched: remove slot_event_list from paging scheduler --- .../scheduler/scheduler_paging_handler.h | 2 +- lib/scheduler/cell_scheduler.cpp | 2 +- .../common_scheduling/paging_scheduler.cpp | 20 ++++-- .../common_scheduling/paging_scheduler.h | 11 ++- lib/scheduler/support/slot_event_list.h | 70 ------------------- lib/scheduler/support/slot_sync_point.h | 68 ------------------ .../paging_scheduler_test.cpp | 2 +- 7 files changed, 24 insertions(+), 151 deletions(-) delete mode 100644 lib/scheduler/support/slot_event_list.h delete mode 100644 lib/scheduler/support/slot_sync_point.h diff --git a/include/srsran/scheduler/scheduler_paging_handler.h b/include/srsran/scheduler/scheduler_paging_handler.h index 172c9caeaa..fca383638c 100644 --- a/include/srsran/scheduler/scheduler_paging_handler.h +++ b/include/srsran/scheduler/scheduler_paging_handler.h @@ -22,7 +22,7 @@ struct sched_paging_information { /// (Bit string of size 48). See TS 38.331. uint64_t paging_identity; /// Cells at which to perform Paging of UE. - std::vector paging_cells; + static_vector paging_cells; /// UE_ID: 5G-S-TMSI mod 1024. Used by the paging scheduler to calculate the Paging Frame. /// \remark See TS 38.304, clause 7.1. unsigned ue_identity_index_value; diff --git a/lib/scheduler/cell_scheduler.cpp b/lib/scheduler/cell_scheduler.cpp index 4e132b58ec..e0fabd8ad7 100644 --- a/lib/scheduler/cell_scheduler.cpp +++ b/lib/scheduler/cell_scheduler.cpp @@ -113,7 +113,7 @@ void cell_scheduler::run_slot(slot_point sl_tx) ra_sch.run_slot(res_grid); // > Schedule Paging. - pg_sch.schedule_paging(res_grid); + pg_sch.run_slot(res_grid); // > Schedule UE DL and UL data. ue_sched.run_slot(sl_tx); diff --git a/lib/scheduler/common_scheduling/paging_scheduler.cpp b/lib/scheduler/common_scheduling/paging_scheduler.cpp index d93ac42c3e..77eec20904 100644 --- a/lib/scheduler/common_scheduling/paging_scheduler.cpp +++ b/lib/scheduler/common_scheduling/paging_scheduler.cpp @@ -21,6 +21,9 @@ using namespace srsran; +// (Implementation-defined) limit for maximum number of pending paging indications. +static constexpr size_t PAGING_INFO_QUEUE_SIZE = 128; + paging_scheduler::paging_scheduler(const scheduler_expert_config& expert_cfg_, const cell_configuration& cell_cfg_, pdcch_resource_allocator& pdcch_sch_, @@ -32,6 +35,7 @@ paging_scheduler::paging_scheduler(const scheduler_expert_config& nof_pf_per_drx_cycle(static_cast(cell_cfg.dl_cfg_common.pcch_cfg.nof_pf)), paging_frame_offset(cell_cfg.dl_cfg_common.pcch_cfg.paging_frame_offset), nof_po_per_pf(static_cast(cell_cfg.dl_cfg_common.pcch_cfg.ns)), + new_paging_notifications(PAGING_INFO_QUEUE_SIZE), logger(srslog::fetch_basic_logger("SCHED")) { if (cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common.paging_search_space_id.has_value()) { @@ -102,16 +106,15 @@ paging_scheduler::paging_scheduler(const scheduler_expert_config& } } -void paging_scheduler::schedule_paging(cell_resource_allocator& res_grid) +void paging_scheduler::run_slot(cell_resource_allocator& res_grid) { // Pop pending Paging notification and process them. - new_paging_notifications.slot_indication(); - span new_paging_infos = new_paging_notifications.get_events(); - for (const auto& pg_info : new_paging_infos) { + sched_paging_information new_pg_info; + while (new_paging_notifications.try_pop(new_pg_info)) { // Check whether Paging information is already present or not. i.e. tackle repeated Paging attempt from upper // layers. - if (paging_pending_ues.find(pg_info.paging_identity) == paging_pending_ues.cend()) { - paging_pending_ues[pg_info.paging_identity] = ue_paging_info{.info = pg_info, .retry_count = 0}; + if (paging_pending_ues.find(new_pg_info.paging_identity) == paging_pending_ues.cend()) { + paging_pending_ues[new_pg_info.paging_identity] = ue_paging_info{.info = new_pg_info, .retry_count = 0}; } } @@ -255,7 +258,10 @@ unsigned paging_scheduler::get_accumulated_paging_msg_size(span @@ -40,7 +41,7 @@ class paging_scheduler /// \brief Performs paging (if any) scheduling for the current slot. /// /// \param[out,in] res_grid Resource grid with current allocations and scheduling results. - void schedule_paging(cell_resource_allocator& res_grid); + void run_slot(cell_resource_allocator& res_grid); /// Handles Paging information reported by upper layers. /// \param[in] paging_info Per UE paging information to be scheduled. @@ -52,6 +53,10 @@ class paging_scheduler paging_retries_count_type retry_count; }; + using paging_info_queue = concurrent_queue; + /// \brief Checks paging conditions for a UE in SearchSpace > 0 i.e pagingSearchSpace > 0 in its active BWP config. /// /// \param[in] pdcch_slot Slot at which the paging scheduler is called. @@ -151,7 +156,7 @@ class paging_scheduler /// List of notifications from upper layers containing Paging information. /// This is used only to avoid data race between threads. - slot_event_list new_paging_notifications; + paging_info_queue new_paging_notifications; /// Contains paging information of UEs yet to be scheduled. std::unordered_map paging_pending_ues; /// Lookup to keep track of scheduled paging UEs at a particular PDSCH time resource index. Index of \c diff --git a/lib/scheduler/support/slot_event_list.h b/lib/scheduler/support/slot_event_list.h deleted file mode 100644 index c71cdeb15d..0000000000 --- a/lib/scheduler/support/slot_event_list.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/span.h" -#include -#include - -namespace srsran { - -/// This class stores incoming events in a thread-safe queue, and pops all enqueued events in a single batch, when -/// a new slot indication is notified. -/// The advantage of this class over a mutexed queue is the lower contention caused when popping elements from the -/// queue. This is particularly relevant because the events need to be processed during the scheduler slot handling. -/// \tparam Event type of event pushed/popped from the list. -template -class slot_event_list -{ -public: - void reserve(unsigned cap) - { - std::lock_guard lock(mutex); - pending_events.reserve(cap); - current_events.reserve(cap); - } - - void slot_indication() - { - current_events.clear(); - std::lock_guard lock(mutex); - pending_events.swap(current_events); - } - - template - void push(Ev&& ev) - { - static_assert(std::is_convertible::value, "Invalid type"); - std::lock_guard lock(mutex); - pending_events.push_back(std::forward(ev)); - } - - template - void emplace(Args&&... args) - { - std::lock_guard lock(mutex); - pending_events.template emplace_back(std::forward(args)...); - } - - span get_events() { return current_events; } - -private: - /// Stores all enqueued events that are going to be processed in the next slot_indication. - std::vector pending_events; - - /// Contains the events being processed in the current slot. - /// Note: the transfer of next_events to current_events is done via a std::swap, which for std::vector is very fast. - std::vector current_events; - - std::mutex mutex; -}; - -} // namespace srsran diff --git a/lib/scheduler/support/slot_sync_point.h b/lib/scheduler/support/slot_sync_point.h deleted file mode 100644 index 8281c8b8ef..0000000000 --- a/lib/scheduler/support/slot_sync_point.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/ran/slot_point.h" -#include -#include - -namespace srsran { - -/// This object creates a barrier for multiple threads when wait() is called. Once the count reaches zero, -/// a callback is invoked. -class slot_sync_point -{ -public: - slot_sync_point() = default; - slot_sync_point(const slot_sync_point&) = delete; - slot_sync_point(slot_sync_point&&) = delete; - slot_sync_point& operator=(const slot_sync_point&) = delete; - slot_sync_point& operator=(slot_sync_point&&) = delete; - - /// \brief Called when thread enters synchronization point. Steps: - /// 1. If the current thread is the first to call wait(), the count is set to the number of workers. - /// 2. The count is decremented. - /// - If count > 0, the current thread blocks waiting for count to reach zero. - /// - If count==0, the current thread invokes completion callback, and notifies remaining threads to unlock. - /// \param sl current slot. - /// \param nof_workers number of workers currently passing through synchronization point. - /// \param func Completion callback invoked when count reaches zero. - template - void wait(slot_point sl, size_t nof_workers, const CompletionFunction& func) - { - std::unique_lock lock(mutex); - srsran_sanity_check(nof_workers > 0, "Invalid count"); - if (sl != last_sl) { - // Initialize barrier. - count = nof_workers; - last_sl = sl; - } - - if (--count == 0) { - // Phase completion step. - func(); - lock.unlock(); - cvar.notify_all(); - } else { - while (count > 0) { - cvar.wait(lock); - } - } - } - -private: - slot_point last_sl; - size_t count; - std::mutex mutex; - std::condition_variable cvar; -}; - -} // namespace srsran diff --git a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp index 0a5e942e59..aec7ff57ba 100644 --- a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp @@ -116,7 +116,7 @@ class base_paging_sched_tester bench->res_grid.slot_indication(current_slot); bench->pdcch_sch.slot_indication(current_slot); - bench->pg_sch.schedule_paging(bench->res_grid); + bench->pg_sch.run_slot(bench->res_grid); // Log scheduling results. sched_res_logger.on_scheduler_result(bench->res_grid[0].result); From 7243e516220fbd333185b2141e3a2bc14aef6f6f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 19 Sep 2024 17:21:30 +0200 Subject: [PATCH 07/32] du_high: review use of transform precoder du: fix DCI Format in transform precoding du: review MAC transform precoding related --- lib/scheduler/CMakeLists.txt | 1 + lib/scheduler/srs/srs_scheduler.h | 42 +++ lib/scheduler/srs/srs_scheduler_impl.cpp | 340 ++++++++++++++++++ lib/scheduler/srs/srs_scheduler_impl.h | 73 ++++ .../ue_scheduling/ue_event_manager.cpp | 12 + .../ue_scheduling/ue_event_manager.h | 3 + .../ue_scheduling/ue_scheduler_impl.cpp | 7 +- .../ue_scheduling/ue_scheduler_impl.h | 4 + 8 files changed, 481 insertions(+), 1 deletion(-) create mode 100644 lib/scheduler/srs/srs_scheduler.h create mode 100644 lib/scheduler/srs/srs_scheduler_impl.cpp create mode 100644 lib/scheduler/srs/srs_scheduler_impl.h diff --git a/lib/scheduler/CMakeLists.txt b/lib/scheduler/CMakeLists.txt index 000ab62d07..8256079d06 100644 --- a/lib/scheduler/CMakeLists.txt +++ b/lib/scheduler/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES pucch_scheduling/pucch_resource_manager.cpp uci_scheduling/uci_scheduler_impl.cpp uci_scheduling/uci_allocator_impl.cpp + srs/srs_scheduler_impl.cpp support/pdcch/pdcch_type0_helpers.cpp support/pdsch/pdsch_default_time_allocation.cpp support/pdsch/pdsch_dmrs_symbol_mask.cpp diff --git a/lib/scheduler/srs/srs_scheduler.h b/lib/scheduler/srs/srs_scheduler.h new file mode 100644 index 0000000000..081fa90a64 --- /dev/null +++ b/lib/scheduler/srs/srs_scheduler.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +namespace srsran { + +struct cell_resource_allocator; +class ue_cell_configuration; + +/// SRS scheduling interface, which handles the scheduling of SRS opportunities. +class srs_scheduler +{ +public: + virtual ~srs_scheduler() = default; + + /// Schedules the SRS occasions. + /// \param[out,in] res_alloc struct with scheduling results. + virtual void run_slot(cell_resource_allocator& res_alloc) = 0; + + /// Adds a UE to the internal list of UEs to be scheduled. + /// \param[in] ue_cfg dedicated configuration of the UE to be added. + virtual void add_ue(const ue_cell_configuration& ue_cfg) = 0; + + /// Removes the UE from the internal list of UEs to be scheduled. + /// \param[in] ue_cfg UE dedicated configuration of the UE to be removed. + virtual void rem_ue(const ue_cell_configuration& ue_cfg) = 0; + + /// Updates the SRS configuration of this UE, if there are any changes w.r.t. the previous configuration. + /// \param[in] ue_cfg New UE dedicated configuration of the UE to be reconfigured. + /// \param[in] ue_cfg Old UE dedicated configuration of the UE to be reconfigured. + virtual void reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) = 0; +}; + +} // namespace srsran diff --git a/lib/scheduler/srs/srs_scheduler_impl.cpp b/lib/scheduler/srs/srs_scheduler_impl.cpp new file mode 100644 index 0000000000..aea552398e --- /dev/null +++ b/lib/scheduler/srs/srs_scheduler_impl.cpp @@ -0,0 +1,340 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srs_scheduler_impl.h" +#include "../cell/resource_grid.h" +#include "srsran/srslog/srslog.h" + +using namespace srsran; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +srs_scheduler_impl::srs_scheduler_impl(const cell_configuration& cell_cfg_, ue_repository& ues_) : + cell_cfg(cell_cfg_), ues(ues_), logger(srslog::fetch_basic_logger("SCHED")) +{ + // Max size of the SRS resource slot wheel, dimensioned based on the SRS periods. + periodic_srs_slot_wheel.resize(std::max(MAX_SR_PERIOD, MAX_CSI_REPORT_PERIOD)); + + // Pre-reserve space for the UEs that will be added. + updated_ues.reserve(MAX_NOF_DU_UES); +} + +srs_scheduler_impl::~srs_scheduler_impl() = default; + +///////////////////// Public functions //////////////////////////// + +void srs_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) +{ + // Initial allocation: we allocate opportunities all over the grid. + schedule_updated_ues_srs(cell_alloc); + + // Only allocate in the farthest slot in the grid, as the previous part of the allocation grid has been completed + // at the first this function was called. + schedule_slot_srs(cell_alloc[cell_alloc.max_ul_slot_alloc_delay]); +} + +void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) +{ + if (not ue_cfg.cfg_dedicated().ul_config.has_value() or + not ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.has_value()) { + return; + } + const srs_config& srs_cfg = ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); + + // In this list we assume that an SRS resource set configured as period only contains periodic SRS resources. + auto get_srs_res_with_id = [&srs_cfg](unsigned srs_res_id) { + return std::find_if( + srs_cfg.srs_res_list.begin(), + srs_cfg.srs_res_list.end(), + [srs_res_id](const srs_config::srs_resource& srs_res) { return srs_res.id.ue_res_id == srs_res_id; }); + }; + + for (const auto& srs_res_set : + ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value().srs_res_set_list) { + if (not std::holds_alternative(srs_res_set.res_type)) { + continue; + } + + for (const auto& srs_res_id : srs_res_set.srs_res_id_list) { + const auto* srs_res = get_srs_res_with_id(srs_res_id); + + if (srs_res == srs_cfg.srs_res_list.end()) { + logger.error("rnti={} SRS resource set id={} has an invalid SRS resource ID {}", + ue_cfg.crnti, + srs_res_set.id, + srs_res_id); + continue; + } + add_resource(ue_cfg.crnti, + srs_res->periodicity_and_offset.value().period, + srs_res->periodicity_and_offset.value().offset, + srs_res->id.ue_res_id); + } + } +} + +void srs_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) +{ + if (not ue_cfg.cfg_dedicated().ul_config.has_value() or + not ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.has_value()) { + return; + } + const srs_config& srs_cfg = ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); + + // In this list we assume that an SRS resource set configured as periodic only contains periodic SRS resources. + auto get_srs_res_with_id = [&srs_cfg](unsigned srs_res_id) { + return std::find_if( + srs_cfg.srs_res_list.begin(), + srs_cfg.srs_res_list.end(), + [srs_res_id](const srs_config::srs_resource& srs_res) { return srs_res.id.ue_res_id == srs_res_id; }); + }; + + for (const auto& srs_res_set : + ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value().srs_res_set_list) { + if (not std::holds_alternative(srs_res_set.res_type)) { + continue; + } + // We assume the + + for (const auto& srs_res_id : srs_res_set.srs_res_id_list) { + const auto* srs_res = get_srs_res_with_id(srs_res_id); + + if (srs_res == srs_cfg.srs_res_list.end()) { + logger.error("rnti={} SRS resource set id={} has an invalid SRS resource ID {}", + ue_cfg.crnti, + srs_res_set.id, + srs_res_id); + continue; + } + rem_resource(ue_cfg.crnti, + srs_res->periodicity_and_offset.value().period, + srs_res->periodicity_and_offset.value().offset, + srs_res->id.ue_res_id); + } + } +} + +void srs_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) +{ + if (new_ue_cfg.cfg_dedicated().ul_config.has_value() and old_ue_cfg.cfg_dedicated().ul_config.has_value() and + new_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.has_value() and + old_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.has_value()) { + // Both old and new UE config have SRS config. + const auto& new_srs_cfg = new_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); + const auto& old_srs_cfg = old_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); + + if (new_srs_cfg.srs_res_set_list == old_srs_cfg.srs_res_set_list and + new_srs_cfg.srs_res_list == old_srs_cfg.srs_res_list) { + // Nothing changed. + return; + } + } + + rem_ue(old_ue_cfg); + add_ue(new_ue_cfg); +} + +///////////////////// Private functions //////////////////////////// + +void srs_scheduler_impl::schedule_slot_srs(srsran::cell_slot_resource_allocator& slot_alloc) +{ + // For the provided slot, check if there are any pending SRS resources to allocate, and allocate them. + auto& slot_srss = periodic_srs_slot_wheel[slot_alloc.slot.to_uint() % periodic_srs_slot_wheel.size()]; + for (auto srs_info_it : slot_srss) { + allocate_srs_opportunity(slot_alloc, srs_info_it); + } +} + +void srs_scheduler_impl::schedule_updated_ues_srs(cell_resource_allocator& cell_alloc) +{ + if (not updated_ues.empty()) { + // Schedule SRS up to the farthest slot. + for (unsigned n = 0; n != cell_alloc.max_ul_slot_alloc_delay; ++n) { + auto& slot_srss = periodic_srs_slot_wheel[(cell_alloc.slot_tx() + n).to_uint() % periodic_srs_slot_wheel.size()]; + // For all the periodic SRS info element at this slot, allocate only those that belong to the UE updated_ues. + for (const periodic_srs_info& srs : slot_srss) { + const bool rnti_in_updated_ues = + std::find(updated_ues.begin(), updated_ues.end(), srs.rnti) != updated_ues.end(); + if (rnti_in_updated_ues) { + allocate_srs_opportunity(cell_alloc[n], srs); + } + } + } + + // Clear the list of updated UEs. + updated_ues.clear(); + } +} + +bool srs_scheduler_impl::allocate_srs_opportunity(cell_slot_resource_allocator& slot_alloc, + const periodic_srs_info& srs_opportunity) +{ + slot_point sl_srs = slot_alloc.slot; + + const ue_cell_configuration* ue_cfg = get_ue_cfg(srs_opportunity.rnti); + if (ue_cfg == nullptr) { + logger.error("cell={} c-rnti={}: UE for which SRS is being scheduled was not found", + cell_cfg.cell_index, + srs_opportunity.rnti); + return false; + } + + if (not ue_cfg->cell_cfg_common.is_ul_enabled(sl_srs)) { + logger.warning("cell={} c-rnti={}: slot={} for SRS resource id={} is being scheduled is not UL enabled", + cell_cfg.cell_index, + srs_opportunity.rnti, + sl_srs, + srs_opportunity.srs_res_id); + return false; + } + + if (slot_alloc.result.ul.srss.full()) { + logger.warning("cell={} c-rnti={}: SRS resource id={} cannot be allocated for slot={}. Cause: SRS list is full", + cell_cfg.cell_index, + srs_opportunity.rnti, + srs_opportunity.srs_res_id, + sl_srs); + return false; + } + + const auto srs_res_list = ue_cfg->cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value().srs_res_list; + + // Retrieve the SRS resource ID from the UE dedicated config. + const auto* res_it = std::find_if( + srs_res_list.begin(), srs_res_list.end(), [srs_opportunity](const srs_config::srs_resource& srs_res) { + return srs_res.id.ue_res_id == srs_opportunity.srs_res_id; + }); + + if (res_it == srs_res_list.end()) { + logger.warning("cell={} c-rnti={}: SRS resource id={} cannot be allocated for slot={}. Cause: SRS resource not " + "found in UE ded. config", + cell_cfg.cell_index, + srs_opportunity.rnti, + srs_opportunity.srs_res_id, + sl_srs); + return false; + } + + const unsigned nof_symbs_per_slot = get_nsymb_per_slot(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.cp); + const unsigned starting_symb = nof_symbs_per_slot - res_it->res_mapping.start_pos - 1; + slot_alloc.ul_res_grid.fill( + grant_info(cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.scs, + ofdm_symbol_range{starting_symb, starting_symb + static_cast(res_it->res_mapping.nof_symb)}, + cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs)); + fill_srs_pdu(slot_alloc.result.ul.srss.emplace_back(), *res_it, *ue_cfg); + + return true; +} + +void srs_scheduler_impl::fill_srs_pdu(srs_info& pdu, + const srs_config::srs_resource& srs_res_cfg, + const ue_cell_configuration& ue_cfg) +{ + pdu.crnti = ue_cfg.crnti; + pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pdu.nof_antenna_ports = cell_cfg.ul_carrier.nof_ant; + + const unsigned nof_symbs_per_slot = get_nsymb_per_slot(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.cp); + const unsigned starting_symb = nof_symbs_per_slot - srs_res_cfg.res_mapping.start_pos - 1; + pdu.symbols.set(starting_symb, starting_symb + static_cast(srs_res_cfg.res_mapping.nof_symb)); + pdu.nof_repetitions = srs_res_cfg.res_mapping.rept_factor; + + pdu.config_index = srs_res_cfg.freq_hop.c_srs; + pdu.sequence_id = static_cast(srs_res_cfg.sequence_id); + pdu.bw_index = srs_res_cfg.freq_hop.b_srs; + pdu.tx_comb = srs_res_cfg.tx_comb.size; + pdu.comb_offset = srs_res_cfg.tx_comb.tx_comb_offset; + pdu.cyclic_shift = srs_res_cfg.tx_comb.tx_comb_cyclic_shift; + pdu.freq_position = srs_res_cfg.freq_domain_pos; + pdu.freq_shift = srs_res_cfg.freq_domain_shift; + pdu.freq_hopping = srs_res_cfg.freq_hop.b_hop; + pdu.group_or_seq_hopping = srs_res_cfg.grp_or_seq_hop; + pdu.resource_type = srs_res_cfg.res_type; + + pdu.t_srs_period = srs_res_cfg.periodicity_and_offset.value().period; + pdu.t_offset = srs_res_cfg.periodicity_and_offset.value().offset; +} + +void srs_scheduler_impl::add_resource(rnti_t crnti, + srs_periodicity res_period, + unsigned res_offset, + srs_config::srs_res_id res_id) +{ + // Add UE-SRS resource element for each offset in the periodic SRS slot wheel. + auto srs_period = static_cast(res_period); + for (unsigned wheel_offset = res_offset, wheel_size = periodic_srs_slot_wheel.size(); wheel_offset < wheel_size; + wheel_offset += srs_period) { + auto& slot_wheel = periodic_srs_slot_wheel[wheel_offset]; + + // Check if the UE is already in the slot wheel. + auto* it = std::find_if(slot_wheel.begin(), slot_wheel.end(), [crnti, res_id](const auto& r) { + return r.rnti == crnti and r.srs_res_id == res_id; + }); + + if (it == slot_wheel.end()) { + // New UE-SRS resource: create a new element in the list of SRS opportunities. + slot_wheel.push_back(periodic_srs_info{crnti, res_id}); + } else { + logger.error("rnti={}: SRS resource id={} with period={} and offset={} already exists in the SRS slot wheel", + crnti, + res_id, + res_period); + } + } +} + +void srs_scheduler_impl::rem_resource(rnti_t crnti, + srs_periodicity res_period, + unsigned res_offset, + srs_config::srs_res_id res_id) +{ + // For each offset in the periodic SRS slot wheel. + auto srs_period = static_cast(res_period); + for (unsigned wheel_offset = res_offset, wheel_size = periodic_srs_slot_wheel.size(); wheel_offset < wheel_size; + wheel_offset += srs_period) { + auto& slot_wheel = periodic_srs_slot_wheel[wheel_offset]; + + // Check if the UE-SRS resource element is still in the slot wheel. + auto* it = std::find_if(slot_wheel.begin(), slot_wheel.end(), [crnti, res_id](const auto& r) { + return r.rnti == crnti and r.srs_res_id == res_id; + }); + + if (it != slot_wheel.end()) { + // Move resource to last position and delete it to avoid O(N) removal. + if (it != slot_wheel.end() - 1) { + auto* last_it = slot_wheel.end() - 1; + std::swap(*it, *last_it); + } + slot_wheel.pop_back(); + + } else { + logger.error( + "rnti={}: no SRS resource id={} with period={} and offset={} found in the SRS slot wheel during UE removal", + crnti, + res_id, + res_period, + res_offset); + } + } +} + +///////////////////// Helper functions //////////////////////////// + +const ue_cell_configuration* srs_scheduler_impl::get_ue_cfg(rnti_t rnti) const +{ + auto* u = ues.find_by_rnti(rnti); + if (u != nullptr) { + auto* ue_cc = u->find_cell(cell_cfg.cell_index); + if (ue_cc != nullptr) { + return &ue_cc->cfg(); + } + } + return nullptr; +} diff --git a/lib/scheduler/srs/srs_scheduler_impl.h b/lib/scheduler/srs/srs_scheduler_impl.h new file mode 100644 index 0000000000..cf724809d2 --- /dev/null +++ b/lib/scheduler/srs/srs_scheduler_impl.h @@ -0,0 +1,73 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "../ue_scheduling/ue_repository.h" +#include "srs_scheduler.h" +#include "srsran/ran/srs/srs_configuration.h" + +namespace srsran { + +struct cell_resource_allocator; +struct cell_slot_resource_allocator; + +class srs_scheduler_impl : public srs_scheduler +{ +public: + explicit srs_scheduler_impl(const cell_configuration& cell_cfg_, ue_repository& ues_); + + ~srs_scheduler_impl() override; + + void run_slot(cell_resource_allocator& res_alloc) override; + + void add_ue(const ue_cell_configuration& ue_cfg) override; + + void rem_ue(const ue_cell_configuration& ue_cfg) override; + + void reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) override; + +private: + /// Information on currently configured SRS resources and corresponding UEs to be scheduled periodically. + struct periodic_srs_info { + rnti_t rnti = rnti_t::INVALID_RNTI; + srs_config::srs_res_id srs_res_id = srs_config::srs_res_id::MAX_NOF_SRS_RES; + }; + + // Helper to fetch a UE cell config. + const ue_cell_configuration* get_ue_cfg(rnti_t rnti) const; + // Helper that schedules the SRS for a given slot. + void schedule_slot_srs(cell_slot_resource_allocator& slot_alloc); + // Helper that schedules the SRS for UEs that were recently added or reconfigured. + void schedule_updated_ues_srs(cell_resource_allocator& res_alloc); + // Helper that allocates an SRS opportunity for a given UE. + bool allocate_srs_opportunity(cell_slot_resource_allocator& slot_alloc, const periodic_srs_info& srs_opportunity); + // Helper that fills the SRS PDU fields. + void fill_srs_pdu(srs_info& pdu, const srs_config::srs_resource& srs_res_cfg, const ue_cell_configuration& ue_cfg); + + void add_resource(rnti_t crnti, srs_periodicity period, unsigned offset, srs_config::srs_res_id res_id); + void rem_resource(rnti_t crnti, srs_periodicity period, unsigned offset, srs_config::srs_res_id res_id); + + // Cell configuration. + const cell_configuration& cell_cfg; + ue_repository& ues; + + srslog::basic_logger& logger; + + // Storage of the periodic SRSs to be scheduled in the resource grid. Each position of the vector represents a slot + // in a ring-like structure (ie slot % WHEEL_SIZE). Each of these vector indexes/slots contains a list of periodic + // SRS information to be scheduled in the respective slot. + std::vector> periodic_srs_slot_wheel; + + // UEs whose configuration has been updated in between the last and current slot indications. + std::vector updated_ues; +}; + +} // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 915851990c..27eaa965ee 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -11,6 +11,7 @@ #include "ue_event_manager.h" #include "../logging/scheduler_event_logger.h" #include "../logging/scheduler_metrics_handler.h" +#include "../srs/srs_scheduler.h" #include "../uci_scheduling/uci_scheduler_impl.h" using namespace srsran; @@ -149,6 +150,9 @@ void ue_event_manager::handle_ue_creation(ue_config_update_event ev) // Update UCI scheduler with new UE UCI resources. du_cells[pcell_index].uci_sched->add_ue(added_ue.get_cell(to_ue_cell_index(i)).cfg()); + // Update SRS scheduler with new UE SRS resources. + du_cells[pcell_index].srs_sched->add_ue(added_ue.get_cell(to_ue_cell_index(i)).cfg()); + // Add UE to slice scheduler. // Note: This action only has effect when UE is created in non-fallback mode. du_cells[pcell_index].slice_sched->add_ue(ueidx); @@ -187,11 +191,14 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) // UE carrier is being removed. // Update UE UCI resources in UCI scheduler. du_cells[ue_cc.cell_index].uci_sched->rem_ue(ue_cc.cfg()); + // Update UE SRS resources in SRS scheduler. + du_cells[ue_cc.cell_index].srs_sched->rem_ue(ue_cc.cfg()); // Schedule removal of UE in slice scheduler. du_cells[ue_cc.cell_index].slice_sched->rem_ue(ue_idx); } else { // UE carrier is being reconfigured. du_cells[ue_cc.cell_index].uci_sched->reconf_ue(ev.next_config().ue_cell_cfg(ue_cc.cell_index), ue_cc.cfg()); + du_cells[ue_cc.cell_index].srs_sched->reconf_ue(ev.next_config().ue_cell_cfg(ue_cc.cell_index), ue_cc.cfg()); } } for (unsigned i = 0, e = ev.next_config().nof_cells(); i != e; ++i) { @@ -200,6 +207,8 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) if (ue_cc == nullptr) { // New UE carrier is being added. du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].uci_sched->add_ue(new_ue_cc_cfg); + + du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].srs_sched->add_ue(new_ue_cc_cfg); } } @@ -242,6 +251,8 @@ void ue_event_manager::handle_ue_deletion(ue_config_delete_event ev) for (unsigned i = 0, e = u.nof_cells(); i != e; ++i) { // Update UCI scheduling by removing existing UE UCI resources. du_cells[u.get_cell(to_ue_cell_index(i)).cell_index].uci_sched->rem_ue(u.get_pcell().cfg()); + // Update SRS scheduling by removing existing UE SRS resources. + du_cells[u.get_cell(to_ue_cell_index(i)).cell_index].srs_sched->rem_ue(u.get_pcell().cfg()); // Schedule removal of UE from slice scheduler. du_cells[u.get_cell(to_ue_cell_index(i)).cell_index].slice_sched->rem_ue(ue_idx); } @@ -739,6 +750,7 @@ void ue_event_manager::add_cell(const cell_creation_event& cell_ev) du_cells[cell_index].fallback_sched = &cell_ev.fallback_sched; du_cells[cell_index].uci_sched = &cell_ev.uci_sched; du_cells[cell_index].slice_sched = &cell_ev.slice_sched; + du_cells[cell_index].srs_sched = &cell_ev.srs_sched; du_cells[cell_index].metrics = &cell_ev.metrics; du_cells[cell_index].ev_logger = &cell_ev.ev_logger; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.h b/lib/scheduler/ue_scheduling/ue_event_manager.h index c101015677..67ac6b6ad8 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.h +++ b/lib/scheduler/ue_scheduling/ue_event_manager.h @@ -25,6 +25,7 @@ class cell_metrics_handler; class scheduler_event_logger; class uci_scheduler_impl; class cell_harq_manager; +class srs_scheduler; struct cell_creation_event { cell_resource_allocator& cell_res_grid; @@ -32,6 +33,7 @@ struct cell_creation_event { ue_fallback_scheduler& fallback_sched; uci_scheduler_impl& uci_sched; slice_scheduler& slice_sched; + srs_scheduler& srs_sched; cell_metrics_handler& metrics; scheduler_event_logger& ev_logger; }; @@ -131,6 +133,7 @@ class ue_event_manager final : public sched_ue_configuration_handler, ue_fallback_scheduler* fallback_sched = nullptr; uci_scheduler_impl* uci_sched = nullptr; slice_scheduler* slice_sched = nullptr; + srs_scheduler* srs_sched = nullptr; cell_metrics_handler* metrics = nullptr; scheduler_event_logger* ev_logger = nullptr; }; diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 7480cc157e..20521bf0ac 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -30,6 +30,7 @@ void ue_scheduler_impl::add_cell(const ue_scheduler_cell_params& params) cells[params.cell_index].fallback_sched, cells[params.cell_index].uci_sched, cells[params.cell_index].slice_sched, + cells[params.cell_index].srs_sched, *params.cell_metrics, *params.ev_logger}); ue_alloc.add_cell(params.cell_index, *params.pdcch_sched, *params.uci_alloc, *params.cell_res_alloc); @@ -201,6 +202,9 @@ void ue_scheduler_impl::run_slot(slot_point slot_tx) // Schedule periodic UCI (SR and CSI) before any UL grants. group_cell.uci_sched.run_slot(*group_cell.cell_res_alloc); + // Schedule periodic SRS before any UE grants. + cells[cell_index].srs_sched.run_slot(*group_cell.cell_res_alloc); + // Run cell-specific SRB0 scheduler. group_cell.fallback_sched.run_slot(*group_cell.cell_res_alloc); @@ -241,6 +245,7 @@ ue_scheduler_impl::cell::cell(const scheduler_ue_expert_config& expert_cfg, cell_harqs(MAX_NOF_DU_UES, MAX_NOF_HARQS, std::make_unique(metrics_handler)), uci_sched(params.cell_res_alloc->cfg, *params.uci_alloc, ues), fallback_sched(expert_cfg, params.cell_res_alloc->cfg, *params.pdcch_sched, *params.pucch_alloc, ues), - slice_sched(params.cell_res_alloc->cfg, ues) + slice_sched(params.cell_res_alloc->cfg, ues), + srs_sched(params.cell_res_alloc->cfg, ues) { } diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h index e59f88cd07..b78a0fbe5b 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h @@ -15,6 +15,7 @@ #include "../policy/scheduler_policy.h" #include "../pucch_scheduling/pucch_guardbands_scheduler.h" #include "../slicing/slice_scheduler.h" +#include "../srs/srs_scheduler_impl.h" #include "../uci_scheduling/uci_scheduler_impl.h" #include "ue_cell_grid_allocator.h" #include "ue_event_manager.h" @@ -72,6 +73,9 @@ class ue_scheduler_impl final : public ue_scheduler /// Slice scheduler. slice_scheduler slice_sched; + /// SRS scheduler + srs_scheduler_impl srs_sched; + cell(const scheduler_ue_expert_config& expert_cfg, const ue_scheduler_cell_params& params, ue_repository& ues, From 7c6f5ed62f9126f659f895377fce814e9b63dbcc Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 18 Sep 2024 11:02:31 +0200 Subject: [PATCH 08/32] sched: add SRS scheduler unittest Signed-off-by: Carlo Galiotto --- lib/scheduler/cell/resource_grid.cpp | 1 + lib/scheduler/srs/srs_scheduler_impl.cpp | 8 +- tests/unittests/scheduler/CMakeLists.txt | 1 + .../scheduler/srs_scheduling/CMakeLists.txt | 18 + .../srs_scheduling/srs_scheduler_test.cpp | 326 ++++++++++++++++++ 5 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 tests/unittests/scheduler/srs_scheduling/CMakeLists.txt create mode 100644 tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp diff --git a/lib/scheduler/cell/resource_grid.cpp b/lib/scheduler/cell/resource_grid.cpp index 9b6e7f475e..9082624478 100644 --- a/lib/scheduler/cell/resource_grid.cpp +++ b/lib/scheduler/cell/resource_grid.cpp @@ -274,6 +274,7 @@ void cell_slot_resource_allocator::slot_indication(slot_point new_slot) result.ul.puschs.clear(); result.ul.prachs.clear(); result.ul.pucchs.clear(); + result.ul.srss.clear(); dl_res_grid.clear(); ul_res_grid.clear(); diff --git a/lib/scheduler/srs/srs_scheduler_impl.cpp b/lib/scheduler/srs/srs_scheduler_impl.cpp index aea552398e..c099ad66c5 100644 --- a/lib/scheduler/srs/srs_scheduler_impl.cpp +++ b/lib/scheduler/srs/srs_scheduler_impl.cpp @@ -19,8 +19,8 @@ using namespace srsran; srs_scheduler_impl::srs_scheduler_impl(const cell_configuration& cell_cfg_, ue_repository& ues_) : cell_cfg(cell_cfg_), ues(ues_), logger(srslog::fetch_basic_logger("SCHED")) { - // Max size of the SRS resource slot wheel, dimensioned based on the SRS periods. - periodic_srs_slot_wheel.resize(std::max(MAX_SR_PERIOD, MAX_CSI_REPORT_PERIOD)); + // Max size of the SRS resource slot wheel, dimensioned based on the maximum SRS periods. + periodic_srs_slot_wheel.resize(static_cast(srs_periodicity::sl2560)); // Pre-reserve space for the UEs that will be added. updated_ues.reserve(MAX_NOF_DU_UES); @@ -78,6 +78,9 @@ void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) srs_res->id.ue_res_id); } } + + // Register the UE in the list of recently configured UEs. + updated_ues.push_back(ue_cfg.crnti); } void srs_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) @@ -158,6 +161,7 @@ void srs_scheduler_impl::schedule_updated_ues_srs(cell_resource_allocator& cell_ // Schedule SRS up to the farthest slot. for (unsigned n = 0; n != cell_alloc.max_ul_slot_alloc_delay; ++n) { auto& slot_srss = periodic_srs_slot_wheel[(cell_alloc.slot_tx() + n).to_uint() % periodic_srs_slot_wheel.size()]; + // For all the periodic SRS info element at this slot, allocate only those that belong to the UE updated_ues. for (const periodic_srs_info& srs : slot_srss) { const bool rnti_in_updated_ues = diff --git a/tests/unittests/scheduler/CMakeLists.txt b/tests/unittests/scheduler/CMakeLists.txt index 4e99a8683e..f4fd074930 100644 --- a/tests/unittests/scheduler/CMakeLists.txt +++ b/tests/unittests/scheduler/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory(uci_and_pucch) add_subdirectory(policy) add_subdirectory(config) add_subdirectory(slicing) +add_subdirectory(srs_scheduling) add_executable(sched_no_ue_test scheduler_no_ue_test.cpp) target_link_libraries(sched_no_ue_test srsran_sched diff --git a/tests/unittests/scheduler/srs_scheduling/CMakeLists.txt b/tests/unittests/scheduler/srs_scheduling/CMakeLists.txt new file mode 100644 index 0000000000..a128cd3cde --- /dev/null +++ b/tests/unittests/scheduler/srs_scheduling/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +add_executable(srs_sched_test + srs_scheduler_test.cpp) +target_link_libraries(srs_sched_test + srsran_sched + scheduler_test_suite + srslog + sched_config + gtest + gtest_main) +gtest_discover_tests(srs_sched_test) diff --git a/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp b/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp new file mode 100644 index 0000000000..a5d7edca57 --- /dev/null +++ b/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp @@ -0,0 +1,326 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "lib/scheduler/srs/srs_scheduler_impl.h" +#include "tests/unittests/scheduler/test_utils/config_generators.h" +#include "tests/unittests/scheduler/test_utils/dummy_test_components.h" +#include "tests/unittests/scheduler/test_utils/scheduler_test_suite.h" +#include "srsran/du/du_cell_config_helpers.h" +#include "srsran/ran/srs/srs_bandwidth_configuration.h" +#include "srsran/support/test_utils.h" +#include +#include + +using namespace srsran; + +namespace { + +class dummy_harq_timeout_notifier : public harq_timeout_notifier +{ +public: + dummy_harq_timeout_notifier(harq_timeout_handler& handler_) : handler(handler_) {} + + void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override + { + handler.handle_harq_timeout(ue_idx, is_dl); + } + +private: + harq_timeout_handler& handler; +}; + +} // namespace + +static unsigned compute_c_srs(unsigned nof_ul_crbs) +{ + // In this test, we only consider the case where B_SRS is 0. + const uint8_t b_srs = 0U; + unsigned candidate_c_srs = 0U; + unsigned candidate_m_srs = 0U; + // Spans over Table 6.4.1.4.3-1 in TS 38.211 and find the smallest C_SRS that maximizes m_srs_0 under the + // constraint of m_SRS <= nof_BW_RBs. + for (unsigned c_srs_it = 0; c_srs_it != 64; ++c_srs_it) { + std::optional srs_cfg = srs_configuration_get(c_srs_it, b_srs); + srsran_assert(srs_cfg.has_value(), "C_SRS is required for this unittest"); + if (srs_cfg.value().m_srs <= nof_ul_crbs and srs_cfg.value().m_srs > candidate_m_srs) { + candidate_m_srs = srs_cfg->m_srs; + candidate_c_srs = c_srs_it; + } + } + return candidate_c_srs; +} + +static sched_cell_configuration_request_message make_custom_sched_cell_configuration_request(bool is_tdd = false) +{ + sched_cell_configuration_request_message req = test_helpers::make_default_sched_cell_configuration_request( + cell_config_builder_params{.scs_common = is_tdd ? subcarrier_spacing::kHz30 : subcarrier_spacing::kHz15, + .channel_bw_mhz = bs_channel_bandwidth::MHz20, + .dl_f_ref_arfcn = is_tdd ? 520000U : 365000U}); + return req; +} + +static bool is_ul_slot(unsigned offset, const tdd_ul_dl_config_common& tdd_cfg) +{ + const unsigned slot_index = offset % (NOF_SUBFRAMES_PER_FRAME * get_nof_slots_per_subframe(tdd_cfg.ref_scs)); + return srsran::get_active_tdd_ul_symbols(tdd_cfg, slot_index, cyclic_prefix::NORMAL).length() != 0; +} + +static sched_ue_creation_request_message +create_sched_ue_creation_request_for_srs_cfg(srs_periodicity srs_period, + unsigned nof_ul_crbs, + const std::optional tdd_cfg) +{ + sched_ue_creation_request_message ue_req = test_helpers::create_default_sched_ue_creation_request(); + auto& ue_srs_cfg = ue_req.cfg.cells.value().front().serv_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.value(); + + // Set SRS resource set periodic. + ue_srs_cfg.srs_res_set_list.front().res_type.emplace(); + + // Set SRS resource periodic. + srs_config::srs_resource& srs_res = ue_srs_cfg.srs_res_list.front(); + srs_res.res_type = srs_resource_type::periodic; + uint16_t srs_offset = 0U; + // The offset needs to be an UL slot. + if (tdd_cfg.has_value()) { + srsran_assert(static_cast(srs_period) >= tdd_cfg.value().pattern1.dl_ul_tx_period_nof_slots, + "SRS period cannot be smaller than the TDD period"); + + srs_offset = test_rgen::uniform_int(0, static_cast(srs_period) - 1); + while (not is_ul_slot(srs_offset, tdd_cfg.value())) { + srs_offset = test_rgen::uniform_int(0, static_cast(srs_period) - 1); + } + } else { + srs_offset = test_rgen::uniform_int(0, static_cast(srs_period) - 1); + } + srs_res.periodicity_and_offset.emplace(srs_config::srs_periodicity_and_offset{srs_period, srs_offset}); + + // This is for 1 UE only. If more UEs are added, this should be updated. + srs_res.tx_comb.size = srsran::tx_comb_size::n4; + srs_res.tx_comb.tx_comb_offset = 0U; + srs_res.tx_comb.tx_comb_cyclic_shift = 0U; + + // Set SRS in symbols [13, 14). + srs_res.res_mapping.start_pos = 0U; + srs_res.res_mapping.nof_symb = n1; + srs_res.res_mapping.rept_factor = n1; + + // Frequency hopping is disabled. + srs_res.freq_domain_pos = 0U; + srs_res.freq_hop.b_hop = 0U; + srs_res.freq_hop.b_srs = 0U; + srs_res.freq_hop.c_srs = compute_c_srs(nof_ul_crbs); + + // SRS placed in the middle of the BW. + std::optional srs_bw_cfg = srs_configuration_get(srs_res.freq_hop.c_srs, srs_res.freq_hop.b_srs); + srsran_assert(srs_bw_cfg.has_value(), "C_SRS is required for this unittest"); + srs_res.freq_domain_shift = (nof_ul_crbs - srs_bw_cfg->m_srs) / 2U; + + srs_res.sequence_id = 0U; + + return ue_req; +} + +struct srs_test_params { + bool is_tdd; + srs_periodicity period; +}; + +class test_bench +{ +public: + test_bench(srs_test_params params) : + expert_cfg{config_helpers::make_default_scheduler_expert_config()}, + cell_cfg{[this, ¶ms]() -> const cell_configuration& { + cell_cfg_list.emplace(to_du_cell_index(0), + std::make_unique( + expert_cfg, make_custom_sched_cell_configuration_request(params.is_tdd))); + return *cell_cfg_list[to_du_cell_index(0)]; + }()}, + cell_harqs{MAX_NOF_DU_UES, MAX_NOF_HARQS, std::make_unique(harq_timeout_handler)}, + srs_sched(cell_cfg, ues), + current_sl_tx{to_numerology_value(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs), 0} + { + slot_indication(current_sl_tx); + mac_logger.set_level(srslog::basic_levels::debug); + } + + // Class members. + scheduler_expert_config expert_cfg; + scheduler_harq_timeout_dummy_handler harq_timeout_handler; + cell_common_configuration_list cell_cfg_list{}; + const cell_configuration& cell_cfg; + cell_harq_manager cell_harqs; + ue_repository ues; + std::vector ue_ded_cfgs; + cell_resource_allocator res_grid{cell_cfg}; + srs_scheduler_impl srs_sched; + slot_point current_sl_tx; + + srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("SCHED", true); + srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); + + // Class methods. + void add_ue(srs_periodicity srs_period) + { + sched_ue_creation_request_message ue_req = create_sched_ue_creation_request_for_srs_cfg( + srs_period, + cell_cfg_list[to_du_cell_index(0)]->ul_cfg_common.init_ul_bwp.generic_params.crbs.length(), + cell_cfg.tdd_cfg_common); + ue_ded_cfgs.emplace_back(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg); + ues.add_ue(std::make_unique(ue_creation_command{ue_ded_cfgs.back(), ue_req.starts_in_fallback, cell_harqs})); + srs_sched.add_ue(ues[ue_req.ue_index].get_pcell().cfg()); + } + + void slot_indication(slot_point slot_tx) + { + mac_logger.set_context(slot_tx.sfn(), slot_tx.slot_index()); + test_logger.set_context(slot_tx.sfn(), slot_tx.slot_index()); + res_grid.slot_indication(slot_tx); + } + + expected test_srs_pdu(const srs_info& srs_pdu) const + { + const auto& srs_cfg = + ues[to_du_ue_index(0)].get_pcell().cfg().cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); + const auto& srs_res_cfg = srs_cfg.srs_res_list.front(); + + if (srs_pdu.crnti != ues[to_du_ue_index(0)].crnti) { + return make_unexpected(std::string("RNTI mismatch")); + } + if (srs_pdu.bwp_cfg != &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params) { + return make_unexpected(std::string("BWP mismatch")); + } + if (srs_pdu.nof_antenna_ports != cell_cfg.ul_carrier.nof_ant) { + return make_unexpected(std::string("Nof antenna ports mismatch")); + } + if (srs_pdu.symbols != ofdm_symbol_range{NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - 1 - srs_res_cfg.res_mapping.start_pos, + NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - 1 - srs_res_cfg.res_mapping.start_pos + + static_cast(srs_res_cfg.res_mapping.nof_symb)}) { + return make_unexpected(std::string("Symbols mismatch")); + } + if (srs_pdu.nof_repetitions != srs_res_cfg.res_mapping.rept_factor) { + return make_unexpected(std::string("Repetition factor mismatch")); + } + if (srs_pdu.config_index != srs_res_cfg.freq_hop.c_srs) { + return make_unexpected(std::string("Frequency domain shift mismatch")); + } + if (srs_pdu.sequence_id != static_cast(srs_res_cfg.sequence_id)) { + return make_unexpected(std::string("Sequence ID mismatch")); + } + if (srs_pdu.bw_index != srs_res_cfg.freq_hop.b_srs) { + return make_unexpected(std::string("B_srs mismatch")); + } + if (srs_pdu.tx_comb != srs_res_cfg.tx_comb.size) { + return make_unexpected(std::string("TX comb size mismatch")); + } + if (srs_pdu.comb_offset != srs_res_cfg.tx_comb.tx_comb_offset) { + return make_unexpected(std::string("TX comb offset mismatch")); + } + if (srs_pdu.cyclic_shift != srs_res_cfg.tx_comb.tx_comb_cyclic_shift) { + return make_unexpected(std::string("TX comb cyclic shift mismatch")); + } + if (srs_pdu.freq_position != srs_res_cfg.freq_domain_pos) { + return make_unexpected(std::string("Freq. domain position mismatch")); + } + if (srs_pdu.freq_shift != static_cast(srs_res_cfg.freq_domain_shift)) { + return make_unexpected(std::string("Freq. domain position mismatch")); + } + if (srs_pdu.freq_hopping != srs_res_cfg.freq_hop.b_hop) { + return make_unexpected(std::string("b_hop mismatch")); + } + if (srs_pdu.group_or_seq_hopping != srs_res_cfg.grp_or_seq_hop) { + return make_unexpected(std::string("group_or_seq_hopping mismatch")); + } + if (srs_pdu.resource_type != srs_res_cfg.res_type) { + return make_unexpected(std::string("group_or_seq_hopping mismatch")); + } + if (srs_res_cfg.res_type != srsran::srs_resource_type::aperiodic) { + srsran_assert(srs_res_cfg.periodicity_and_offset.has_value(), "Periodicity and offset is required for this test"); + if (srs_pdu.t_srs_period != srs_res_cfg.periodicity_and_offset.value().period) { + return make_unexpected(std::string("Periodicity mismatch")); + } + if (srs_pdu.t_offset != static_cast(srs_res_cfg.periodicity_and_offset.value().offset)) { + return make_unexpected(std::string("Offset mismatch")); + } + } + + return true; + } + + uint16_t get_offset() const + { + if (ues.empty()) { + return 0; + } + return ues[to_du_ue_index(0U)] + .get_pcell() + .cfg() + .cfg_dedicated() + .ul_config.value() + .init_ul_bwp.srs_cfg.value() + .srs_res_list.front() + .periodicity_and_offset->offset; + } +}; + +class srs_scheduler_tester : public ::testing::TestWithParam, public test_bench +{ +protected: + srs_scheduler_tester() : test_bench(GetParam()) {} +}; + +TEST_P(srs_scheduler_tester, test_different_periods) +{ + unsigned srs_period_uint = static_cast(GetParam().period); + + const unsigned add_ue_slot = test_rgen::uniform_int(0, res_grid.RING_ALLOCATOR_SIZE); + // Check at the allocation for at least 4 the size of the resource grid. + const unsigned nof_slots_to_test = + add_ue_slot + std::max(srs_period_uint * 4, static_cast(res_grid.RING_ALLOCATOR_SIZE) * 4); + + for (unsigned sl_cnt = 0; sl_cnt < nof_slots_to_test + add_ue_slot; ++sl_cnt) { + // Add the UE at the specified slot. + if (sl_cnt == add_ue_slot) { + add_ue(GetParam().period); + } + + srs_sched.run_slot(res_grid); + // Only check the results once the UE has been added. + if (not ues.empty() and (current_sl_tx - get_offset()).to_uint() % srs_period_uint == 0) { + ASSERT_EQ(1, res_grid[0].result.ul.srss.size()); + expected pdu_test = test_srs_pdu(res_grid[0].result.ul.srss.front()); + ASSERT_TRUE(pdu_test.has_value()) << pdu_test.error(); + } else { + ASSERT_TRUE(res_grid[0].result.ul.srss.empty()); + } + + // Update the slot indicator. + slot_indication(++current_sl_tx); + } +} + +INSTANTIATE_TEST_SUITE_P(test_srs_scheduler_for_different_periods, + srs_scheduler_tester, + testing::Values(srs_test_params{.is_tdd = false, .period = srs_periodicity::sl1}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl2}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl4}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl5}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl8}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl10}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl20}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl40}, + srs_test_params{.is_tdd = false, .period = srs_periodicity::sl80}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl10}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl20}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl40}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl80}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl160}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl320}, + srs_test_params{.is_tdd = true, .period = srs_periodicity::sl640})); From 641e5d384fd5201f49582cb609ff3416a4df08c4 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 18 Sep 2024 19:12:11 +0200 Subject: [PATCH 09/32] sched: add validator for ue SRS configuration Signed-off-by: Carlo Galiotto --- .../config/serving_cell_config_validator.h | 7 ++- .../config/scheduler_ue_config_validator.cpp | 4 +- .../config/serving_cell_config_validator.cpp | 50 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/srsran/scheduler/config/serving_cell_config_validator.h b/include/srsran/scheduler/config/serving_cell_config_validator.h index 3b44d53ca9..08eb03b87b 100644 --- a/include/srsran/scheduler/config/serving_cell_config_validator.h +++ b/include/srsran/scheduler/config/serving_cell_config_validator.h @@ -32,7 +32,12 @@ validator_result validate_pdsch_cfg(const serving_cell_config& ue_cell_cfg); /// \param[in] ue_cell_cfg UE serving cell configuration to be validated. /// \param[in] nof_dl_antennas Number of antennas used for DL tx. /// \return In case an invalid parameter is detected, returns a string containing an error message. -error_type validate_pucch_cfg(const serving_cell_config& ue_cell_cfg, unsigned nof_dl_antennas); +validator_result validate_pucch_cfg(const serving_cell_config& ue_cell_cfg, unsigned nof_dl_antennas); + +/// \brief Validates SRS Config in \c sched_ue_creation_request_message used to create a UE. +/// \param[in] ue_cell_cfg UE serving cell configuration to be validated. +/// \return In case an invalid parameter is detected, returns a string containing an error message. +validator_result validate_srs_cfg(const serving_cell_config& ue_cell_cfg); /// \brief Validates the NZP-CSI-RS Resource list in \c serving_cell_config passed to a UE. validator_result validate_nzp_csi_rs_list(span nzp_csi_rs_list, diff --git a/lib/scheduler/config/scheduler_ue_config_validator.cpp b/lib/scheduler/config/scheduler_ue_config_validator.cpp index 64ac11465b..4c4868824f 100644 --- a/lib/scheduler/config/scheduler_ue_config_validator.cpp +++ b/lib/scheduler/config/scheduler_ue_config_validator.cpp @@ -28,8 +28,10 @@ srsran::config_validators::validate_sched_ue_creation_request_message(const sche HANDLE_ERROR(validate_pdsch_cfg(cell.serv_cell_cfg)); - if (cell.serv_cell_cfg.ul_config.has_value() and cell.serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.has_value()) { + if (cell.serv_cell_cfg.ul_config.has_value() and cell.serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.has_value() and + cell.serv_cell_cfg.ul_config->init_ul_bwp.srs_cfg.has_value()) { HANDLE_ERROR(validate_pucch_cfg(cell.serv_cell_cfg, cell_cfg.dl_carrier.nof_ant)); + HANDLE_ERROR(validate_srs_cfg(cell.serv_cell_cfg)); } HANDLE_ERROR(validate_csi_meas_cfg(cell.serv_cell_cfg, cell_cfg.tdd_cfg_common)); diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index 3ab586710b..d6aab0cd0e 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -400,6 +400,56 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel return {}; } +validator_result srsran::config_validators::validate_srs_cfg(const serving_cell_config& ue_cell_cfg) +{ + VERIFY(ue_cell_cfg.ul_config.has_value() and ue_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.has_value(), + "Missing configuration for uplinkConfig or pucch-Config in spCellConfig"); + + const auto& srs_cfg = ue_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.value(); + + VERIFY(srs_cfg.srs_res_set_list.size() == 1 and srs_cfg.srs_res_set_list.front().id == srs_config::MIN_SRS_RES_SET_ID, + "The SRS resource set list is expected to have a size of 1 and the SRS resource set ID to be 0"); + VERIFY(srs_cfg.srs_res_set_list.front().srs_res_id_list.size() == 1, + "The SRS resource set list is expected to have a size of 1"); + VERIFY(srs_cfg.srs_res_list.size() == 1 and srs_cfg.srs_res_list.front().id.ue_res_id == srs_config::MIN_SRS_RES_ID, + "The SRS resource lits is expected to have a size of 1 and the SRS resource ID to be 0"); + VERIFY(srs_cfg.srs_res_set_list.front().srs_res_id_list.front() == srs_cfg.srs_res_list.front().id.ue_res_id, + "The SRS resource set list should point to the SRS resource list"); + const auto& srs_res_set = srs_cfg.srs_res_set_list.front(); + VERIFY(srs_res_set.srs_res_set_usage == srs_config::srs_resource_set::usage::codebook, + "Only SRS resource set usage of codebook is supported"); + + const auto& srs_res = srs_cfg.srs_res_list.front(); + VERIFY( + (std::holds_alternative(srs_res_set.res_type) and + srs_res.res_type == srs_resource_type::aperiodic) or + (std::holds_alternative(srs_res_set.res_type) and + srs_res.res_type == srs_resource_type::periodic) or + (std::holds_alternative(srs_res_set.res_type) and + srs_res.res_type == srs_resource_type::semi_persistent), + "The SRS resource set and resource should have the same type"); + if (srs_res.res_type == srs_resource_type::periodic) { + VERIFY(srs_res.periodicity_and_offset.has_value(), + "The SRS resource should have a periodicity and offset when the resource type is periodic"); + VERIFY(srs_res.periodicity_and_offset.value().offset < + static_cast(srs_res.periodicity_and_offset.value().period), + "The SRS resource offset should be less than the periodicity"); + } + VERIFY(srs_res.tx_comb.tx_comb_offset < static_cast(srs_res.tx_comb.size), + "The SRS resource txCombOffset should be less than the TX comb size"); + const uint8_t max_tx_comb_cs = srs_res.tx_comb.size == tx_comb_size::n2 ? 7U : 11U; + VERIFY(srs_res.tx_comb.tx_comb_cyclic_shift <= max_tx_comb_cs, + "The SRS resource tx_comb_cyclic_shift should be less than or equal to 7 for TX comb size n2 and TX comb size " + "11 for n4"); + VERIFY(srs_res.res_mapping.rept_factor <= srs_res.res_mapping.nof_symb, + "The SRS resource repetition factor should be less than or equal to the number of symbols"); + VERIFY(static_cast(srs_res.res_mapping.nof_symb) <= srs_res.res_mapping.start_pos + 1, + "The SRS resource number of symbols and start position should be such that the SRS resource fits within the " + "slot symbols"); + + return {}; +} + validator_result srsran::config_validators::validate_nzp_csi_rs_list(span nzp_csi_rs_res_list, const std::optional& tdd_cfg_common) From 2947c63cded657690bdb90af344cac1187399b75 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 19 Sep 2024 10:43:02 +0200 Subject: [PATCH 10/32] sched: add srs entry to sched result logs Signed-off-by: Carlo Galiotto --- lib/scheduler/logging/scheduler_result_logger.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/scheduler/logging/scheduler_result_logger.cpp b/lib/scheduler/logging/scheduler_result_logger.cpp index c4cc30fc4f..76cf6ada9d 100644 --- a/lib/scheduler/logging/scheduler_result_logger.cpp +++ b/lib/scheduler/logging/scheduler_result_logger.cpp @@ -288,6 +288,19 @@ void scheduler_result_logger::log_debug(const sched_result& result, std::chrono: } } + for (const auto& srs : result.ul.srss) { + fmt::format_to(fmtbuf, + "\n- SRS: c-rnti={} symb={} tx-comb=(n{} o={} cs={}) c_srs={} f_sh={} seq_id={}", + srs.crnti, + srs.symbols, + static_cast(srs.tx_comb), + srs.comb_offset, + srs.cyclic_shift, + srs.config_index, + srs.freq_shift, + srs.sequence_id); + } + if (fmtbuf.size() > 0) { const unsigned nof_pdschs = result.dl.paging_grants.size() + result.dl.rar_grants.size() + result.dl.ue_grants.size() + result.dl.bc.sibs.size(); From a9b40b235af9af0ff26b596302fbf83b247f5875 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 27 Sep 2024 12:28:49 +0200 Subject: [PATCH 11/32] sched: improve comments in SRS scheduler Signed-off-by: Carlo Galiotto --- .../config/serving_cell_config_validator.cpp | 19 +++++++++++------- lib/scheduler/srs/srs_scheduler_impl.cpp | 20 ++++++++++++++----- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index d6aab0cd0e..ee21f3506b 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -403,21 +403,21 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel validator_result srsran::config_validators::validate_srs_cfg(const serving_cell_config& ue_cell_cfg) { VERIFY(ue_cell_cfg.ul_config.has_value() and ue_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.has_value(), - "Missing configuration for uplinkConfig or pucch-Config in spCellConfig"); + "Missing configuration for uplinkConfig or srs-Config in spCellConfig"); const auto& srs_cfg = ue_cell_cfg.ul_config.value().init_ul_bwp.srs_cfg.value(); VERIFY(srs_cfg.srs_res_set_list.size() == 1 and srs_cfg.srs_res_set_list.front().id == srs_config::MIN_SRS_RES_SET_ID, - "The SRS resource set list is expected to have a size of 1 and the SRS resource set ID to be 0"); + "The SRS resource set list is expected to have size 1 and its only set is expected to have ID 0"); VERIFY(srs_cfg.srs_res_set_list.front().srs_res_id_list.size() == 1, - "The SRS resource set list is expected to have a size of 1"); + "The SRS resource list of the SRS resource set ID 0 is expected to have size 1"); VERIFY(srs_cfg.srs_res_list.size() == 1 and srs_cfg.srs_res_list.front().id.ue_res_id == srs_config::MIN_SRS_RES_ID, - "The SRS resource lits is expected to have a size of 1 and the SRS resource ID to be 0"); + "The SRS resource list is expected to have size 1 and its only resource is expected to have ID 0"); VERIFY(srs_cfg.srs_res_set_list.front().srs_res_id_list.front() == srs_cfg.srs_res_list.front().id.ue_res_id, - "The SRS resource set list should point to the SRS resource list"); + "The SRS resource set ID 0's resource should point to the SRS resource ID 0"); const auto& srs_res_set = srs_cfg.srs_res_set_list.front(); VERIFY(srs_res_set.srs_res_set_usage == srs_config::srs_resource_set::usage::codebook, - "Only SRS resource set usage of codebook is supported"); + "Only SRS resource set usage \"codebook\" is supported"); const auto& srs_res = srs_cfg.srs_res_list.front(); VERIFY( @@ -427,7 +427,7 @@ validator_result srsran::config_validators::validate_srs_cfg(const serving_cell_ srs_res.res_type == srs_resource_type::periodic) or (std::holds_alternative(srs_res_set.res_type) and srs_res.res_type == srs_resource_type::semi_persistent), - "The SRS resource set and resource should have the same type"); + "The SRS resource set and its resource should be of the same type"); if (srs_res.res_type == srs_resource_type::periodic) { VERIFY(srs_res.periodicity_and_offset.has_value(), "The SRS resource should have a periodicity and offset when the resource type is periodic"); @@ -443,6 +443,11 @@ validator_result srsran::config_validators::validate_srs_cfg(const serving_cell_ "11 for n4"); VERIFY(srs_res.res_mapping.rept_factor <= srs_res.res_mapping.nof_symb, "The SRS resource repetition factor should be less than or equal to the number of symbols"); + // NOTE: The parameter \c start_pos indicates the distance from the last symbol of the slot. The actual starting + // OFDM symbol is NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - (srs_res.res_mapping.start_pos + 1). + // The final symbol = + // NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - (srs_res.res_mapping.start_pos + 1) + srs_res.res_mapping.nof_symb + // needs to be less than or equal to NOF_OFDM_SYM_PER_SLOT_NORMAL_CP. VERIFY(static_cast(srs_res.res_mapping.nof_symb) <= srs_res.res_mapping.start_pos + 1, "The SRS resource number of symbols and start position should be such that the SRS resource fits within the " "slot symbols"); diff --git a/lib/scheduler/srs/srs_scheduler_impl.cpp b/lib/scheduler/srs/srs_scheduler_impl.cpp index c099ad66c5..4dab5ef0a2 100644 --- a/lib/scheduler/srs/srs_scheduler_impl.cpp +++ b/lib/scheduler/srs/srs_scheduler_impl.cpp @@ -35,8 +35,8 @@ void srs_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) // Initial allocation: we allocate opportunities all over the grid. schedule_updated_ues_srs(cell_alloc); - // Only allocate in the farthest slot in the grid, as the previous part of the allocation grid has been completed - // at the first this function was called. + // Only allocate in the farthest slot in the grid. The allocation in the first slots of the grid has been completed by + // the previous function. schedule_slot_srs(cell_alloc[cell_alloc.max_ul_slot_alloc_delay]); } @@ -48,7 +48,6 @@ void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) } const srs_config& srs_cfg = ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); - // In this list we assume that an SRS resource set configured as period only contains periodic SRS resources. auto get_srs_res_with_id = [&srs_cfg](unsigned srs_res_id) { return std::find_if( srs_cfg.srs_res_list.begin(), @@ -58,6 +57,7 @@ void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) for (const auto& srs_res_set : ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value().srs_res_set_list) { + // This scheduler is only for periodic SRS resources. if (not std::holds_alternative(srs_res_set.res_type)) { continue; } @@ -72,6 +72,12 @@ void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) srs_res_id); continue; } + // We assume that a periodic SRS resource set only contains periodic SRS resources. This has been checked in the + // scheduler configuration validator. + srsran_sanity_check(srs_res->periodicity_and_offset.has_value(), + "rnti={}: Periodicity and offset not set for SRS resource ID={}", + ue_cfg.crnti, + srs_res->id.ue_res_id); add_resource(ue_cfg.crnti, srs_res->periodicity_and_offset.value().period, srs_res->periodicity_and_offset.value().offset, @@ -91,7 +97,6 @@ void srs_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) } const srs_config& srs_cfg = ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.value(); - // In this list we assume that an SRS resource set configured as periodic only contains periodic SRS resources. auto get_srs_res_with_id = [&srs_cfg](unsigned srs_res_id) { return std::find_if( srs_cfg.srs_res_list.begin(), @@ -104,7 +109,6 @@ void srs_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) if (not std::holds_alternative(srs_res_set.res_type)) { continue; } - // We assume the for (const auto& srs_res_id : srs_res_set.srs_res_id_list) { const auto* srs_res = get_srs_res_with_id(srs_res_id); @@ -116,6 +120,12 @@ void srs_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) srs_res_id); continue; } + // We assume that a periodic SRS resource set only contains periodic SRS resources. This has been checked in the + // scheduler configuration validator. + srsran_sanity_check(srs_res->periodicity_and_offset.has_value(), + "rnti={}: Periodicity and offset not set for SRS resource ID={}", + ue_cfg.crnti, + srs_res->id.ue_res_id); rem_resource(ue_cfg.crnti, srs_res->periodicity_and_offset.value().period, srs_res->periodicity_and_offset.value().offset, From 56026d19f0dccb7130c6fcebc2cc5b337cc79b4f Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 19 Sep 2024 18:23:07 +0200 Subject: [PATCH 12/32] sched: take nof antenna ports from srs resource cfg Signed-off-by: Carlo Galiotto --- lib/scheduler/srs/srs_scheduler_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/srs/srs_scheduler_impl.cpp b/lib/scheduler/srs/srs_scheduler_impl.cpp index 4dab5ef0a2..fe7c3d8dc5 100644 --- a/lib/scheduler/srs/srs_scheduler_impl.cpp +++ b/lib/scheduler/srs/srs_scheduler_impl.cpp @@ -253,7 +253,7 @@ void srs_scheduler_impl::fill_srs_pdu(srs_info& pdu, { pdu.crnti = ue_cfg.crnti; pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - pdu.nof_antenna_ports = cell_cfg.ul_carrier.nof_ant; + pdu.nof_antenna_ports = static_cast(srs_res_cfg.nof_ports); const unsigned nof_symbs_per_slot = get_nsymb_per_slot(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.cp); const unsigned starting_symb = nof_symbs_per_slot - srs_res_cfg.res_mapping.start_pos - 1; From 70016d3b638b4e8735775a81b8a2245d36c627f4 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 30 Sep 2024 11:39:19 +0200 Subject: [PATCH 13/32] sched: fix valgrind issue in srs sched test Signed-off-by: Carlo Galiotto --- .../srs_scheduling/srs_scheduler_test.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp b/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp index a5d7edca57..14f12025c5 100644 --- a/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp +++ b/tests/unittests/scheduler/srs_scheduling/srs_scheduler_test.cpp @@ -127,11 +127,25 @@ create_sched_ue_creation_request_for_srs_cfg(srs_periodicity return ue_req; } +namespace srs_periodicity_test { + struct srs_test_params { bool is_tdd; srs_periodicity period; }; +std::ostream& operator<<(std::ostream& os, const srs_test_params& params) +{ + // Make sure there are no spaces nor colons in this string, otherwise Gtest complains about the test name being + // invalid. + os << "Is_tdd_" << params.is_tdd << "_srs_period_slots_" << static_cast(params.period); + return os; +} + +} // namespace srs_periodicity_test + +using namespace srs_periodicity_test; + class test_bench { public: @@ -278,9 +292,9 @@ class srs_scheduler_tester : public ::testing::TestWithParam, p TEST_P(srs_scheduler_tester, test_different_periods) { - unsigned srs_period_uint = static_cast(GetParam().period); + auto srs_period_uint = static_cast(GetParam().period); - const unsigned add_ue_slot = test_rgen::uniform_int(0, res_grid.RING_ALLOCATOR_SIZE); + const auto add_ue_slot = test_rgen::uniform_int(0, res_grid.RING_ALLOCATOR_SIZE); // Check at the allocation for at least 4 the size of the resource grid. const unsigned nof_slots_to_test = add_ue_slot + std::max(srs_period_uint * 4, static_cast(res_grid.RING_ALLOCATOR_SIZE) * 4); From 2d5f65e847b8cc480173d2b8b932228eb9c800ab Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 26 Sep 2024 11:56:57 +0200 Subject: [PATCH 14/32] app_units: added the interface cu_cp_application unit. Use the interface in the gNB and CU applications --- apps/cu/cu.cpp | 63 ++++++------ apps/gnb/gnb.cpp | 99 ++++++++++--------- apps/units/cu_cp/cu_cp_application_unit.h | 43 ++++++++ .../cu_cp/cu_cp_application_unit_impl.cpp | 28 ++++++ .../units/cu_cp/cu_cp_application_unit_impl.h | 22 ++++- apps/units/flexible_du/du_low/CMakeLists.txt | 1 + 6 files changed, 175 insertions(+), 81 deletions(-) create mode 100644 apps/units/cu_cp/cu_cp_application_unit.h diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 3d049d047d..33e90c4aaa 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -8,8 +8,6 @@ * */ -#include "srsran/cu_up/cu_up.h" -#include "srsran/cu_up/cu_up_factory.h" #include "srsran/f1ap/gateways/f1c_network_server_factory.h" #include "srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h" #include "srsran/gateways/udp_network_gateway.h" @@ -33,13 +31,9 @@ #include "apps/cu/cu_appconfig_cli11_schema.h" #include "apps/cu/cu_worker_manager.h" -#include "apps/units/cu_cp/cu_cp_builder.h" +#include "apps/units/cu_cp/cu_cp_application_unit.h" #include "apps/units/cu_cp/cu_cp_config_translators.h" -#include "apps/units/cu_cp/cu_cp_logger_registrator.h" #include "apps/units/cu_cp/cu_cp_unit_config.h" -#include "apps/units/cu_cp/cu_cp_unit_config_cli11_schema.h" -#include "apps/units/cu_cp/cu_cp_unit_config_validator.h" -#include "apps/units/cu_cp/cu_cp_unit_logger_config.h" #include "apps/units/cu_cp/pcap_factory.h" #include "apps/units/cu_up/cu_up_builder.h" #include "apps/units/cu_up/cu_up_logger_registrator.h" @@ -47,8 +41,11 @@ #include "apps/units/cu_up/cu_up_unit_config_cli11_schema.h" #include "apps/units/cu_up/cu_up_unit_config_translators.h" #include "apps/units/cu_up/cu_up_unit_config_validator.h" +#include "apps/units/cu_up/cu_up_unit_config_yaml_writer.h" #include "apps/units/cu_up/cu_up_wrapper.h" #include "apps/units/cu_up/pcap_factory.h" +#include "srsran/cu_up/cu_up.h" +#include "srsran/cu_up/cu_up_factory.h" // TODO remove apps/gnb/*.h #include "apps/gnb/adapters/e2_gateway_remote_connector.h" @@ -60,8 +57,6 @@ #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" #include "apps/services/stdin_command_dispatcher.h" -#include "apps/units/cu_cp/cu_cp_unit_config_yaml_writer.h" -#include "apps/units/cu_up/cu_up_unit_config_yaml_writer.h" #include "cu_appconfig.h" #include "cu_appconfig_validator.h" #include "cu_appconfig_yaml_writer.h" @@ -124,7 +119,7 @@ static void initialize_log(const std::string& filename) } static void register_app_logs(const logger_appconfig& log_cfg, - const cu_cp_unit_logger_config& cu_cp_loggers, + cu_cp_application_unit& cu_cp_app_unit, const cu_up_unit_logger_config& cu_up_loggers) { // Set log-level of app and all non-layer specific components to app level. @@ -149,7 +144,7 @@ static void register_app_logs(const logger_appconfig& log_cfg, metrics_logger.set_hex_dump_max_size(log_cfg.hex_max_size); // Register units logs. - register_cu_cp_loggers(cu_cp_loggers); + cu_cp_app_unit.on_loggers_registration(); register_cu_up_loggers(cu_up_loggers); } @@ -190,33 +185,36 @@ int main(int argc, char** argv) cu_appconfig cu_cfg; configure_cli11_with_cu_appconfig_schema(app, cu_cfg); - cu_cp_unit_config cu_cp_config; - cu_cp_config.pcap_cfg.set_default_filename("/tmp/cu"); - configure_cli11_with_cu_cp_unit_config_schema(app, cu_cp_config); + auto cu_cp_app_unit = create_cu_cp_application_unit(); + cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg.set_default_filename("/tmp/cu"); + cu_cp_app_unit->on_parsing_configuration_registration(app); cu_up_unit_config cu_up_config; cu_up_config.pcap_cfg.set_default_filename("/tmp/cu"); configure_cli11_with_cu_up_unit_config_schema(app, cu_up_config); // Set the callback for the app calling all the autoderivation functions. - app.callback([&app, &cu_cp_config, &cu_up_config]() { - autoderive_cu_cp_parameters_after_parsing(app, cu_cp_config); - autoderive_cu_up_parameters_after_parsing( - cu_cp_config.amf_config.amf.bind_addr, cu_cp_config.amf_config.no_core, cu_up_config); + app.callback([&app, &cu_cp_app_unit, &cu_up_config]() { + cu_cp_app_unit->on_configuration_parameters_autoderivation(app); + + autoderive_cu_up_parameters_after_parsing(cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf.bind_addr, + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, + cu_up_config); }); // Parse arguments. CLI11_PARSE(app, argc, argv); // Check the modified configuration. - if (!validate_cu_appconfig(cu_cfg) || !validate_cu_cp_unit_config(cu_cp_config) || + if (!validate_cu_appconfig(cu_cfg) || + !cu_cp_app_unit->on_configuration_validation(os_sched_affinity_bitmask::available_cpus()) || !validate_cu_up_unit_config(cu_up_config)) { report_error("Invalid configuration detected.\n"); } // Set up logging. initialize_log(cu_cfg.log_cfg.filename); - register_app_logs(cu_cfg.log_cfg, cu_cp_config.loggers, cu_up_config.loggers); + register_app_logs(cu_cfg.log_cfg, *cu_cp_app_unit, cu_up_config.loggers); // Log input configuration. srslog::basic_logger& config_logger = srslog::fetch_basic_logger("CONFIG"); @@ -224,7 +222,7 @@ int main(int argc, char** argv) YAML::Node node; fill_cu_appconfig_in_yaml_schema(node, cu_cfg); fill_cu_up_config_in_yaml_schema(node, cu_up_config); - fill_cu_cp_config_in_yaml_schema(node, cu_cp_config); + cu_cp_app_unit->dump_config(node); config_logger.debug("Input configuration (all values): \n{}", YAML::Dump(node)); } else { config_logger.info("Input configuration (only non-default values): \n{}", app.config_to_str(false, false)); @@ -261,10 +259,12 @@ int main(int argc, char** argv) check_drm_kms_polling(cu_logger); // Create worker manager. - cu_worker_manager workers{cu_cfg, cu_cp_config.pcap_cfg, cu_up_config.pcap_cfg, cu_up_config.gtpu_queue_size}; + cu_worker_manager workers{ + cu_cfg, cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg, cu_up_config.pcap_cfg, cu_up_config.gtpu_queue_size}; // Create layer specific PCAPs. - cu_cp_dlt_pcaps cu_cp_dlt_pcaps = create_cu_cp_dlt_pcap(cu_cp_config.pcap_cfg, *workers.get_executor_getter()); + cu_cp_dlt_pcaps cu_cp_dlt_pcaps = + create_cu_cp_dlt_pcap(cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg, *workers.get_executor_getter()); cu_up_dlt_pcaps cu_up_dlt_pcaps = create_cu_up_dlt_pcaps(cu_up_config.pcap_cfg, *workers.get_executor_getter()); // Create IO broker. @@ -315,16 +315,19 @@ int main(int argc, char** argv) cu_cp_dependencies.timers = cu_timers; // Create N2 Client Gateways. - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( - cu_cp_config.amf_config.no_core, cu_cp_config.amf_config.amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); - - for (const auto& amf : cu_cp_config.extra_amfs) { - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client( - generate_n2_client_config(cu_cp_config.amf_config.no_core, amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); + cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client( + generate_n2_client_config(cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf, + *cu_cp_dlt_pcaps.ngap, + *epoll_broker))); + + for (const auto& amf : cu_cp_app_unit->get_cu_cp_unit_config().extra_amfs) { + cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); } // create CU-CP. - auto cu_cp_obj_and_cmds = build_cu_cp(cu_cp_config, cu_cp_dependencies); + auto cu_cp_obj_and_cmds = cu_cp_app_unit->create_cu_cp(cu_cp_dependencies); srs_cu_cp::cu_cp& cu_cp_obj = *cu_cp_obj_and_cmds.unit; // Create console helper object for commands and metrics printing. diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index c89bfd73d0..69ebcd4292 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -46,31 +46,26 @@ // This include is not unused - it helps prevent false alarms from the thread sanitizer. #include "srsran/support/tsan_options.h" -#include "apps/units/cu_cp/cu_cp_config_translators.h" -#include "apps/units/cu_cp/cu_cp_logger_registrator.h" -#include "apps/units/cu_cp/cu_cp_unit_config_cli11_schema.h" -#include "apps/units/cu_cp/cu_cp_unit_config_validator.h" -#include "apps/units/cu_up/cu_up_logger_registrator.h" -#include "apps/units/cu_up/cu_up_unit_config_cli11_schema.h" -#include "apps/units/cu_up/cu_up_unit_config_validator.h" - -#include - #include "apps/services/application_message_banners.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" #include "apps/services/core_isolation_manager.h" #include "apps/services/metrics/metrics_manager.h" #include "apps/services/metrics/metrics_notifier_proxy.h" -#include "apps/units/cu_cp/cu_cp_builder.h" -#include "apps/units/cu_cp/cu_cp_unit_config_yaml_writer.h" +#include "apps/units/cu_cp/cu_cp_application_unit.h" +#include "apps/units/cu_cp/cu_cp_config_translators.h" +#include "apps/units/cu_cp/cu_cp_unit_config.h" #include "apps/units/cu_cp/pcap_factory.h" #include "apps/units/cu_up/cu_up_builder.h" +#include "apps/units/cu_up/cu_up_logger_registrator.h" +#include "apps/units/cu_up/cu_up_unit_config_cli11_schema.h" #include "apps/units/cu_up/cu_up_unit_config_translators.h" +#include "apps/units/cu_up/cu_up_unit_config_validator.h" #include "apps/units/cu_up/cu_up_unit_config_yaml_writer.h" #include "apps/units/cu_up/pcap_factory.h" #include "apps/units/flexible_du/du_high/du_high_config.h" #include "apps/units/flexible_du/du_high/pcap_factory.h" #include "apps/units/flexible_du/flexible_du_application_unit.h" +#include #include "srsran/du/du_power_controller.h" #include "srsran/support/cli11_utils.h" @@ -135,7 +130,7 @@ static void initialize_log(const std::string& filename) } static void register_app_logs(const logger_appconfig& log_cfg, - const cu_cp_unit_logger_config& cu_cp_loggers, + cu_cp_application_unit& cu_cp_app_unit, const cu_up_unit_logger_config& cu_up_loggers, flexible_du_application_unit& du_app_unit) { @@ -165,7 +160,7 @@ static void register_app_logs(const logger_appconfig& log_cfg, e2ap_logger.set_hex_dump_max_size(log_cfg.hex_max_size); // Register units logs. - register_cu_cp_loggers(cu_cp_loggers); + cu_cp_app_unit.on_loggers_registration(); register_cu_up_loggers(cu_up_loggers); du_app_unit.on_loggers_registration(); } @@ -216,9 +211,9 @@ int main(int argc, char** argv) // Configure CLI11 with the gNB application configuration schema. configure_cli11_with_gnb_appconfig_schema(app, gnb_cfg); - cu_cp_unit_config cu_cp_config; - cu_cp_config.pcap_cfg.set_default_filename("/tmp/gnb"); - configure_cli11_with_cu_cp_unit_config_schema(app, cu_cp_config); + auto cu_cp_app_unit = create_cu_cp_application_unit(); + cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg.set_default_filename("/tmp/gnb"); + cu_cp_app_unit->on_parsing_configuration_registration(app); cu_up_unit_config cu_up_config; cu_up_config.pcap_cfg.set_default_filename("/tmp/gnb"); @@ -229,38 +224,39 @@ int main(int argc, char** argv) du_app_unit->on_parsing_configuration_registration(app); // Set the callback for the app calling all the autoderivation functions. - app.callback([&app, &gnb_cfg, &du_app_unit, &cu_cp_config, &cu_up_config]() { + app.callback([&app, &gnb_cfg, &du_app_unit, &cu_cp_app_unit, &cu_up_config]() { + cu_cp_unit_config& cu_cp_unit_cfg = cu_cp_app_unit->get_cu_cp_unit_config(); autoderive_gnb_parameters_after_parsing(app, gnb_cfg); - autoderive_slicing_args(du_app_unit->get_du_high_unit_config(), cu_cp_config); + autoderive_slicing_args(du_app_unit->get_du_high_unit_config(), cu_cp_unit_cfg); du_app_unit->on_configuration_parameters_autoderivation(app); // If test mode is enabled, we auto-enable "no_core" option and generate a amf config with no core. if (du_app_unit->get_du_high_unit_config().is_testmode_enabled()) { - cu_cp_config.amf_config.no_core = true; - cu_cp_config.amf_config.amf.supported_tas = {{7, {{"00101", {s_nssai_t{1}}}}}}; + cu_cp_unit_cfg.amf_config.no_core = true; + cu_cp_unit_cfg.amf_config.amf.supported_tas = {{7, {{"00101", {s_nssai_t{1}}}}}}; } - autoderive_cu_cp_parameters_after_parsing(app, cu_cp_config); + cu_cp_app_unit->on_configuration_parameters_autoderivation(app); autoderive_cu_up_parameters_after_parsing( - cu_cp_config.amf_config.amf.bind_addr, cu_cp_config.amf_config.no_core, cu_up_config); + cu_cp_unit_cfg.amf_config.amf.bind_addr, cu_cp_unit_cfg.amf_config.no_core, cu_up_config); }); // Parse arguments. CLI11_PARSE(app, argc, argv); + auto available_cpu_mask = (gnb_cfg.expert_execution_cfg.affinities.isolated_cpus) + ? gnb_cfg.expert_execution_cfg.affinities.isolated_cpus.value() + : os_sched_affinity_bitmask::available_cpus(); // Check the modified configuration. - if (!validate_appconfig(gnb_cfg) || !validate_cu_cp_unit_config(cu_cp_config) || - !validate_cu_up_unit_config(cu_up_config) || - !du_app_unit->on_configuration_validation((gnb_cfg.expert_execution_cfg.affinities.isolated_cpus) - ? gnb_cfg.expert_execution_cfg.affinities.isolated_cpus.value() - : os_sched_affinity_bitmask::available_cpus()) || - !validate_plmn_and_tacs(du_app_unit->get_du_high_unit_config(), cu_cp_config)) { + if (!validate_appconfig(gnb_cfg) || !cu_cp_app_unit->on_configuration_validation(available_cpu_mask) || + !validate_cu_up_unit_config(cu_up_config) || !du_app_unit->on_configuration_validation(available_cpu_mask) || + !validate_plmn_and_tacs(du_app_unit->get_du_high_unit_config(), cu_cp_app_unit->get_cu_cp_unit_config())) { report_error("Invalid configuration detected.\n"); } // Set up logging. initialize_log(gnb_cfg.log_cfg.filename); - register_app_logs(gnb_cfg.log_cfg, cu_cp_config.loggers, cu_up_config.loggers, *du_app_unit); + register_app_logs(gnb_cfg.log_cfg, *cu_cp_app_unit, cu_up_config.loggers, *du_app_unit); // Log input configuration. srslog::basic_logger& config_logger = srslog::fetch_basic_logger("CONFIG"); @@ -268,7 +264,7 @@ int main(int argc, char** argv) YAML::Node node; fill_gnb_appconfig_in_yaml_schema(node, gnb_cfg); fill_cu_up_config_in_yaml_schema(node, cu_up_config); - fill_cu_cp_config_in_yaml_schema(node, cu_cp_config); + cu_cp_app_unit->dump_config(node); du_app_unit->dump_config(node); config_logger.debug("Input configuration (all values): \n{}", YAML::Dump(node)); } else { @@ -321,7 +317,7 @@ int main(int argc, char** argv) // Instantiate worker manager. worker_manager_config worker_manager_cfg; fill_gnb_worker_manager_config(worker_manager_cfg, gnb_cfg); - fill_cu_cp_worker_manager_config(worker_manager_cfg, cu_cp_config); + cu_cp_app_unit->fill_worker_manager_config(worker_manager_cfg); fill_cu_up_worker_manager_config(worker_manager_cfg, cu_up_config); du_app_unit->fill_worker_manager_config(worker_manager_cfg); @@ -339,7 +335,8 @@ int main(int argc, char** argv) // We disable one accordingly. cu_up_config.pcap_cfg.disable_e1_pcaps(); du_app_unit->get_du_high_unit_config().pcaps.disable_f1_pcaps(); - cu_cp_dlt_pcaps cu_cp_dlt_pcaps = create_cu_cp_dlt_pcap(cu_cp_config.pcap_cfg, *workers.get_executor_getter()); + cu_cp_dlt_pcaps cu_cp_dlt_pcaps = + create_cu_cp_dlt_pcap(cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg, *workers.get_executor_getter()); cu_up_dlt_pcaps cu_up_dlt_pcaps = create_cu_up_dlt_pcaps(cu_up_config.pcap_cfg, *workers.get_executor_getter()); flexible_du_pcaps du_pcaps = create_du_pcaps(du_app_unit->get_du_high_unit_config().pcaps, workers); @@ -375,10 +372,13 @@ int main(int argc, char** argv) // Load CU-CP plugins if enabled std::optional ng_handover_plugin = - cu_cp_config.load_plugins ? dynlink_manager::create("libsrsran_plugin_ng_handover.so", gnb_logger) : std::nullopt; - std::optional mocn_plugin = - cu_cp_config.load_plugins ? dynlink_manager::create("libsrsran_plugin_mocn.so", gnb_logger) : std::nullopt; - if (cu_cp_config.load_plugins) { + cu_cp_app_unit->get_cu_cp_unit_config().load_plugins + ? dynlink_manager::create("libsrsran_plugin_ng_handover.so", gnb_logger) + : std::nullopt; + std::optional mocn_plugin = cu_cp_app_unit->get_cu_cp_unit_config().load_plugins + ? dynlink_manager::create("libsrsran_plugin_mocn.so", gnb_logger) + : std::nullopt; + if (cu_cp_app_unit->get_cu_cp_unit_config().load_plugins) { if (not ng_handover_plugin) { gnb_logger.error("Could not open NG Handover plugin"); return -1; @@ -388,7 +388,7 @@ int main(int argc, char** argv) gnb_logger.error("Could not open NG Handover function pointer"); return -1; } - cu_cp_config.start_ng_ho_func = ng_ho_func.value(); + cu_cp_app_unit->get_cu_cp_unit_config().start_ng_ho_func = ng_ho_func.value(); if (not mocn_plugin) { gnb_logger.error("Could not open MOCN plugin"); @@ -399,22 +399,25 @@ int main(int argc, char** argv) gnb_logger.error("Could not open MOCN function pointer"); return -1; } - cu_cp_config.connect_amfs_func_ptr = connect_amfs.value(); - expected disconnect_amfs = mocn_plugin->load_symbol("disconnect_amfs_func"); + cu_cp_app_unit->get_cu_cp_unit_config().connect_amfs_func_ptr = connect_amfs.value(); + expected disconnect_amfs = mocn_plugin->load_symbol("disconnect_amfs_func"); if (not disconnect_amfs) { gnb_logger.error("Could not open MOCN function pointer"); return -1; } - cu_cp_config.disconnect_amfs_func_ptr = disconnect_amfs.value(); + cu_cp_app_unit->get_cu_cp_unit_config().disconnect_amfs_func_ptr = disconnect_amfs.value(); } // Create N2 Client Gateways. - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( - cu_cp_config.amf_config.no_core, cu_cp_config.amf_config.amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); - - for (const auto& amf : cu_cp_config.extra_amfs) { - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client( - generate_n2_client_config(cu_cp_config.amf_config.no_core, amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); + cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client( + generate_n2_client_config(cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf, + *cu_cp_dlt_pcaps.ngap, + *epoll_broker))); + + for (const auto& amf : cu_cp_app_unit->get_cu_cp_unit_config().extra_amfs) { + cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); } // E2AP configuration. @@ -424,7 +427,7 @@ int main(int argc, char** argv) e2_gateway_remote_connector e2_gw{*epoll_broker, e2_du_nw_config, *du_pcaps.e2ap}; // create CU-CP. - auto cu_cp_obj_and_cmds = build_cu_cp(cu_cp_config, cu_cp_dependencies); + auto cu_cp_obj_and_cmds = cu_cp_app_unit->create_cu_cp(cu_cp_dependencies); srs_cu_cp::cu_cp& cu_cp_obj = *cu_cp_obj_and_cmds.unit; diff --git a/apps/units/cu_cp/cu_cp_application_unit.h b/apps/units/cu_cp/cu_cp_application_unit.h new file mode 100644 index 0000000000..e9ba8ea253 --- /dev/null +++ b/apps/units/cu_cp/cu_cp_application_unit.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "apps/units/application_unit.h" +#include "apps/units/cu_cp/cu_cp_builder.h" +#include + +namespace srsran { +struct worker_manager_config; + +/// CU-CP application unit interface. +class cu_cp_application_unit : public application_unit +{ +public: + virtual ~cu_cp_application_unit() = default; + + /// Creates a CU-CP unit with the given dependencies. + virtual cu_cp_unit create_cu_cp(cu_cp_build_dependencies& dependencies) = 0; + + /// Returns the CU-CP configuration of this CU-CP application unit. + virtual cu_cp_unit_config& get_cu_cp_unit_config() = 0; + virtual const cu_cp_unit_config& get_cu_cp_unit_config() const = 0; + + /// Dumps the CU-CP configuration into the given YAML node. + virtual void dump_config(YAML::Node& node) const = 0; + + /// Fills the given worker manager configuration with the CU-CP parameters. + virtual void fill_worker_manager_config(worker_manager_config& config) = 0; +}; + +/// Creates a CU-CP application unit. +std::unique_ptr create_cu_cp_application_unit(); + +} // namespace srsran diff --git a/apps/units/cu_cp/cu_cp_application_unit_impl.cpp b/apps/units/cu_cp/cu_cp_application_unit_impl.cpp index d8176ac142..c3bed2b40c 100644 --- a/apps/units/cu_cp/cu_cp_application_unit_impl.cpp +++ b/apps/units/cu_cp/cu_cp_application_unit_impl.cpp @@ -9,9 +9,12 @@ */ #include "cu_cp_application_unit_impl.h" +#include "cu_cp_builder.h" +#include "cu_cp_config_translators.h" #include "cu_cp_logger_registrator.h" #include "cu_cp_unit_config_cli11_schema.h" #include "cu_cp_unit_config_validator.h" +#include "cu_cp_unit_config_yaml_writer.h" using namespace srsran; @@ -20,6 +23,11 @@ void cu_cp_application_unit_impl::on_parsing_configuration_registration(CLI::App configure_cli11_with_cu_cp_unit_config_schema(app, unit_cfg); } +void cu_cp_application_unit_impl::on_configuration_parameters_autoderivation(CLI::App& app) +{ + autoderive_cu_cp_parameters_after_parsing(app, unit_cfg); +} + bool cu_cp_application_unit_impl::on_configuration_validation(const os_sched_affinity_bitmask& available_cpus) const { return validate_cu_cp_unit_config(unit_cfg); @@ -29,3 +37,23 @@ void cu_cp_application_unit_impl::on_loggers_registration() { register_cu_cp_loggers(unit_cfg.loggers); } + +cu_cp_unit cu_cp_application_unit_impl::create_cu_cp(cu_cp_build_dependencies& dependencies) +{ + return build_cu_cp(unit_cfg, dependencies); +} + +void cu_cp_application_unit_impl::dump_config(YAML::Node& node) const +{ + fill_cu_cp_config_in_yaml_schema(node, unit_cfg); +} + +void cu_cp_application_unit_impl::fill_worker_manager_config(worker_manager_config& config) +{ + fill_cu_cp_worker_manager_config(config, unit_cfg); +} + +std::unique_ptr srsran::create_cu_cp_application_unit() +{ + return std::make_unique(); +} diff --git a/apps/units/cu_cp/cu_cp_application_unit_impl.h b/apps/units/cu_cp/cu_cp_application_unit_impl.h index 876a9b9351..2bead19bc5 100644 --- a/apps/units/cu_cp/cu_cp_application_unit_impl.h +++ b/apps/units/cu_cp/cu_cp_application_unit_impl.h @@ -10,24 +10,40 @@ #pragma once -#include "../application_unit.h" -#include "cu_cp_unit_config.h" +#include "apps/units/cu_cp/cu_cp_application_unit.h" +#include "apps/units/cu_cp/cu_cp_unit_config.h" namespace srsran { /// CU-CP application unit implementation. -class cu_cp_application_unit_impl : public application_unit +class cu_cp_application_unit_impl : public cu_cp_application_unit { public: // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; + // See interface for documentation. + void on_configuration_parameters_autoderivation(CLI::App& app) override; + // See interface for documentation. bool on_configuration_validation(const os_sched_affinity_bitmask& available_cpus) const override; // See interface for documentation. void on_loggers_registration() override; + // See interface for documentation. + cu_cp_unit create_cu_cp(cu_cp_build_dependencies& dependencies) override; + + // See interface for documentation. + cu_cp_unit_config& get_cu_cp_unit_config() override { return unit_cfg; } + const cu_cp_unit_config& get_cu_cp_unit_config() const override { return unit_cfg; } + + // See interface for documentation. + void dump_config(YAML::Node& node) const override; + + // See interface for documentation. + void fill_worker_manager_config(worker_manager_config& config) override; + private: cu_cp_unit_config unit_cfg; }; diff --git a/apps/units/flexible_du/du_low/CMakeLists.txt b/apps/units/flexible_du/du_low/CMakeLists.txt index f11ddafa4e..f341d6193e 100644 --- a/apps/units/flexible_du/du_low/CMakeLists.txt +++ b/apps/units/flexible_du/du_low/CMakeLists.txt @@ -24,4 +24,5 @@ if (DPDK_FOUND) hal_hwacc_pdsch hal_bbdev_factory) endif (DPDK_FOUND) + target_link_libraries(srsran_du_low_unit_helpers PUBLIC ${DU_LOW_UNIT_HELPERS_LIBRARIES}) From b0c04df2a910154b074284735b04aca761d26cad Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sun, 29 Sep 2024 20:03:16 +0200 Subject: [PATCH 15/32] sched: fix slicing prioritization --- lib/scheduler/slicing/ran_slice_instance.cpp | 2 +- lib/scheduler/slicing/ran_slice_instance.h | 3 +- lib/scheduler/slicing/slice_scheduler.cpp | 14 +++--- .../slicing/slice_scheduler_test.cpp | 48 +++++++++++-------- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 6135ed2486..dde039ce72 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -38,7 +38,7 @@ void ran_slice_instance::slot_indication(slot_point slot_tx) last_pdsch_alloc_slot.clear(); } if (last_pusch_alloc_slot.valid() and slot_tx > last_pusch_alloc_slot + MAX_SLOTS_SINCE_LAST_PXSCH) { - last_pdsch_alloc_slot.clear(); + last_pusch_alloc_slot.clear(); } } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 0e1c92a742..23a8ee9ad3 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -23,7 +23,8 @@ namespace srsran { class ran_slice_instance { // Const for the max difference in number of slots between the current slot and the last allocation slot. - static constexpr unsigned MAX_SLOTS_SINCE_LAST_PXSCH = 512; + // This limit ensures lack of ambiguity in the slot point comparison + static constexpr unsigned MAX_SLOTS_SINCE_LAST_PXSCH = 256; public: ran_slice_instance(ran_slice_id_t id_, const cell_configuration& cell_cfg_, const slice_rrm_policy_config& cfg_); diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 7de1430f88..fca0174059 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -314,7 +314,8 @@ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_pri // Priority when slice still needs to reach its minimum RB ratio agreement. static constexpr priority_type high_prio = 0x2U; static constexpr priority_type slice_prio_bitsize = 4U; - static constexpr priority_type delay_bitsize = 8U; + static constexpr priority_type delay_prio_bitsize = 8U; + static constexpr priority_type delay_prio_bitmask = (1U << delay_prio_bitsize) - 1U; static constexpr priority_type rr_bitsize = 8U; unsigned rb_count = is_dl ? inst.pdsch_rb_count : inst.nof_pusch_rbs_allocated(pxsch_slot); @@ -324,7 +325,7 @@ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_pri } // Prioritize closer slots over slots further away into the future. This is relevant for UL-heavy cases. - unsigned slot_dist = 0xfU - ((pxsch_slot - pdcch_slot) & 0xfU); + unsigned slot_dist = 0xfU - std::min(static_cast(pxsch_slot - pdcch_slot), 0xfU); // In case minRB > 0 and minimum RB ratio agreement is not yet reached, we give it a higher priority. priority_type slice_prio = @@ -333,12 +334,11 @@ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_pri // Increase priorities of slices that have not been scheduled for a long time. priority_type delay_prio = is_dl ? inst.nof_slots_since_last_pdsch(pxsch_slot) : inst.nof_slots_since_last_pusch(pxsch_slot); - delay_prio = delay_prio & ((1U << delay_bitsize) - 1U); + delay_prio = std::min(delay_prio, delay_prio_bitmask); // Round-robin across slices with the same slice and delay priorities. - priority_type rr_prio = (current_slot_count % nof_slices) == inst.id.value() ? 1 : 0; - rr_prio = rr_prio & ((1U << rr_bitsize) - 1U); + priority_type rr_prio = ((inst.id.value() + current_slot_count) % nof_slices) & ((1U << rr_bitsize) - 1U); - return (slot_dist << (delay_bitsize + rr_bitsize + slice_prio_bitsize)) + - (slice_prio << (delay_bitsize + rr_bitsize)) + (delay_prio << rr_bitsize) + rr_prio; + return (slot_dist << (delay_prio_bitsize + rr_bitsize + slice_prio_bitsize)) + + (slice_prio << (delay_prio_bitsize + rr_bitsize)) + (delay_prio << rr_bitsize) + rr_prio; } diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index f1f9bfef1d..a97f3b7130 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -300,9 +300,10 @@ TEST_F(rb_ratio_slice_scheduler_test, when_slice_with_min_rb_has_ues_then_it_is_ // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); - - next_dl_slice = slice_sched.get_next_dl_candidate(); + // Default SRB slice has very high priority. We ignore it as candidate for this test. + if (next_dl_slice->id() == default_srb_slice_id) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + } ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_MIN_DRB)); } @@ -312,13 +313,12 @@ TEST_F(rb_ratio_slice_scheduler_test, when_slice_rb_ratios_are_min_bounded_then_ ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); run_slot(); - // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); - - next_dl_slice = slice_sched.get_next_dl_candidate(); + // Default SRB slice has very high priority. We ignore it as candidate for this test. + if (next_dl_slice->id() == default_srb_slice_id) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + } ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); - ASSERT_EQ(next_dl_slice->remaining_rbs(), MIN_SLICE_RB); } @@ -328,17 +328,21 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); run_slot(); - // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); + // Default SRB slice has very high priority. We ignore it as candidate for this test. + if (next_dl_slice->id() == default_srb_slice_id) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + } - next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); next_dl_slice->store_grant(MIN_SLICE_RB - 1); // we leave one RB empty (MIN_SLICE_RB - 1). ASSERT_EQ(next_dl_slice->remaining_rbs(), 1); // No more slices to schedule. next_dl_slice = slice_sched.get_next_dl_candidate(); + if (next_dl_slice->id() == default_srb_slice_id) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + } ASSERT_FALSE(next_dl_slice.has_value()); } @@ -350,14 +354,19 @@ TEST_F(rb_ratio_slice_scheduler_test, // Default SRB slice has very high priority. auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); + // Default SRB slice has very high priority. We ignore it as candidate for this test. + if (next_dl_slice->id() == default_srb_slice_id) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + } - next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); next_dl_slice->store_grant(MIN_SLICE_RB); ASSERT_EQ(next_dl_slice->remaining_rbs(), 0); next_dl_slice = slice_sched.get_next_dl_candidate(); + if (next_dl_slice->id() == default_srb_slice_id) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + } // Original slice is selected again, now using maxRB ratio as the remaining RBs. ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_SLICE_RB - MIN_SLICE_RB); @@ -373,26 +382,27 @@ TEST_F(rb_ratio_slice_scheduler_test, ASSERT_NE(this->add_ue(to_du_ue_index(0)), nullptr); run_slot(); - // Default SRB slice has very high priority. + // High priority slices auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); - - next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); next_dl_slice->store_grant(MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); + + // Lower priority candidates. + next_dl_slice = slice_sched.get_next_dl_candidate(); next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_FALSE(next_dl_slice.has_value()); // New slot and priorities are reestablished. run_slot(); next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); + next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); ASSERT_EQ(next_dl_slice->remaining_rbs(), MIN_SLICE_RB); next_dl_slice->store_grant(MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); - next_dl_slice = slice_sched.get_next_dl_candidate(); ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); ASSERT_EQ(next_dl_slice->remaining_rbs(), MAX_SLICE_RB - MIN_SLICE_RB); next_dl_slice = slice_sched.get_next_dl_candidate(); From 12c87ae57f5a5bfa19f3c195b03c0efd563770ab Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sun, 29 Sep 2024 20:51:48 +0200 Subject: [PATCH 16/32] sched: fix dangling pointer to expert config and skip round-robin algorithm if there are no UEs with newTx data --- lib/scheduler/policy/scheduler_time_rr.cpp | 8 +++++--- lib/scheduler/policy/scheduler_time_rr.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index a2b37ea74e..ecc67a29c4 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -53,6 +53,9 @@ static unsigned get_max_ues_to_be_sched(const slice_ue_repository& ues, bool is_ } } } + if (nof_ue_with_new_tx == 0) { + return 0; + } return scheduler_alloc_limits_lookup[lookup_idx].nof_ues_to_be_scheduled_per_slot; } @@ -69,12 +72,11 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& const scheduler_ue_expert_config& expert_cfg, unsigned slice_max_rbs) { - if (ues.empty()) { + unsigned nof_ues_to_be_scheduled_per_slot = get_max_ues_to_be_sched(ues, is_dl); + if (nof_ues_to_be_scheduled_per_slot == 0) { return 0; } - unsigned nof_ues_to_be_scheduled_per_slot = get_max_ues_to_be_sched(ues, is_dl); - // > Apply limits if passed to scheduler. if (is_dl) { nof_ues_to_be_scheduled_per_slot = std::min(expert_cfg.max_pdschs_per_slot, nof_ues_to_be_scheduled_per_slot); diff --git a/lib/scheduler/policy/scheduler_time_rr.h b/lib/scheduler/policy/scheduler_time_rr.h index ca177a59cb..a887d686da 100644 --- a/lib/scheduler/policy/scheduler_time_rr.h +++ b/lib/scheduler/policy/scheduler_time_rr.h @@ -32,7 +32,7 @@ class scheduler_time_rr : public scheduler_policy srslog::basic_logger& logger; du_ue_index_t next_dl_ue_index, next_ul_ue_index; - const scheduler_ue_expert_config& expert_cfg; + const scheduler_ue_expert_config expert_cfg; }; } // namespace srsran From 3f435d4493901c71ae3eec8c24148f2a3e6adfd8 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 30 Sep 2024 13:25:15 +0200 Subject: [PATCH 17/32] ci,e2e: android allowed to fail --- .gitlab/ci/e2e.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index aa887c2f26..6215f3f9b3 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -564,6 +564,7 @@ android b200: - job: "basic relwithdeb" artifacts: true - *retina-needs + allow_failure: true android IMS: stage: rf @@ -580,6 +581,7 @@ android IMS: - job: "basic relwithdeb" artifacts: true - *retina-needs + allow_failure: true android x300: stage: rf @@ -595,6 +597,7 @@ android x300: - job: "basic relwithdeb" artifacts: true - *retina-needs + allow_failure: true ################################################################################ # VIAVI From d7bc1852688a87af5a9b0ec997a1989f1bc8c950 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 30 Sep 2024 13:26:06 +0200 Subject: [PATCH 18/32] ci: avoid multi project pipelines to inherit variables --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61aec530d4..c2879c7424 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -110,6 +110,8 @@ helm: variables: CI_DESCRIPTION: Synchronization with srsGNB NOTIFY_SLACK: "true" + inherit: + variables: false trigger: project: softwareradiosystems/ci/srsgnb_k8s branch: main @@ -125,6 +127,8 @@ enterprise: CI_DESCRIPTION: Nightly SRSRAN_COMMIT: $CI_COMMIT_SHA NOTIFY_SLACK: "true" + inherit: + variables: false trigger: project: softwareradiosystems/srsran_5g_enterprise branch: main From 3b0bafbe88b23835a40f7081c6ba2f828f76db1b Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 30 Sep 2024 16:44:14 +0200 Subject: [PATCH 19/32] ci,viavi: adjust viavi test parameters --- tests/e2e/tests/viavi/test_declaration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index d488174d7d..f153a73f72 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -147,8 +147,8 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 3 - warning_as_errors: true + expected_nof_kos: 9999999999999 + warning_as_errors: false - campaign_filename: *campaign_filename test_name: "1UE birth-death UDP bidirectional" From 5a7a94345a3a35cc73c0c85ca698a5430844d5b0 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 26 Sep 2024 18:16:38 +0200 Subject: [PATCH 20/32] units: added the CU-UP application unit. Updated gNB and CU applications to use it --- apps/cu/CMakeLists.txt | 1 - apps/cu/cu.cpp | 139 +++++-------- apps/cu/cu_worker_manager.cpp | 195 ------------------ apps/cu/cu_worker_manager.h | 99 --------- apps/gnb/gnb.cpp | 113 +++++----- apps/services/worker_manager.cpp | 23 ++- apps/services/worker_manager_config.h | 6 +- apps/units/cu_up/cu_up_application_unit.h | 44 ++++ .../cu_up/cu_up_application_unit_impl.cpp | 24 +++ .../units/cu_up/cu_up_application_unit_impl.h | 20 +- apps/units/cu_up/cu_up_builder.cpp | 34 +-- apps/units/cu_up/cu_up_builder.h | 19 +- .../cu_up/cu_up_unit_config_cli11_schema.cpp | 11 - .../cu_up/cu_up_unit_config_cli11_schema.h | 3 - .../du_high/du_high_config_translators.cpp | 2 +- include/srsran/f1u/cu_up/f1u_gateway.h | 2 + .../f1u_split_connector_factory.h | 4 +- .../f1u/local_connector/f1u_local_connector.h | 2 + .../split_connector/f1u_split_connector.cpp | 23 ++- .../split_connector/f1u_split_connector.h | 8 +- tests/unittests/cu_up/cu_up_test_helpers.h | 2 + .../common/f1u_cu_split_connector_test.cpp | 2 +- 22 files changed, 269 insertions(+), 507 deletions(-) delete mode 100644 apps/cu/cu_worker_manager.cpp delete mode 100644 apps/cu/cu_worker_manager.h create mode 100644 apps/units/cu_up/cu_up_application_unit.h diff --git a/apps/cu/CMakeLists.txt b/apps/cu/CMakeLists.txt index 6c0634b040..8058b06d53 100644 --- a/apps/cu/CMakeLists.txt +++ b/apps/cu/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable(srscu cu_appconfig_cli11_schema.cpp cu_appconfig_validator.cpp cu_appconfig_yaml_writer.cpp - cu_worker_manager.cpp ) install(TARGETS srscu diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 33e90c4aaa..94d2164c41 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -30,37 +30,32 @@ #include "srsran/support/versioning/version.h" #include "apps/cu/cu_appconfig_cli11_schema.h" -#include "apps/cu/cu_worker_manager.h" #include "apps/units/cu_cp/cu_cp_application_unit.h" #include "apps/units/cu_cp/cu_cp_config_translators.h" #include "apps/units/cu_cp/cu_cp_unit_config.h" #include "apps/units/cu_cp/pcap_factory.h" -#include "apps/units/cu_up/cu_up_builder.h" -#include "apps/units/cu_up/cu_up_logger_registrator.h" +#include "apps/units/cu_up/cu_up_application_unit.h" #include "apps/units/cu_up/cu_up_unit_config.h" -#include "apps/units/cu_up/cu_up_unit_config_cli11_schema.h" -#include "apps/units/cu_up/cu_up_unit_config_translators.h" -#include "apps/units/cu_up/cu_up_unit_config_validator.h" -#include "apps/units/cu_up/cu_up_unit_config_yaml_writer.h" -#include "apps/units/cu_up/cu_up_wrapper.h" #include "apps/units/cu_up/pcap_factory.h" #include "srsran/cu_up/cu_up.h" -#include "srsran/cu_up/cu_up_factory.h" // TODO remove apps/gnb/*.h #include "apps/gnb/adapters/e2_gateway_remote_connector.h" #include "apps/gnb/gnb_appconfig_translators.h" -#include "srsran/e1ap/gateways/e1_local_connector_factory.h" -#include "srsran/ngap/gateways/n2_connection_client_factory.h" #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" #include "apps/services/stdin_command_dispatcher.h" +#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager_config.h" #include "cu_appconfig.h" #include "cu_appconfig_validator.h" #include "cu_appconfig_yaml_writer.h" +#include "srsran/e1ap/gateways/e1_local_connector_factory.h" +#include "srsran/ngap/gateways/n2_connection_client_factory.h" + #include #include @@ -118,9 +113,9 @@ static void initialize_log(const std::string& filename) srslog::init(); } -static void register_app_logs(const logger_appconfig& log_cfg, - cu_cp_application_unit& cu_cp_app_unit, - const cu_up_unit_logger_config& cu_up_loggers) +static void register_app_logs(const logger_appconfig& log_cfg, + cu_cp_application_unit& cu_cp_app_unit, + cu_up_application_unit& cu_up_app_unit) { // Set log-level of app and all non-layer specific components to app level. for (const auto& id : {"ALL", "SCTP-GW", "IO-EPOLL", "UDP-GW", "PCAP"}) { @@ -145,19 +140,23 @@ static void register_app_logs(const logger_appconfig& log_cfg, // Register units logs. cu_cp_app_unit.on_loggers_registration(); - register_cu_up_loggers(cu_up_loggers); + cu_up_app_unit.on_loggers_registration(); } -// Temporary helper to create CU-UP. -// TODO remove -std::unique_ptr app_build_cu_up(const cu_up_unit_config& unit_cfg, - cu_worker_manager& workers, - const std::string& f1u_bind_addr, - srs_cu_up::e1_connection_client& e1_conn_client, - f1u_cu_up_gateway& f1u_gateway, - dlt_pcap& gtpu_pcap, - timer_manager& timers, - io_broker& io_brk); +static void fill_cu_worker_manager_config(worker_manager_config& config, const cu_appconfig& unit_cfg) +{ + config.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; + config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; +} + +static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_cfg, const cu_cp_unit_config& cu_cp_cfg) +{ + // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. + if (cu_up_cfg.upf_cfg.bind_addr == "auto") { + cu_up_cfg.upf_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; + } + cu_up_cfg.upf_cfg.no_core = cu_cp_cfg.amf_config.no_core; +} int main(int argc, char** argv) { @@ -189,17 +188,16 @@ int main(int argc, char** argv) cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg.set_default_filename("/tmp/cu"); cu_cp_app_unit->on_parsing_configuration_registration(app); - cu_up_unit_config cu_up_config; - cu_up_config.pcap_cfg.set_default_filename("/tmp/cu"); - configure_cli11_with_cu_up_unit_config_schema(app, cu_up_config); + auto cu_up_app_unit = create_cu_up_application_unit(); + cu_up_app_unit->get_cu_up_unit_config().pcap_cfg.set_default_filename("/tmp/cu"); + cu_up_app_unit->on_parsing_configuration_registration(app); // Set the callback for the app calling all the autoderivation functions. - app.callback([&app, &cu_cp_app_unit, &cu_up_config]() { + app.callback([&app, &cu_cp_app_unit, &cu_up_app_unit]() { cu_cp_app_unit->on_configuration_parameters_autoderivation(app); - autoderive_cu_up_parameters_after_parsing(cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf.bind_addr, - cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, - cu_up_config); + autoderive_cu_up_parameters_after_parsing(cu_up_app_unit->get_cu_up_unit_config(), + cu_cp_app_unit->get_cu_cp_unit_config()); }); // Parse arguments. @@ -208,21 +206,21 @@ int main(int argc, char** argv) // Check the modified configuration. if (!validate_cu_appconfig(cu_cfg) || !cu_cp_app_unit->on_configuration_validation(os_sched_affinity_bitmask::available_cpus()) || - !validate_cu_up_unit_config(cu_up_config)) { + !cu_up_app_unit->on_configuration_validation(os_sched_affinity_bitmask::available_cpus())) { report_error("Invalid configuration detected.\n"); } // Set up logging. initialize_log(cu_cfg.log_cfg.filename); - register_app_logs(cu_cfg.log_cfg, *cu_cp_app_unit, cu_up_config.loggers); + register_app_logs(cu_cfg.log_cfg, *cu_cp_app_unit, *cu_up_app_unit); // Log input configuration. srslog::basic_logger& config_logger = srslog::fetch_basic_logger("CONFIG"); if (config_logger.debug.enabled()) { YAML::Node node; fill_cu_appconfig_in_yaml_schema(node, cu_cfg); - fill_cu_up_config_in_yaml_schema(node, cu_up_config); cu_cp_app_unit->dump_config(node); + cu_up_app_unit->dump_config(node); config_logger.debug("Input configuration (all values): \n{}", YAML::Dump(node)); } else { config_logger.info("Input configuration (only non-default values): \n{}", app.config_to_str(false, false)); @@ -259,13 +257,17 @@ int main(int argc, char** argv) check_drm_kms_polling(cu_logger); // Create worker manager. - cu_worker_manager workers{ - cu_cfg, cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg, cu_up_config.pcap_cfg, cu_up_config.gtpu_queue_size}; + worker_manager_config worker_manager_cfg; + fill_cu_worker_manager_config(worker_manager_cfg, cu_cfg); + cu_cp_app_unit->fill_worker_manager_config(worker_manager_cfg); + cu_up_app_unit->fill_worker_manager_config(worker_manager_cfg); + worker_manager workers{worker_manager_cfg}; // Create layer specific PCAPs. cu_cp_dlt_pcaps cu_cp_dlt_pcaps = create_cu_cp_dlt_pcap(cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg, *workers.get_executor_getter()); - cu_up_dlt_pcaps cu_up_dlt_pcaps = create_cu_up_dlt_pcaps(cu_up_config.pcap_cfg, *workers.get_executor_getter()); + cu_up_dlt_pcaps cu_up_dlt_pcaps = + create_cu_up_dlt_pcaps(cu_up_app_unit->get_cu_up_unit_config().pcap_cfg, *workers.get_executor_getter()); // Create IO broker. const auto& low_prio_cpu_mask = cu_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg.mask; @@ -294,7 +296,7 @@ int main(int argc, char** argv) std::unique_ptr cu_f1u_gw = srs_cu_up::create_udp_ngu_gateway(cu_f1u_gw_config, *epoll_broker, *workers.cu_up_io_ul_exec); std::unique_ptr cu_f1u_conn = - srs_cu_up::create_split_f1u_gw({cu_f1u_gw.get(), cu_f1u_gtpu_demux.get(), *cu_up_dlt_pcaps.f1u, GTPU_PORT}); + srs_cu_up::create_split_f1u_gw({*cu_f1u_gw, *cu_f1u_gtpu_demux, *cu_up_dlt_pcaps.f1u, GTPU_PORT}); // Create E1AP local connector std::unique_ptr e1_gw = @@ -350,14 +352,15 @@ int main(int argc, char** argv) cu_f1c_gw->attach_cu_cp(cu_cp_obj.get_f1c_handler()); // Create and start CU-UP - std::unique_ptr cu_up_obj = app_build_cu_up(cu_up_config, - workers, - cu_cfg.nru_cfg.bind_addr, - *e1_gw, - *cu_f1u_conn, - *cu_up_dlt_pcaps.n3, - *cu_timers, - *epoll_broker); + cu_up_unit_dependencies cu_up_unit_deps; + cu_up_unit_deps.workers = &workers; + cu_up_unit_deps.e1ap_conn_client = e1_gw.get(); + cu_up_unit_deps.f1u_gateway = cu_f1u_conn.get(); + cu_up_unit_deps.gtpu_pcap = cu_up_dlt_pcaps.n3.get(); + cu_up_unit_deps.timers = cu_timers; + cu_up_unit_deps.io_brk = epoll_broker.get(); + + std::unique_ptr cu_up_obj = cu_up_app_unit->create_cu_up_unit(cu_up_unit_deps); cu_up_obj->start(); { @@ -389,45 +392,3 @@ int main(int argc, char** argv) return 0; } - -// Temporary helper to create CU-UP. -// TODO remove -std::unique_ptr app_build_cu_up(const cu_up_unit_config& unit_cfg, - cu_worker_manager& workers, - const std::string& f1u_bind_address, - srs_cu_up::e1_connection_client& e1_conn_client, - f1u_cu_up_gateway& f1u_gateway, - dlt_pcap& gtpu_pcap, - timer_manager& timers, - io_broker& io_brk) -{ - srs_cu_up::cu_up_configuration config = generate_cu_up_config(unit_cfg); - config.ctrl_executor = workers.cu_up_ctrl_exec; - config.cu_up_e2_exec = workers.cu_up_e2_exec; - config.ue_exec_pool = workers.cu_up_exec_mapper.get(); - config.io_ul_executor = workers.cu_up_io_ul_exec; // Optionally select separate exec for UL IO - config.e1ap.e1_conn_client = &e1_conn_client; - config.f1u_gateway = &f1u_gateway; - config.gtpu_pcap = >pu_pcap; - config.timers = &timers; - config.qos = generate_cu_up_qos_config(unit_cfg); - - config.net_cfg.f1u_bind_addr = f1u_bind_address; // TODO remove this parameter and make sure that the CU-UP gets the - // bind address directly from the gateway. - - // Create NG-U gateway. - std::unique_ptr ngu_gw; - if (not unit_cfg.upf_cfg.no_core) { - udp_network_gateway_config ngu_gw_config = {}; - ngu_gw_config.bind_address = config.net_cfg.n3_bind_addr; - ngu_gw_config.bind_port = config.net_cfg.n3_bind_port; - ngu_gw_config.bind_interface = config.net_cfg.n3_bind_interface; - ngu_gw_config.rx_max_mmsg = config.net_cfg.n3_rx_max_mmsg; - ngu_gw = srs_cu_up::create_udp_ngu_gateway(ngu_gw_config, io_brk, *workers.cu_up_io_ul_exec); - } else { - ngu_gw = srs_cu_up::create_no_core_ngu_gateway(); - } - config.ngu_gw = ngu_gw.get(); - - return std::make_unique(std::move(ngu_gw), create_cu_up(config)); -} diff --git a/apps/cu/cu_worker_manager.cpp b/apps/cu/cu_worker_manager.cpp deleted file mode 100644 index 099548355a..0000000000 --- a/apps/cu/cu_worker_manager.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "cu_worker_manager.h" -#include "srsran/support/event_tracing.h" - -using namespace srsran; - -static const uint32_t task_worker_queue_size = 2048; - -cu_worker_manager::cu_worker_manager(const cu_appconfig& appcfg, - cu_cp_unit_pcap_config cu_cp_pcap_cfg, - cu_up_unit_pcap_config cu_up_pcap_cfg, - unsigned gtpu_queue_size) : - low_prio_affinity_mng({appcfg.expert_execution_cfg.affinities.low_priority_cpu_cfg}) -{ - create_low_prio_executors(appcfg, cu_cp_pcap_cfg, cu_up_pcap_cfg, gtpu_queue_size); - associate_low_prio_executors(); -} - -void cu_worker_manager::stop() -{ - exec_mng.stop(); -} - -void cu_worker_manager::create_worker_pool(const std::string& name, - unsigned nof_workers, - unsigned queue_size, - const std::vector& execs, - os_thread_realtime_priority prio, - span cpu_masks) -{ - using namespace execution_config_helper; - - concurrent_queue_policy queue_policy = concurrent_queue_policy::locking_mpmc; - - const worker_pool pool{name, - nof_workers, - {{queue_policy, queue_size}}, - execs, - std::chrono::microseconds{queue_policy == concurrent_queue_policy::locking_mpmc ? 0 : 10}, - prio, - std::vector{cpu_masks.begin(), cpu_masks.end()}}; - if (not exec_mng.add_execution_context(create_execution_context(pool))) { - report_fatal_error("Failed to instantiate {} execution context", pool.name); - } -} - -void cu_worker_manager::create_prio_worker(const std::string& name, - unsigned queue_size, - const std::vector& execs, - const os_sched_affinity_bitmask& mask, - os_thread_realtime_priority prio) -{ - using namespace execution_config_helper; - - const single_worker worker_desc{ - name, {concurrent_queue_policy::locking_mpsc, queue_size}, execs, std::nullopt, prio, mask}; - if (not exec_mng.add_execution_context(create_execution_context(worker_desc))) { - report_fatal_error("Failed to instantiate {} execution context", worker_desc.name); - } -} - -void append_pcap_strands(std::vector& strand_list, - const cu_cp_unit_pcap_config& cp_pcaps, - const cu_up_unit_pcap_config& up_pcaps) -{ - using namespace execution_config_helper; - - // Default configuration for each pcap writer strand. - strand base_strand_cfg{{{"pcap_exec", concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}}; - - // These layers have very low throughput, so no point in instantiating more than one strand. - // This means that there is no parallelization in pcap writing across these layers. - if (cp_pcaps.f1ap.enabled or cp_pcaps.ngap.enabled or cp_pcaps.e1ap.enabled) { - strand_list.emplace_back(base_strand_cfg); - } - - if (up_pcaps.n3.enabled) { - base_strand_cfg.queues[0].name = "n3_pcap_exec"; - strand_list.emplace_back(base_strand_cfg); - } - - if (up_pcaps.f1u.enabled) { - base_strand_cfg.queues[0].name = "f1u_pcap_exec"; - strand_list.emplace_back(base_strand_cfg); - } -} - -execution_config_helper::worker_pool cu_worker_manager::create_low_prio_workers(const cu_appconfig& appcfg) -{ - using namespace execution_config_helper; - - // Configure non-RT worker pool. - worker_pool non_rt_pool{ - "non_rt_pool", - appcfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads, - {{concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}, // two task priority levels. - {concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}, - // Left empty, is filled later. - {}, - std::chrono::microseconds{100}, - os_thread_realtime_priority::no_realtime(), - std::vector{appcfg.expert_execution_cfg.affinities.low_priority_cpu_cfg.mask}}; - - return non_rt_pool; -} - -void cu_worker_manager::create_low_prio_executors(const cu_appconfig& appcfg, - const cu_cp_unit_pcap_config& cu_cp_pcap_cfg, - const cu_up_unit_pcap_config& cu_up_pcap_cfg, - unsigned gtpu_queue_size) -{ - using namespace execution_config_helper; - // TODO: split executor creation and association to workers - worker_pool non_rt_pool = create_low_prio_workers(appcfg); - - // Associate executors to the worker pool. - // Used for PCAP writing. - non_rt_pool.executors.emplace_back("low_prio_exec", task_priority::max - 1); - // Used for control plane and timer management. - non_rt_pool.executors.emplace_back("high_prio_exec", task_priority::max); - // Used to serialize all CU-UP tasks, while CU-UP does not support multithreading. - non_rt_pool.executors.push_back({"cu_up_strand", - task_priority::max - 1, - {}, // define CU-UP strands below. - task_worker_queue_size}); - - std::vector& low_prio_strands = non_rt_pool.executors[0].strands; - std::vector& high_prio_strands = non_rt_pool.executors[1].strands; - std::vector& cu_up_strands = non_rt_pool.executors[2].strands; - - // Configuration of strands for PCAP writing. These strands will use the low priority executor. - append_pcap_strands(low_prio_strands, cu_cp_pcap_cfg, cu_up_pcap_cfg); - - // Configuration of strand for the control plane handling (CU-CP and DU-high control plane). This strand will - // support two priority levels, the highest being for timer management. - strand cp_strand{{{"timer_exec", concurrent_queue_policy::lockfree_spsc, task_worker_queue_size}, - {"ctrl_exec", concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}}; - high_prio_strands.push_back(cp_strand); - - // Configuration of strands for user plane handling (CU-UP and DU-low user plane). Given that the CU-UP doesn't - // currently support multithreading, these strands will point to a strand that interfaces with the non-RT thread pool. - // Each UE strand will have three queues, one for timer management and configuration, one for DL data plane and one - // for UL data plane. - cu_up_strands.push_back( - strand{{{"cu_up_ctrl_exec", concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}, - {"cu_up_io_ul_exec", concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}}); - for (unsigned i = 0; i != nof_cu_up_ue_strands; ++i) { - cu_up_strands.push_back( - strand{{{fmt::format("ue_up_ctrl_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}, - {fmt::format("ue_up_ul_exec#{}", i), - concurrent_queue_policy::lockfree_mpmc, - gtpu_queue_size}, // TODO: Consider separate param for size of UL queue if needed. - {fmt::format("ue_up_dl_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, gtpu_queue_size}}}); - } - - // Create non-RT worker pool. - if (not exec_mng.add_execution_context(create_execution_context(non_rt_pool))) { - report_fatal_error("Failed to instantiate {} execution context", non_rt_pool.name); - } -} - -void cu_worker_manager::associate_low_prio_executors() -{ - using namespace execution_config_helper; - const auto& exec_map = exec_mng.executors(); - - // Update executor pointer mapping - cu_cp_exec = exec_map.at("ctrl_exec"); - cu_cp_e2_exec = exec_map.at("ctrl_exec"); - metrics_hub_exec = exec_map.at("ctrl_exec"); - cu_up_ctrl_exec = exec_map.at("cu_up_ctrl_exec"); - cu_up_io_ul_exec = exec_map.at("cu_up_io_ul_exec"); - cu_up_e2_exec = exec_map.at("cu_up_ctrl_exec"); - - // Create CU-UP execution mapper object. - std::vector ue_up_dl_execs(nof_cu_up_ue_strands, nullptr); - std::vector ue_up_ul_execs(nof_cu_up_ue_strands, nullptr); - std::vector ue_up_ctrl_execs(nof_cu_up_ue_strands, nullptr); - for (unsigned i = 0; i != nof_cu_up_ue_strands; ++i) { - ue_up_dl_execs[i] = exec_map.at(fmt::format("ue_up_dl_exec#{}", i)); - ue_up_ul_execs[i] = exec_map.at(fmt::format("ue_up_ul_exec#{}", i)); - ue_up_ctrl_execs[i] = exec_map.at(fmt::format("ue_up_ctrl_exec#{}", i)); - } - cu_up_exec_mapper = srs_cu_up::make_cu_up_executor_pool( - *exec_map.at("cu_up_ctrl_exec"), ue_up_dl_execs, ue_up_ul_execs, ue_up_ctrl_execs, *exec_map.at("low_prio_exec")); -} diff --git a/apps/cu/cu_worker_manager.h b/apps/cu/cu_worker_manager.h deleted file mode 100644 index 3b79a55ef3..0000000000 --- a/apps/cu/cu_worker_manager.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "apps/services/os_sched_affinity_manager.h" -#include "apps/services/worker_manager_worker_getter.h" -#include "apps/units/cu_cp/cu_cp_unit_pcap_config.h" -#include "apps/units/cu_up/cu_up_unit_pcap_config.h" -#include "cu_appconfig.h" -#include "srsran/cu_up/cu_up_executor_pool.h" -#include "srsran/support/executors/task_execution_manager.h" -#include "srsran/support/executors/task_executor.h" - -namespace srsran { - -/// Manages the workers of the app. -struct cu_worker_manager : public worker_manager_executor_getter { - cu_worker_manager(const cu_appconfig& appcfg, - cu_cp_unit_pcap_config cu_cp_pcap_cfg, - cu_up_unit_pcap_config cu_up_pcap_cfg, - unsigned gtpu_queue_size); - - void stop(); - - /// cu-cp ctrl exec points to general ctrl_worker - /// cu-up ue exec points to the general ue_worker - /// - /// The handler side is responsible for executor dispatching: - /// - ngap::handle_message calls cu-cp ctrl exec - /// - f1ap_cu::handle_message calls cu-cp ctrl exec - /// - e1ap_cu_cp::handle_message calls cu-cp ctrl exec - /// - e1ap_cu_up::handle_message calls cu-up ue exec - - task_executor* cu_cp_exec = nullptr; - task_executor* cu_up_ctrl_exec = nullptr; ///< CU-UP executor for control - task_executor* cu_up_io_ul_exec = nullptr; ///< CU-UP executor for UL socket transmission - task_executor* cu_cp_e2_exec = nullptr; - task_executor* cu_up_e2_exec = nullptr; - task_executor* metrics_hub_exec = nullptr; - - std::unique_ptr cu_up_exec_mapper; - - // Gets the DU-low downlink executors. - void get_du_low_dl_executors(std::vector& executors, unsigned sector_id) const; - - /// Get executor based on the name. - task_executor* find_executor(const std::string& name) const - { - auto it = exec_mng.executors().find(name); - return it != exec_mng.executors().end() ? it->second : nullptr; - } - - task_executor& get_executor(const std::string& name) const override { return *exec_mng.executors().at(name); } - - worker_manager_executor_getter* get_executor_getter() { return this; } - -private: - static const unsigned nof_cu_up_ue_strands = 16; - - /// Manager of execution contexts and respective executors instantiated by the application. - task_execution_manager exec_mng; - - os_sched_affinity_manager low_prio_affinity_mng; - - /// CPU affinity bitmask manager per cell. - std::vector affinity_mng; - - /// Helper method to create workers with non zero priority. - void create_prio_worker(const std::string& name, - unsigned queue_size, - const std::vector& execs, - const os_sched_affinity_bitmask& mask, - os_thread_realtime_priority prio = os_thread_realtime_priority::no_realtime()); - - /// Helper method to create worker pool. - void create_worker_pool(const std::string& name, - unsigned nof_workers, - unsigned queue_size, - const std::vector& execs, - os_thread_realtime_priority prio = os_thread_realtime_priority::no_realtime(), - span cpu_masks = {}); - - execution_config_helper::worker_pool create_low_prio_workers(const cu_appconfig& appcfg); - void create_low_prio_executors(const cu_appconfig& appcfg, - const cu_cp_unit_pcap_config& cu_cp_pcap_cfg, - const cu_up_unit_pcap_config& cu_up_pcap_cfg, - unsigned gtpu_queue_size); - void associate_low_prio_executors(); -}; - -} // namespace srsran diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 69ebcd4292..f35b93494c 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -8,23 +8,22 @@ * */ +#include "srsran/support/backtrace.h" +#include "srsran/support/config_parsers.h" #include "srsran/support/cpu_features.h" #include "srsran/support/dynlink_manager.h" #include "srsran/support/event_tracing.h" +#include "srsran/support/io/io_broker_factory.h" #include "srsran/support/signal_handling.h" #include "srsran/support/versioning/build_info.h" #include "srsran/support/versioning/version.h" -#include "srsran/f1u/local_connector/f1u_local_connector.h" - -#include "srsran/ngap/gateways/n2_connection_client_factory.h" -#include "srsran/support/io/io_broker_factory.h" - +#include "srsran/du/du_power_controller.h" #include "srsran/e1ap/gateways/e1_local_connector_factory.h" #include "srsran/f1ap/gateways/f1c_local_connector_factory.h" +#include "srsran/f1u/local_connector/f1u_local_connector.h" #include "srsran/gtpu/ngu_gateway.h" -#include "srsran/support/backtrace.h" -#include "srsran/support/config_parsers.h" +#include "srsran/ngap/gateways/n2_connection_client_factory.h" #include "gnb_appconfig.h" #include "gnb_appconfig_cli11_schema.h" @@ -32,44 +31,34 @@ #include "gnb_appconfig_validators.h" #include "gnb_appconfig_yaml_writer.h" -#include "apps/services/worker_manager.h" - +#include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" +#include "apps/services/buffer_pool/buffer_pool_manager.h" +#include "apps/services/core_isolation_manager.h" +#include "apps/services/e2_metric_connector_manager.h" +#include "apps/services/metrics/metrics_manager.h" +#include "apps/services/metrics/metrics_notifier_proxy.h" #include "apps/services/stdin_command_dispatcher.h" - -#include "apps/units/flexible_du/split_dynamic/dynamic_du_factory.h" +#include "apps/services/worker_manager.h" #include "apps/gnb/adapters/e2_gateway_remote_connector.h" -#include "apps/services/e2_metric_connector_manager.h" // Include ThreadSanitizer (TSAN) options if thread sanitization is enabled. // This include is not unused - it helps prevent false alarms from the thread sanitizer. #include "srsran/support/tsan_options.h" -#include "apps/services/application_message_banners.h" -#include "apps/services/buffer_pool/buffer_pool_manager.h" -#include "apps/services/core_isolation_manager.h" -#include "apps/services/metrics/metrics_manager.h" -#include "apps/services/metrics/metrics_notifier_proxy.h" #include "apps/units/cu_cp/cu_cp_application_unit.h" #include "apps/units/cu_cp/cu_cp_config_translators.h" #include "apps/units/cu_cp/cu_cp_unit_config.h" #include "apps/units/cu_cp/pcap_factory.h" -#include "apps/units/cu_up/cu_up_builder.h" -#include "apps/units/cu_up/cu_up_logger_registrator.h" -#include "apps/units/cu_up/cu_up_unit_config_cli11_schema.h" -#include "apps/units/cu_up/cu_up_unit_config_translators.h" -#include "apps/units/cu_up/cu_up_unit_config_validator.h" -#include "apps/units/cu_up/cu_up_unit_config_yaml_writer.h" +#include "apps/units/cu_up/cu_up_application_unit.h" +#include "apps/units/cu_up/cu_up_unit_config.h" #include "apps/units/cu_up/pcap_factory.h" #include "apps/units/flexible_du/du_high/du_high_config.h" #include "apps/units/flexible_du/du_high/pcap_factory.h" #include "apps/units/flexible_du/flexible_du_application_unit.h" -#include - -#include "srsran/du/du_power_controller.h" -#include "srsran/support/cli11_utils.h" +#include #include #ifdef DPDK_FOUND @@ -129,10 +118,10 @@ static void initialize_log(const std::string& filename) srslog::init(); } -static void register_app_logs(const logger_appconfig& log_cfg, - cu_cp_application_unit& cu_cp_app_unit, - const cu_up_unit_logger_config& cu_up_loggers, - flexible_du_application_unit& du_app_unit) +static void register_app_logs(const logger_appconfig& log_cfg, + cu_cp_application_unit& cu_cp_app_unit, + cu_up_application_unit& cu_up_app_unit, + flexible_du_application_unit& du_app_unit) { // Set log-level of app and all non-layer specific components to app level. for (const auto& id : {"ALL", "SCTP-GW", "IO-EPOLL", "UDP-GW", "PCAP"}) { @@ -161,7 +150,7 @@ static void register_app_logs(const logger_appconfig& log_cfg, // Register units logs. cu_cp_app_unit.on_loggers_registration(); - register_cu_up_loggers(cu_up_loggers); + cu_up_app_unit.on_loggers_registration(); du_app_unit.on_loggers_registration(); } @@ -185,6 +174,15 @@ static void autoderive_slicing_args(du_high_unit_config& du_hi_cfg, cu_cp_unit_c } } +static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_cfg, const cu_cp_unit_config& cu_cp_cfg) +{ + // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. + if (cu_up_cfg.upf_cfg.bind_addr == "auto") { + cu_up_cfg.upf_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; + } + cu_up_cfg.upf_cfg.no_core = cu_cp_cfg.amf_config.no_core; +} + int main(int argc, char** argv) { // Set the application error handler. @@ -215,30 +213,29 @@ int main(int argc, char** argv) cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg.set_default_filename("/tmp/gnb"); cu_cp_app_unit->on_parsing_configuration_registration(app); - cu_up_unit_config cu_up_config; - cu_up_config.pcap_cfg.set_default_filename("/tmp/gnb"); - configure_cli11_with_cu_up_unit_config_schema(app, cu_up_config); + auto cu_up_app_unit = create_cu_up_application_unit(); + cu_up_app_unit->get_cu_up_unit_config().pcap_cfg.set_default_filename("/tmp/gnb"); + cu_up_app_unit->on_parsing_configuration_registration(app); auto du_app_unit = create_flexible_du_application_unit(); du_app_unit->get_du_high_unit_config().pcaps.set_default_filename("/tmp/gnb"); du_app_unit->on_parsing_configuration_registration(app); // Set the callback for the app calling all the autoderivation functions. - app.callback([&app, &gnb_cfg, &du_app_unit, &cu_cp_app_unit, &cu_up_config]() { - cu_cp_unit_config& cu_cp_unit_cfg = cu_cp_app_unit->get_cu_cp_unit_config(); + app.callback([&app, &gnb_cfg, &du_app_unit, &cu_cp_app_unit, &cu_up_app_unit]() { autoderive_gnb_parameters_after_parsing(app, gnb_cfg); - autoderive_slicing_args(du_app_unit->get_du_high_unit_config(), cu_cp_unit_cfg); + autoderive_slicing_args(du_app_unit->get_du_high_unit_config(), cu_cp_app_unit->get_cu_cp_unit_config()); du_app_unit->on_configuration_parameters_autoderivation(app); // If test mode is enabled, we auto-enable "no_core" option and generate a amf config with no core. if (du_app_unit->get_du_high_unit_config().is_testmode_enabled()) { - cu_cp_unit_cfg.amf_config.no_core = true; - cu_cp_unit_cfg.amf_config.amf.supported_tas = {{7, {{"00101", {s_nssai_t{1}}}}}}; + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core = true; + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf.supported_tas = {{7, {{"00101", {s_nssai_t{1}}}}}}; } cu_cp_app_unit->on_configuration_parameters_autoderivation(app); - autoderive_cu_up_parameters_after_parsing( - cu_cp_unit_cfg.amf_config.amf.bind_addr, cu_cp_unit_cfg.amf_config.no_core, cu_up_config); + autoderive_cu_up_parameters_after_parsing(cu_up_app_unit->get_cu_up_unit_config(), + cu_cp_app_unit->get_cu_cp_unit_config()); }); // Parse arguments. @@ -249,22 +246,23 @@ int main(int argc, char** argv) : os_sched_affinity_bitmask::available_cpus(); // Check the modified configuration. if (!validate_appconfig(gnb_cfg) || !cu_cp_app_unit->on_configuration_validation(available_cpu_mask) || - !validate_cu_up_unit_config(cu_up_config) || !du_app_unit->on_configuration_validation(available_cpu_mask) || + !cu_up_app_unit->on_configuration_validation(available_cpu_mask) || + !du_app_unit->on_configuration_validation(available_cpu_mask) || !validate_plmn_and_tacs(du_app_unit->get_du_high_unit_config(), cu_cp_app_unit->get_cu_cp_unit_config())) { report_error("Invalid configuration detected.\n"); } // Set up logging. initialize_log(gnb_cfg.log_cfg.filename); - register_app_logs(gnb_cfg.log_cfg, *cu_cp_app_unit, cu_up_config.loggers, *du_app_unit); + register_app_logs(gnb_cfg.log_cfg, *cu_cp_app_unit, *cu_up_app_unit, *du_app_unit); // Log input configuration. srslog::basic_logger& config_logger = srslog::fetch_basic_logger("CONFIG"); if (config_logger.debug.enabled()) { YAML::Node node; fill_gnb_appconfig_in_yaml_schema(node, gnb_cfg); - fill_cu_up_config_in_yaml_schema(node, cu_up_config); cu_cp_app_unit->dump_config(node); + cu_up_app_unit->dump_config(node); du_app_unit->dump_config(node); config_logger.debug("Input configuration (all values): \n{}", YAML::Dump(node)); } else { @@ -318,7 +316,7 @@ int main(int argc, char** argv) worker_manager_config worker_manager_cfg; fill_gnb_worker_manager_config(worker_manager_cfg, gnb_cfg); cu_cp_app_unit->fill_worker_manager_config(worker_manager_cfg); - fill_cu_up_worker_manager_config(worker_manager_cfg, cu_up_config); + cu_up_app_unit->fill_worker_manager_config(worker_manager_cfg); du_app_unit->fill_worker_manager_config(worker_manager_cfg); worker_manager workers{worker_manager_cfg}; @@ -333,12 +331,13 @@ int main(int argc, char** argv) // Create layer specific PCAPs. // In the gNB app, there is no point in instantiating two pcaps for each node of E1 and F1. // We disable one accordingly. - cu_up_config.pcap_cfg.disable_e1_pcaps(); + cu_up_app_unit->get_cu_up_unit_config().pcap_cfg.disable_e1_pcaps(); du_app_unit->get_du_high_unit_config().pcaps.disable_f1_pcaps(); cu_cp_dlt_pcaps cu_cp_dlt_pcaps = create_cu_cp_dlt_pcap(cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg, *workers.get_executor_getter()); - cu_up_dlt_pcaps cu_up_dlt_pcaps = create_cu_up_dlt_pcaps(cu_up_config.pcap_cfg, *workers.get_executor_getter()); - flexible_du_pcaps du_pcaps = create_du_pcaps(du_app_unit->get_du_high_unit_config().pcaps, workers); + cu_up_dlt_pcaps cu_up_dlt_pcaps = + create_cu_up_dlt_pcaps(cu_up_app_unit->get_cu_up_unit_config().pcap_cfg, *workers.get_executor_getter()); + flexible_du_pcaps du_pcaps = create_du_pcaps(du_app_unit->get_du_high_unit_config().pcaps, workers); std::unique_ptr f1c_gw = create_f1c_local_connector(f1c_local_connector_config{*cu_cp_dlt_pcaps.f1ap}); @@ -432,13 +431,15 @@ int main(int argc, char** argv) srs_cu_cp::cu_cp& cu_cp_obj = *cu_cp_obj_and_cmds.unit; // Create and start CU-UP - std::unique_ptr cu_up_obj = build_cu_up(cu_up_config, - workers, - *e1_gw, - *f1u_conn->get_f1u_cu_up_gateway(), - *cu_up_dlt_pcaps.n3, - *cu_timers, - *epoll_broker); + cu_up_unit_dependencies cu_up_unit_deps; + cu_up_unit_deps.workers = &workers; + cu_up_unit_deps.e1ap_conn_client = e1_gw.get(); + cu_up_unit_deps.f1u_gateway = f1u_conn->get_f1u_cu_up_gateway(); + cu_up_unit_deps.gtpu_pcap = cu_up_dlt_pcaps.n3.get(); + cu_up_unit_deps.timers = cu_timers; + cu_up_unit_deps.io_brk = epoll_broker.get(); + + std::unique_ptr cu_up_obj = cu_up_app_unit->create_cu_up_unit(cu_up_unit_deps); // Instantiate one DU. app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder; diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager.cpp index af618781b3..060f909958 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager.cpp @@ -36,10 +36,6 @@ worker_manager::worker_manager(const worker_manager_config& worker_cfg) : srsran_assert(ru_config_count <= 1, "Worker manager received configuration for more than one RU type"); } - if (worker_cfg.ru_ofh_cfg) { - ru_timing_mask = worker_cfg.ru_ofh_cfg.value().ru_timing_cpu; - } - for (const auto& cell_affinities : worker_cfg.config_affinities) { affinity_mng.emplace_back(cell_affinities); } @@ -47,9 +43,12 @@ worker_manager::worker_manager(const worker_manager_config& worker_cfg) : create_low_prio_executors(worker_cfg); associate_low_prio_executors(); - create_du_executors(worker_cfg.du_hi_cfg, worker_cfg.du_low_cfg, worker_cfg.fapi_cfg); + if (worker_cfg.du_hi_cfg) { + create_du_executors(worker_cfg.du_hi_cfg.value(), worker_cfg.du_low_cfg, worker_cfg.fapi_cfg); + } if (worker_cfg.ru_ofh_cfg) { + ru_timing_mask = worker_cfg.ru_ofh_cfg.value().ru_timing_cpu; ru_txrx_affinity_masks = worker_cfg.ru_ofh_cfg.value().txrx_affinities; create_ofh_executors(worker_cfg.ru_ofh_cfg.value()); } @@ -310,17 +309,19 @@ void worker_manager::create_low_prio_executors(const worker_manager_config& work strand cp_strand{{{"timer_exec", concurrent_queue_policy::lockfree_spsc, task_worker_queue_size, - not worker_cfg.du_hi_cfg.is_rt_mode_enabled}, + worker_cfg.du_hi_cfg ? !worker_cfg.du_hi_cfg->is_rt_mode_enabled : false}, {"ctrl_exec", concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}}; high_prio_strands.push_back(cp_strand); // Setup strands for the data plane of all the instantiated DUs. // One strand per DU, each with multiple priority levels. - for (unsigned i = 0; i != worker_cfg.du_hi_cfg.nof_cells; ++i) { - low_prio_strands.push_back(strand{ - {{fmt::format("du_rb_prio_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}, - {fmt::format("du_rb_ul_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, worker_cfg.gtpu_queue_size}, - {fmt::format("du_rb_dl_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, worker_cfg.gtpu_queue_size}}}); + if (worker_cfg.du_hi_cfg) { + for (unsigned i = 0; i != worker_cfg.du_hi_cfg->nof_cells; ++i) { + low_prio_strands.push_back(strand{ + {{fmt::format("du_rb_prio_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}, + {fmt::format("du_rb_ul_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, worker_cfg.gtpu_queue_size}, + {fmt::format("du_rb_dl_exec#{}", i), concurrent_queue_policy::lockfree_mpmc, worker_cfg.gtpu_queue_size}}}); + } } // Configuration of strands for user plane handling (CU-UP and DU-low user plane). Given that the CU-UP doesn't diff --git a/apps/services/worker_manager_config.h b/apps/services/worker_manager_config.h index 5962eea8f2..809d2fc8c5 100644 --- a/apps/services/worker_manager_config.h +++ b/apps/services/worker_manager_config.h @@ -66,7 +66,7 @@ struct worker_manager_config { /// DU high worker configuration. struct du_high_config { unsigned nof_cells; - bool is_rt_mode_enabled = true; + bool is_rt_mode_enabled; }; /// PCAP worker configuration. @@ -85,14 +85,14 @@ struct worker_manager_config { unsigned nof_low_prio_threads; /// Low priority CPU bitmasks. os_sched_affinity_config low_prio_sched_config; - /// DU high configuration. - du_high_config du_hi_cfg; /// PCAP configuration. pcap_config pcap_cfg; /// GTPU queue size. unsigned gtpu_queue_size; /// Vector of affinities mask indexed by cell. std::vector> config_affinities; + /// DU high configuration. + std::optional du_hi_cfg; /// FAPI configuration. std::optional fapi_cfg; /// DU low configuration diff --git a/apps/units/cu_up/cu_up_application_unit.h b/apps/units/cu_up/cu_up_application_unit.h new file mode 100644 index 0000000000..7e49e98b07 --- /dev/null +++ b/apps/units/cu_up/cu_up_application_unit.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "apps/units/application_unit.h" +#include "apps/units/cu_up/cu_up_builder.h" +#include + +namespace srsran { +struct worker_manager_config; + +/// CU-UP application unit interface. +class cu_up_application_unit : public application_unit +{ +public: + virtual ~cu_up_application_unit() = default; + + /// Creates a CU-UP using the given dependencies. + virtual std::unique_ptr + create_cu_up_unit(const cu_up_unit_dependencies& dependencies) = 0; + + /// Returns the CU-UP unit configuration of this CU-UP application unit. + virtual cu_up_unit_config& get_cu_up_unit_config() = 0; + virtual const cu_up_unit_config& get_cu_up_unit_config() const = 0; + + /// Dumps the CU-UP configuration into the given YAML node. + virtual void dump_config(YAML::Node& node) const = 0; + + /// Fills the given worker manager configuration with the CU-UP parameters. + virtual void fill_worker_manager_config(worker_manager_config& config) = 0; +}; + +/// Creates a CU-UP application unit. +std::unique_ptr create_cu_up_application_unit(); + +} // namespace srsran diff --git a/apps/units/cu_up/cu_up_application_unit_impl.cpp b/apps/units/cu_up/cu_up_application_unit_impl.cpp index aa6a0990f5..cfabf9dff0 100644 --- a/apps/units/cu_up/cu_up_application_unit_impl.cpp +++ b/apps/units/cu_up/cu_up_application_unit_impl.cpp @@ -9,9 +9,12 @@ */ #include "cu_up_application_unit_impl.h" +#include "cu_up_builder.h" #include "cu_up_logger_registrator.h" #include "cu_up_unit_config_cli11_schema.h" +#include "cu_up_unit_config_translators.h" #include "cu_up_unit_config_validator.h" +#include "cu_up_unit_config_yaml_writer.h" using namespace srsran; @@ -29,3 +32,24 @@ void cu_up_application_unit_impl::on_loggers_registration() { register_cu_up_loggers(unit_cfg.loggers); } +std::unique_ptr + +cu_up_application_unit_impl::create_cu_up_unit(const cu_up_unit_dependencies& dependencies) +{ + return build_cu_up(unit_cfg, dependencies); +} + +void cu_up_application_unit_impl::dump_config(YAML::Node& node) const +{ + fill_cu_up_config_in_yaml_schema(node, unit_cfg); +} + +void cu_up_application_unit_impl::fill_worker_manager_config(worker_manager_config& config) +{ + fill_cu_up_worker_manager_config(config, unit_cfg); +} + +std::unique_ptr srsran::create_cu_up_application_unit() +{ + return std::make_unique(); +} diff --git a/apps/units/cu_up/cu_up_application_unit_impl.h b/apps/units/cu_up/cu_up_application_unit_impl.h index 4b9457c944..e21963bcdf 100644 --- a/apps/units/cu_up/cu_up_application_unit_impl.h +++ b/apps/units/cu_up/cu_up_application_unit_impl.h @@ -10,24 +10,40 @@ #pragma once -#include "../application_unit.h" +#include "apps/units/cu_up/cu_up_application_unit.h" #include "cu_up_unit_config.h" namespace srsran { /// CU-UP application unit implementation. -class cu_up_application_unit_impl : public application_unit +class cu_up_application_unit_impl : public cu_up_application_unit { public: // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; + // See interface for documentation. + void on_configuration_parameters_autoderivation(CLI::App& app) override {} + // See interface for documentation. bool on_configuration_validation(const os_sched_affinity_bitmask& available_cpus) const override; // See interface for documentation. void on_loggers_registration() override; + // See interface for documentation. + std::unique_ptr create_cu_up_unit(const cu_up_unit_dependencies& dependencies) override; + + // See interface for documentation. + cu_up_unit_config& get_cu_up_unit_config() override { return unit_cfg; } + const cu_up_unit_config& get_cu_up_unit_config() const override { return unit_cfg; } + + // See interface for documentation. + void dump_config(YAML::Node& node) const override; + + // See interface for documentation. + void fill_worker_manager_config(worker_manager_config& config) override; + private: cu_up_unit_config unit_cfg; }; diff --git a/apps/units/cu_up/cu_up_builder.cpp b/apps/units/cu_up/cu_up_builder.cpp index 99501b9c26..a08112623e 100644 --- a/apps/units/cu_up/cu_up_builder.cpp +++ b/apps/units/cu_up/cu_up_builder.cpp @@ -17,25 +17,24 @@ using namespace srsran; -std::unique_ptr srsran::build_cu_up(const cu_up_unit_config& unit_cfg, - worker_manager& workers, - srs_cu_up::e1_connection_client& e1_conn_client, - f1u_cu_up_gateway& f1u_gateway, - dlt_pcap& gtpu_pcap, - timer_manager& timers, - io_broker& io_brk) +std::unique_ptr srsran::build_cu_up(const cu_up_unit_config& unit_cfg, + const cu_up_unit_dependencies& dependencies) { srs_cu_up::cu_up_configuration config = generate_cu_up_config(unit_cfg); - config.ctrl_executor = workers.cu_up_ctrl_exec; - config.cu_up_e2_exec = workers.cu_up_e2_exec; - config.ue_exec_pool = workers.cu_up_exec_mapper.get(); - config.io_ul_executor = workers.cu_up_io_ul_exec; // Optionally select separate exec for UL IO - config.e1ap.e1_conn_client = &e1_conn_client; - config.f1u_gateway = &f1u_gateway; - config.gtpu_pcap = >pu_pcap; - config.timers = &timers; - config.qos = generate_cu_up_qos_config(unit_cfg); + config.ctrl_executor = dependencies.workers->cu_up_ctrl_exec; + config.cu_up_e2_exec = dependencies.workers->cu_up_e2_exec; + config.ue_exec_pool = dependencies.workers->cu_up_exec_mapper.get(); + config.io_ul_executor = dependencies.workers->cu_up_io_ul_exec; // Optionally select separate exec for UL IO + config.e1ap.e1_conn_client = dependencies.e1ap_conn_client; + config.f1u_gateway = dependencies.f1u_gateway; + config.gtpu_pcap = dependencies.gtpu_pcap; + config.timers = dependencies.timers; + config.qos = generate_cu_up_qos_config(unit_cfg); + auto address = config.f1u_gateway->get_cu_bind_address(); + srsran_assert(address.has_value(), "Invalid F1-U bind address"); + + config.net_cfg.f1u_bind_addr = address.value(); // Create NG-U gateway. std::unique_ptr ngu_gw; if (not unit_cfg.upf_cfg.no_core) { @@ -44,7 +43,8 @@ std::unique_ptr srsran::build_cu_up(const cu_up_unit ngu_gw_config.bind_port = config.net_cfg.n3_bind_port; ngu_gw_config.bind_interface = config.net_cfg.n3_bind_interface; ngu_gw_config.rx_max_mmsg = config.net_cfg.n3_rx_max_mmsg; - ngu_gw = srs_cu_up::create_udp_ngu_gateway(ngu_gw_config, io_brk, *workers.cu_up_io_ul_exec); + ngu_gw = + srs_cu_up::create_udp_ngu_gateway(ngu_gw_config, *dependencies.io_brk, *dependencies.workers->cu_up_io_ul_exec); } else { ngu_gw = srs_cu_up::create_no_core_ngu_gateway(); } diff --git a/apps/units/cu_up/cu_up_builder.h b/apps/units/cu_up/cu_up_builder.h index abb875c1fa..cd4f92185f 100644 --- a/apps/units/cu_up/cu_up_builder.h +++ b/apps/units/cu_up/cu_up_builder.h @@ -26,13 +26,18 @@ class f1u_cu_up_gateway; class io_broker; struct worker_manager; +/// CU-UP unit dependencies. +struct cu_up_unit_dependencies { + worker_manager* workers; + srs_cu_up::e1_connection_client* e1ap_conn_client; + f1u_cu_up_gateway* f1u_gateway; + dlt_pcap* gtpu_pcap; + timer_manager* timers; + io_broker* io_brk; +}; + /// Builds the CU UP using the given arguments. -std::unique_ptr build_cu_up(const cu_up_unit_config& unit_cfg, - worker_manager& workers, - srs_cu_up::e1_connection_client& e1ap_conn_client, - f1u_cu_up_gateway& f1u_gateway, - dlt_pcap& gtpu_pcap, - timer_manager& timers, - io_broker& io_brk); +std::unique_ptr build_cu_up(const cu_up_unit_config& unit_cfg, + const cu_up_unit_dependencies& dependencies); } // namespace srsran diff --git a/apps/units/cu_up/cu_up_unit_config_cli11_schema.cpp b/apps/units/cu_up/cu_up_unit_config_cli11_schema.cpp index 44ba621151..7285333b99 100644 --- a/apps/units/cu_up/cu_up_unit_config_cli11_schema.cpp +++ b/apps/units/cu_up/cu_up_unit_config_cli11_schema.cpp @@ -186,14 +186,3 @@ void srsran::configure_cli11_with_cu_up_unit_config_schema(CLI::App& app, cu_up_ CLI::App* test_mode_subcmd = add_subcommand(app, "test_mode", "CU-UP test mode parameters")->configurable(); configure_cli11_test_mode_args(*test_mode_subcmd, unit_cfg.test_mode_cfg); } - -void srsran::autoderive_cu_up_parameters_after_parsing(const std::string& n2_bind_addr, - bool no_core, - cu_up_unit_config& unit_cfg) -{ - // If no UPF is configured, we autoderive the UPF configuration from the CU-CP AMF configuration. - if (unit_cfg.upf_cfg.bind_addr == "auto") { - unit_cfg.upf_cfg.bind_addr = n2_bind_addr; - } - unit_cfg.upf_cfg.no_core = no_core; -} diff --git a/apps/units/cu_up/cu_up_unit_config_cli11_schema.h b/apps/units/cu_up/cu_up_unit_config_cli11_schema.h index 2c70d5939e..ff7eb3d715 100644 --- a/apps/units/cu_up/cu_up_unit_config_cli11_schema.h +++ b/apps/units/cu_up/cu_up_unit_config_cli11_schema.h @@ -19,7 +19,4 @@ struct cu_up_unit_config; /// Configures the given CLI11 application with the CU-UP application unit configuration schema. void configure_cli11_with_cu_up_unit_config_schema(CLI::App& app, cu_up_unit_config& unit_cfg); -/// Auto derive CU-UP parameters after the parsing. -void autoderive_cu_up_parameters_after_parsing(const std::string& bind_addr, bool no_core, cu_up_unit_config& unit_cfg); - } // namespace srsran diff --git a/apps/units/flexible_du/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/du_high/du_high_config_translators.cpp index 07ca6835ca..fba3b05b3e 100644 --- a/apps/units/flexible_du/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_translators.cpp @@ -948,7 +948,7 @@ void srsran::fill_du_high_worker_manager_config(worker_manager_config& confi const du_high_unit_config& unit_cfg, bool is_blocking_mode_enabled) { - auto& du_hi_cfg = config.du_hi_cfg; + auto& du_hi_cfg = config.du_hi_cfg.emplace(); du_hi_cfg.is_rt_mode_enabled = !is_blocking_mode_enabled; du_hi_cfg.nof_cells = unit_cfg.cells_cfg.size(); diff --git a/include/srsran/f1u/cu_up/f1u_gateway.h b/include/srsran/f1u/cu_up/f1u_gateway.h index a5292699eb..3f8190ada6 100644 --- a/include/srsran/f1u/cu_up/f1u_gateway.h +++ b/include/srsran/f1u/cu_up/f1u_gateway.h @@ -58,6 +58,8 @@ class f1u_cu_up_gateway : public srs_cu_up::f1u_bearer_disconnector virtual void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, const up_transport_layer_info& dl_up_tnl_info) = 0; + + virtual expected get_cu_bind_address() const = 0; }; /// This class will be used to provide the interfaces to diff --git a/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h b/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h index 0e3befe480..8699f2e640 100644 --- a/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h +++ b/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h @@ -20,8 +20,8 @@ namespace srsran::srs_cu_up { struct f1u_cu_up_split_gateway_creation_msg { - ngu_gateway* udp_gw; - gtpu_demux* demux; + ngu_gateway& udp_gw; + gtpu_demux& demux; dlt_pcap& gtpu_pcap; uint16_t peer_port; }; diff --git a/include/srsran/f1u/local_connector/f1u_local_connector.h b/include/srsran/f1u/local_connector/f1u_local_connector.h index f56c4b0342..36cc36b9a7 100644 --- a/include/srsran/f1u/local_connector/f1u_local_connector.h +++ b/include/srsran/f1u/local_connector/f1u_local_connector.h @@ -202,6 +202,8 @@ class f1u_local_connector final : public srs_du::f1u_du_gateway, public f1u_cu_u return fmt::format("127.0.0.{}", 1 + static_cast(gnb_du_id)); } + expected get_cu_bind_address() const override { return {"127.0.2.1"}; } + private: srslog::basic_logger& logger_cu; srslog::basic_logger& logger_du; diff --git a/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp b/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp index 010b4f7a3e..134cefd47f 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp @@ -110,8 +110,8 @@ void f1u_split_gateway_cu_bearer::stop() stopped = true; } -f1u_split_connector::f1u_split_connector(ngu_gateway* udp_gw_, - gtpu_demux* demux_, +f1u_split_connector::f1u_split_connector(ngu_gateway& udp_gw_, + gtpu_demux& demux_, dlt_pcap& gtpu_pcap_, uint16_t peer_port_) : logger_cu(srslog::fetch_basic_logger("CU-F1-U")), @@ -121,8 +121,8 @@ f1u_split_connector::f1u_split_connector(ngu_gateway* udp_gw_, gtpu_pcap(gtpu_pcap_) { gw_data_gtpu_demux_adapter = std::make_unique(); - udp_session = udp_gw->create(*gw_data_gtpu_demux_adapter); - gw_data_gtpu_demux_adapter->connect_gtpu_demux(*demux); + udp_session = udp_gw.create(*gw_data_gtpu_demux_adapter); + gw_data_gtpu_demux_adapter->connect_gtpu_demux(demux); } f1u_split_connector::~f1u_split_connector() = default; @@ -156,7 +156,7 @@ f1u_split_connector::create_cu_bearer(uint32_t ue_i cu_bearer->attach_tunnel_rx(std::move(tunnel_rx)); // attach tunnel rx to DEMUX - if (!demux->add_tunnel(ul_up_tnl_info.gtp_teid, cu_bearer->ul_exec, cu_bearer->get_tunnel_rx_interface())) { + if (!demux.add_tunnel(ul_up_tnl_info.gtp_teid, cu_bearer->ul_exec, cu_bearer->get_tunnel_rx_interface())) { logger_cu.error("Could not attach UL-TEID to demux RX. TEID {} already exists", ul_up_tnl_info.gtp_teid); // continue here; but the new tunnel won't be able to rx any data because the TEID was already registered at demux } @@ -215,7 +215,7 @@ void f1u_split_connector::disconnect_cu_bearer(const up_transport_layer_info& ul cu_bearer->gtpu_to_f1u_adapter->disconnect(); // Remove UL from GTP-U demux - demux->remove_tunnel(ul_up_tnl_info.gtp_teid); + demux.remove_tunnel(ul_up_tnl_info.gtp_teid); // Remove DL path { @@ -224,3 +224,14 @@ void f1u_split_connector::disconnect_cu_bearer(const up_transport_layer_info& ul } logger_cu.debug("Removed CU F1-U bearer with UL GTP Tunnel={}.", ul_up_tnl_info); } + +expected f1u_split_connector::get_cu_bind_address() const +{ + std::string ip_address; + + if (not udp_session->get_bind_address(ip_address)) { + return make_unexpected(default_error_t{}); + } + + return ip_address; +} diff --git a/lib/f1u/cu_up/split_connector/f1u_split_connector.h b/lib/f1u/cu_up/split_connector/f1u_split_connector.h index 1b57dce6a0..7967ef286b 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.h +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.h @@ -103,7 +103,7 @@ class f1u_split_gateway_cu_bearer final : public f1u_cu_up_gateway_bearer class f1u_split_connector final : public f1u_cu_up_udp_gateway { public: - f1u_split_connector(ngu_gateway* udp_gw_, gtpu_demux* demux_, dlt_pcap& gtpu_pcap_, uint16_t peer_port_ = GTPU_PORT); + f1u_split_connector(ngu_gateway& udp_gw_, gtpu_demux& demux_, dlt_pcap& gtpu_pcap_, uint16_t peer_port_ = GTPU_PORT); ~f1u_split_connector() override; f1u_cu_up_gateway* get_f1u_cu_up_gateway() { return this; } @@ -122,6 +122,8 @@ class f1u_split_connector final : public f1u_cu_up_udp_gateway void disconnect_cu_bearer(const up_transport_layer_info& ul_up_tnl_info) override; + expected get_cu_bind_address() const override; + private: srslog::basic_logger& logger_cu; // Key is the UL UP TNL Info (CU-CP address and UL TEID reserved by CU-CP) @@ -129,9 +131,9 @@ class f1u_split_connector final : public f1u_cu_up_udp_gateway std::mutex map_mutex; // shared mutex for access to cu_map uint16_t peer_port; - ngu_gateway* udp_gw; + ngu_gateway& udp_gw; std::unique_ptr udp_session; - gtpu_demux* demux; + gtpu_demux& demux; std::unique_ptr gw_data_gtpu_demux_adapter; dlt_pcap& gtpu_pcap; }; diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index 25f577d4c6..6af51a6cd2 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -241,6 +241,8 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway removed_ul_teid_list.push_back(ul_up_tnl_info.gtp_teid); } + expected get_cu_bind_address() const override { return "127.0.0.1"; } + std::list created_ul_teid_list = {}; std::list attached_ul_teid_list = {}; std::list removed_ul_teid_list = {}; diff --git a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp index cbc4464f98..8604a6fbb3 100644 --- a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp @@ -133,7 +133,7 @@ class f1u_cu_split_connector_test : public ::testing::Test nru_gw_config.reuse_addr = true; udp_gw = srs_cu_up::create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); - f1u_cu_up_split_gateway_creation_msg cu_create_msg{udp_gw.get(), demux.get(), dummy_pcap, tester_bind_port.value()}; + f1u_cu_up_split_gateway_creation_msg cu_create_msg{*udp_gw, *demux, dummy_pcap, tester_bind_port.value()}; cu_gw = create_split_f1u_gw(cu_create_msg); cu_gw_bind_port = cu_gw->get_bind_port(); ASSERT_TRUE(cu_gw_bind_port.has_value()); From 749e4f6eb17fbebadc906804991b819ce95cb88b Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Tue, 1 Oct 2024 11:37:44 +0200 Subject: [PATCH 21/32] app_units: pass the application name in construction to set the PCAPS paths --- apps/cu/cu.cpp | 6 ++---- apps/du/du.cpp | 3 +-- apps/gnb/gnb.cpp | 9 +++------ apps/units/cu_cp/cu_cp_application_unit.h | 2 +- apps/units/cu_cp/cu_cp_application_unit_impl.cpp | 11 +++++++++-- apps/units/cu_cp/cu_cp_application_unit_impl.h | 2 ++ apps/units/cu_cp/cu_cp_unit_pcap_config.h | 12 +----------- apps/units/cu_up/cu_up_application_unit.h | 2 +- apps/units/cu_up/cu_up_application_unit_impl.cpp | 11 +++++++++-- apps/units/cu_up/cu_up_application_unit_impl.h | 2 ++ apps/units/cu_up/cu_up_unit_pcap_config.h | 10 ---------- apps/units/flexible_du/du_high/du_high_config.h | 12 +----------- .../flexible_du/flexible_du_application_unit.h | 2 +- .../split_6/split6_du_application_unit_impl.cpp | 9 +++++++++ .../split_6/split6_du_application_unit_impl.h | 2 ++ .../split_7_2_du_application_unit_impl.cpp | 13 +++++++++++-- .../split_7_2/split_7_2_du_application_unit_impl.h | 2 ++ .../split_8/split_8_du_application_unit_impl.cpp | 13 +++++++++++-- .../split_8/split_8_du_application_unit_impl.h | 2 ++ .../dynamic_du_application_unit_impl.cpp | 13 +++++++++++-- .../dynamic_du_application_unit_impl.h | 2 ++ 21 files changed, 83 insertions(+), 57 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 94d2164c41..d083cdbf4e 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -184,12 +184,10 @@ int main(int argc, char** argv) cu_appconfig cu_cfg; configure_cli11_with_cu_appconfig_schema(app, cu_cfg); - auto cu_cp_app_unit = create_cu_cp_application_unit(); - cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg.set_default_filename("/tmp/cu"); + auto cu_cp_app_unit = create_cu_cp_application_unit("cu"); cu_cp_app_unit->on_parsing_configuration_registration(app); - auto cu_up_app_unit = create_cu_up_application_unit(); - cu_up_app_unit->get_cu_up_unit_config().pcap_cfg.set_default_filename("/tmp/cu"); + auto cu_up_app_unit = create_cu_up_application_unit("cu"); cu_up_app_unit->on_parsing_configuration_registration(app); // Set the callback for the app calling all the autoderivation functions. diff --git a/apps/du/du.cpp b/apps/du/du.cpp index cda223e9ad..d55a13cf49 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -165,8 +165,7 @@ int main(int argc, char** argv) // Configure CLI11 with the DU application configuration schema. configure_cli11_with_du_appconfig_schema(app, du_cfg); - auto du_app_unit = create_flexible_du_application_unit(); - du_app_unit->get_du_high_unit_config().pcaps.set_default_filename("/tmp/du"); + auto du_app_unit = create_flexible_du_application_unit("du"); du_app_unit->on_parsing_configuration_registration(app); // Set the callback for the app calling all the autoderivation functions. diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index f35b93494c..99d77a6743 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -209,16 +209,13 @@ int main(int argc, char** argv) // Configure CLI11 with the gNB application configuration schema. configure_cli11_with_gnb_appconfig_schema(app, gnb_cfg); - auto cu_cp_app_unit = create_cu_cp_application_unit(); - cu_cp_app_unit->get_cu_cp_unit_config().pcap_cfg.set_default_filename("/tmp/gnb"); + auto cu_cp_app_unit = create_cu_cp_application_unit("gnb"); cu_cp_app_unit->on_parsing_configuration_registration(app); - auto cu_up_app_unit = create_cu_up_application_unit(); - cu_up_app_unit->get_cu_up_unit_config().pcap_cfg.set_default_filename("/tmp/gnb"); + auto cu_up_app_unit = create_cu_up_application_unit("gnb"); cu_up_app_unit->on_parsing_configuration_registration(app); - auto du_app_unit = create_flexible_du_application_unit(); - du_app_unit->get_du_high_unit_config().pcaps.set_default_filename("/tmp/gnb"); + auto du_app_unit = create_flexible_du_application_unit("gnb"); du_app_unit->on_parsing_configuration_registration(app); // Set the callback for the app calling all the autoderivation functions. diff --git a/apps/units/cu_cp/cu_cp_application_unit.h b/apps/units/cu_cp/cu_cp_application_unit.h index e9ba8ea253..221d07ee23 100644 --- a/apps/units/cu_cp/cu_cp_application_unit.h +++ b/apps/units/cu_cp/cu_cp_application_unit.h @@ -38,6 +38,6 @@ class cu_cp_application_unit : public application_unit }; /// Creates a CU-CP application unit. -std::unique_ptr create_cu_cp_application_unit(); +std::unique_ptr create_cu_cp_application_unit(std::string_view app_name); } // namespace srsran diff --git a/apps/units/cu_cp/cu_cp_application_unit_impl.cpp b/apps/units/cu_cp/cu_cp_application_unit_impl.cpp index c3bed2b40c..cd920029bb 100644 --- a/apps/units/cu_cp/cu_cp_application_unit_impl.cpp +++ b/apps/units/cu_cp/cu_cp_application_unit_impl.cpp @@ -18,6 +18,13 @@ using namespace srsran; +cu_cp_application_unit_impl::cu_cp_application_unit_impl(std::string_view app_name) +{ + unit_cfg.pcap_cfg.ngap.filename = fmt::format("/tmp/{}_ngap.pcap", app_name); + unit_cfg.pcap_cfg.e1ap.filename = fmt::format("/tmp/{}_e1ap.pcap", app_name); + unit_cfg.pcap_cfg.f1ap.filename = fmt::format("/tmp/{}_f1ap.pcap", app_name); +} + void cu_cp_application_unit_impl::on_parsing_configuration_registration(CLI::App& app) { configure_cli11_with_cu_cp_unit_config_schema(app, unit_cfg); @@ -53,7 +60,7 @@ void cu_cp_application_unit_impl::fill_worker_manager_config(worker_manager_conf fill_cu_cp_worker_manager_config(config, unit_cfg); } -std::unique_ptr srsran::create_cu_cp_application_unit() +std::unique_ptr srsran::create_cu_cp_application_unit(std::string_view app_name) { - return std::make_unique(); + return std::make_unique(app_name); } diff --git a/apps/units/cu_cp/cu_cp_application_unit_impl.h b/apps/units/cu_cp/cu_cp_application_unit_impl.h index 2bead19bc5..90834081ed 100644 --- a/apps/units/cu_cp/cu_cp_application_unit_impl.h +++ b/apps/units/cu_cp/cu_cp_application_unit_impl.h @@ -19,6 +19,8 @@ namespace srsran { class cu_cp_application_unit_impl : public cu_cp_application_unit { public: + explicit cu_cp_application_unit_impl(std::string_view app_name); + // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; diff --git a/apps/units/cu_cp/cu_cp_unit_pcap_config.h b/apps/units/cu_cp/cu_cp_unit_pcap_config.h index 6014797b3b..ec9f109f1d 100644 --- a/apps/units/cu_cp/cu_cp_unit_pcap_config.h +++ b/apps/units/cu_cp/cu_cp_unit_pcap_config.h @@ -10,7 +10,6 @@ #pragma once -#include "fmt/core.h" #include namespace srsran { @@ -29,15 +28,6 @@ struct cu_cp_unit_pcap_config { std::string filename = "/tmp/cu_f1ap.pcap"; bool enabled = false; } f1ap; - - /// helper method to set the filename prefix for different apps. - /// This is used to provide different defaults depending on the app, - /// e.g.: "/tmp/gnb_e1ap.pcap" or "/tmp/cu_e1ap.pcap" - void set_default_filename(std::string prefix) - { - ngap.filename = fmt::format("{}_ngap.pcap", prefix); - e1ap.filename = fmt::format("{}_e1ap.pcap", prefix); - f1ap.filename = fmt::format("{}_f1ap.pcap", prefix); - } }; + } // namespace srsran diff --git a/apps/units/cu_up/cu_up_application_unit.h b/apps/units/cu_up/cu_up_application_unit.h index 7e49e98b07..4f430328c1 100644 --- a/apps/units/cu_up/cu_up_application_unit.h +++ b/apps/units/cu_up/cu_up_application_unit.h @@ -39,6 +39,6 @@ class cu_up_application_unit : public application_unit }; /// Creates a CU-UP application unit. -std::unique_ptr create_cu_up_application_unit(); +std::unique_ptr create_cu_up_application_unit(std::string_view app_name); } // namespace srsran diff --git a/apps/units/cu_up/cu_up_application_unit_impl.cpp b/apps/units/cu_up/cu_up_application_unit_impl.cpp index cfabf9dff0..f8a952d7c3 100644 --- a/apps/units/cu_up/cu_up_application_unit_impl.cpp +++ b/apps/units/cu_up/cu_up_application_unit_impl.cpp @@ -18,6 +18,13 @@ using namespace srsran; +cu_up_application_unit_impl::cu_up_application_unit_impl(std::string_view app_name) +{ + unit_cfg.pcap_cfg.n3.filename = fmt::format("/tmp/{}_n3.pcap", app_name); + unit_cfg.pcap_cfg.f1u.filename = fmt::format("/tmp/{}_f1u.pcap", app_name); + unit_cfg.pcap_cfg.e1ap.filename = fmt::format("/tmp/{}_e1ap.pcap", app_name); +} + void cu_up_application_unit_impl::on_parsing_configuration_registration(CLI::App& app) { configure_cli11_with_cu_up_unit_config_schema(app, unit_cfg); @@ -49,7 +56,7 @@ void cu_up_application_unit_impl::fill_worker_manager_config(worker_manager_conf fill_cu_up_worker_manager_config(config, unit_cfg); } -std::unique_ptr srsran::create_cu_up_application_unit() +std::unique_ptr srsran::create_cu_up_application_unit(std::string_view app_name) { - return std::make_unique(); + return std::make_unique(app_name); } diff --git a/apps/units/cu_up/cu_up_application_unit_impl.h b/apps/units/cu_up/cu_up_application_unit_impl.h index e21963bcdf..2474afc881 100644 --- a/apps/units/cu_up/cu_up_application_unit_impl.h +++ b/apps/units/cu_up/cu_up_application_unit_impl.h @@ -19,6 +19,8 @@ namespace srsran { class cu_up_application_unit_impl : public cu_up_application_unit { public: + explicit cu_up_application_unit_impl(std::string_view app_name); + // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; diff --git a/apps/units/cu_up/cu_up_unit_pcap_config.h b/apps/units/cu_up/cu_up_unit_pcap_config.h index 1ebf8f0054..b5bdec1f95 100644 --- a/apps/units/cu_up/cu_up_unit_pcap_config.h +++ b/apps/units/cu_up/cu_up_unit_pcap_config.h @@ -10,7 +10,6 @@ #pragma once -#include "fmt/core.h" #include namespace srsran { @@ -30,15 +29,6 @@ struct cu_up_unit_pcap_config { bool enabled = false; } e1ap; - /// helper method to set the filename prefix for different apps. - /// This is used to provide different defaults depending on the app, - /// e.g.: "/tmp/gnb_e1ap.pcap" or "/tmp/cu_e1ap.pcap" - void set_default_filename(std::string prefix) - { - n3.filename = fmt::format("{}_n3.pcap", prefix); - f1u.filename = fmt::format("{}_f1u.pcap", prefix); - e1ap.filename = fmt::format("{}_e1ap.pcap", prefix); - } /// When using the gNB app, there is no point in instantiating /// E1 pcaps twice. This function force disables them in the CU-UP. /// TODO: revisit diff --git a/apps/units/flexible_du/du_high/du_high_config.h b/apps/units/flexible_du/du_high/du_high_config.h index 62653d0a12..59b9af2d19 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -672,17 +672,7 @@ struct du_high_unit_pcap_config { std::string type = "udp"; bool enabled = false; } mac; - /// helper method to set the filename prefix for different apps. - /// This is used to provide different defaults depending on the app, - /// e.g.: "/tmp/gnb_f1ap.pcap", "/tmp/cu_f1ap.pcap" or "/tmp/du_f1ap.pcap" - void set_default_filename(std::string prefix) - { - e2ap.filename = fmt::format("{}_e2ap.pcap", prefix); - f1ap.filename = fmt::format("{}_f1ap.pcap", prefix); - f1u.filename = fmt::format("{}_f1u.pcap", prefix); - rlc.filename = fmt::format("{}_rlc.pcap", prefix); - mac.filename = fmt::format("{}_mac.pcap", prefix); - } + /// When using the gNB app, there is no point in instantiating /// F1 pcaps twice. This function force disables them. /// TODO: revisit diff --git a/apps/units/flexible_du/flexible_du_application_unit.h b/apps/units/flexible_du/flexible_du_application_unit.h index fb3d35ff74..de5ed27180 100644 --- a/apps/units/flexible_du/flexible_du_application_unit.h +++ b/apps/units/flexible_du/flexible_du_application_unit.h @@ -43,6 +43,6 @@ class flexible_du_application_unit : public application_unit /// Different splits must provide an implementation of this free function so the applications can instantiate a flexible /// DU application unit. Only one of these implementations should be compiled, based on the DU_SPLIT_TYPE cmake /// definition. -std::unique_ptr create_flexible_du_application_unit(); +std::unique_ptr create_flexible_du_application_unit(std::string_view app_name); } // namespace srsran diff --git a/apps/units/flexible_du/split_6/split6_du_application_unit_impl.cpp b/apps/units/flexible_du/split_6/split6_du_application_unit_impl.cpp index ca89cfb5a7..26cb023445 100644 --- a/apps/units/flexible_du/split_6/split6_du_application_unit_impl.cpp +++ b/apps/units/flexible_du/split_6/split6_du_application_unit_impl.cpp @@ -20,6 +20,15 @@ using namespace srsran; +split6_du_application_unit_impl::split6_du_application_unit_impl(std::string_view app_name) +{ + unit_cfg.du_high_cfg.config.pcaps.e2ap.filename = fmt::format("/tmp/{}_e2ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1ap.filename = fmt::format("/tmp/{}_f1ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1u.filename = fmt::format("/tmp/{}_f1u.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.rlc.filename = fmt::format("/tmp/{}_rlc.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.mac.filename = fmt::format("/tmp/{}_mac.pcap", app_name); +} + void split6_du_application_unit_impl::on_loggers_registration() { register_split6_du_loggers(unit_cfg); diff --git a/apps/units/flexible_du/split_6/split6_du_application_unit_impl.h b/apps/units/flexible_du/split_6/split6_du_application_unit_impl.h index 7a62bab4c1..4dc3700082 100644 --- a/apps/units/flexible_du/split_6/split6_du_application_unit_impl.h +++ b/apps/units/flexible_du/split_6/split6_du_application_unit_impl.h @@ -20,6 +20,8 @@ namespace srsran { class split6_du_application_unit_impl : public flexible_du_application_unit { public: + explicit split6_du_application_unit_impl(std::string_view app_name); + // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; diff --git a/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.cpp b/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.cpp index f3d27d2841..3108259676 100644 --- a/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.cpp +++ b/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.cpp @@ -37,6 +37,15 @@ bool split_7_2_du_application_unit_impl::on_configuration_validation( return validate_split_7_2_du_unit_config(unit_cfg, available_cpus); } +split_7_2_du_application_unit_impl::split_7_2_du_application_unit_impl(std::string_view app_name) +{ + unit_cfg.du_high_cfg.config.pcaps.e2ap.filename = fmt::format("/tmp/{}_e2ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1ap.filename = fmt::format("/tmp/{}_f1ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1u.filename = fmt::format("/tmp/{}_f1u.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.rlc.filename = fmt::format("/tmp/{}_rlc.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.mac.filename = fmt::format("/tmp/{}_mac.pcap", app_name); +} + void split_7_2_du_application_unit_impl::on_parsing_configuration_registration(CLI::App& app) { configure_cli11_with_split_7_2_du_unit_config_schema(app, unit_cfg); @@ -47,9 +56,9 @@ du_unit split_7_2_du_application_unit_impl::create_flexible_du_unit(const du_uni return create_split_7_2_du(unit_cfg, dependencies); } -std::unique_ptr srsran::create_flexible_du_application_unit() +std::unique_ptr srsran::create_flexible_du_application_unit(std::string_view app_name) { - return std::make_unique(); + return std::make_unique(app_name); } void split_7_2_du_application_unit_impl::dump_config(YAML::Node& node) const diff --git a/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.h b/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.h index 9d874c0b92..5cb334e6d6 100644 --- a/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.h +++ b/apps/units/flexible_du/split_7_2/split_7_2_du_application_unit_impl.h @@ -19,6 +19,8 @@ namespace srsran { class split_7_2_du_application_unit_impl : public flexible_du_application_unit { public: + explicit split_7_2_du_application_unit_impl(std::string_view app_name); + // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; diff --git a/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.cpp b/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.cpp index 1773f85a58..4d6255ed4f 100644 --- a/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.cpp +++ b/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.cpp @@ -37,6 +37,15 @@ bool split_8_du_application_unit_impl::on_configuration_validation( return validate_split_8_du_unit_config(unit_cfg, available_cpus); } +split_8_du_application_unit_impl::split_8_du_application_unit_impl(std::string_view app_name) +{ + unit_cfg.du_high_cfg.config.pcaps.e2ap.filename = fmt::format("/tmp/{}_e2ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1ap.filename = fmt::format("/tmp/{}_f1ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1u.filename = fmt::format("/tmp/{}_f1u.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.rlc.filename = fmt::format("/tmp/{}_rlc.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.mac.filename = fmt::format("/tmp/{}_mac.pcap", app_name); +} + void split_8_du_application_unit_impl::on_parsing_configuration_registration(CLI::App& app) { configure_cli11_with_split_8_du_unit_config_schema(app, unit_cfg); @@ -47,9 +56,9 @@ du_unit split_8_du_application_unit_impl::create_flexible_du_unit(const du_unit_ return create_split_8_du(unit_cfg, dependencies); } -std::unique_ptr srsran::create_flexible_du_application_unit() +std::unique_ptr srsran::create_flexible_du_application_unit(std::string_view app_name) { - return std::make_unique(); + return std::make_unique(app_name); } void split_8_du_application_unit_impl::dump_config(YAML::Node& node) const diff --git a/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.h b/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.h index 8830a6f87a..149fed14f3 100644 --- a/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.h +++ b/apps/units/flexible_du/split_8/split_8_du_application_unit_impl.h @@ -19,6 +19,8 @@ namespace srsran { class split_8_du_application_unit_impl : public flexible_du_application_unit { public: + explicit split_8_du_application_unit_impl(std::string_view app_name); + // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.cpp b/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.cpp index e8f5f3d56a..9cca34e0a0 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.cpp @@ -34,6 +34,15 @@ bool dynamic_du_application_unit_impl::on_configuration_validation( return validate_dynamic_du_unit_config(unit_cfg, available_cpus); } +dynamic_du_application_unit_impl::dynamic_du_application_unit_impl(std::string_view app_name) +{ + unit_cfg.du_high_cfg.config.pcaps.e2ap.filename = fmt::format("/tmp/{}_e2ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1ap.filename = fmt::format("/tmp/{}_f1ap.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.f1u.filename = fmt::format("/tmp/{}_f1u.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.rlc.filename = fmt::format("/tmp/{}_rlc.pcap", app_name); + unit_cfg.du_high_cfg.config.pcaps.mac.filename = fmt::format("/tmp/{}_mac.pcap", app_name); +} + void dynamic_du_application_unit_impl::on_parsing_configuration_registration(CLI::App& app) { configure_cli11_with_dynamic_du_unit_config_schema(app, unit_cfg); @@ -44,9 +53,9 @@ du_unit dynamic_du_application_unit_impl::create_flexible_du_unit(const du_unit_ return create_dynamic_du(unit_cfg, dependencies); } -std::unique_ptr srsran::create_flexible_du_application_unit() +std::unique_ptr srsran::create_flexible_du_application_unit(std::string_view app_name) { - return std::make_unique(); + return std::make_unique(app_name); } void dynamic_du_application_unit_impl::dump_config(YAML::Node& node) const diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.h b/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.h index fee4136424..e023cd3347 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.h +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_application_unit_impl.h @@ -21,6 +21,8 @@ namespace srsran { class dynamic_du_application_unit_impl : public flexible_du_application_unit { public: + explicit dynamic_du_application_unit_impl(std::string_view app_name); + // See interface for documentation. void on_parsing_configuration_registration(CLI::App& app) override; From 9815696b5bbd937c44486a43bb96218147f9c9d0 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 1 Oct 2024 17:23:41 +0200 Subject: [PATCH 22/32] SCHED: Avoid two instances of a double map lookup in the paging scheduler --- lib/scheduler/common_scheduling/paging_scheduler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/common_scheduling/paging_scheduler.cpp b/lib/scheduler/common_scheduling/paging_scheduler.cpp index 77eec20904..3710969b1a 100644 --- a/lib/scheduler/common_scheduling/paging_scheduler.cpp +++ b/lib/scheduler/common_scheduling/paging_scheduler.cpp @@ -113,9 +113,7 @@ void paging_scheduler::run_slot(cell_resource_allocator& res_grid) while (new_paging_notifications.try_pop(new_pg_info)) { // Check whether Paging information is already present or not. i.e. tackle repeated Paging attempt from upper // layers. - if (paging_pending_ues.find(new_pg_info.paging_identity) == paging_pending_ues.cend()) { - paging_pending_ues[new_pg_info.paging_identity] = ue_paging_info{.info = new_pg_info, .retry_count = 0}; - } + paging_pending_ues.try_emplace(new_pg_info.paging_identity, ue_paging_info{.info = new_pg_info, .retry_count = 0}); } // NOTE: @@ -140,7 +138,7 @@ void paging_scheduler::run_slot(cell_resource_allocator& res_grid) // Check for maximum paging retries. auto it = paging_pending_ues.begin(); while (it != paging_pending_ues.end()) { - if (paging_pending_ues[it->first].retry_count >= expert_cfg.pg.max_paging_retries) { + if (it->second.retry_count >= expert_cfg.pg.max_paging_retries) { it = paging_pending_ues.erase(it); } else { ++it; From 1eaad26485c641211dff6a8b8cb2a14a9d239acb Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 1 Oct 2024 17:50:21 +0200 Subject: [PATCH 23/32] GTPU: Remove some double map lookups --- lib/gtpu/gtpu_demux_impl.cpp | 38 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/gtpu/gtpu_demux_impl.cpp b/lib/gtpu/gtpu_demux_impl.cpp index 7b6040f851..33eff3cc6c 100644 --- a/lib/gtpu/gtpu_demux_impl.cpp +++ b/lib/gtpu/gtpu_demux_impl.cpp @@ -25,48 +25,51 @@ bool gtpu_demux_impl::add_tunnel(gtpu_teid_t te gtpu_tunnel_common_rx_upper_layer_interface* tunnel) { std::lock_guard guard(map_mutex); - if (teid_to_tunnel.find(teid) != teid_to_tunnel.end()) { + auto it = teid_to_tunnel.try_emplace(teid, gtpu_demux_tunnel_ctx_t{&tunnel_exec, tunnel}); + if (not it.second) { logger.error("Tunnel already exists. teid={}", teid); return false; } + logger.info("Tunnel added. teid={}", teid); - teid_to_tunnel[teid] = {&tunnel_exec, tunnel}; return true; } bool gtpu_demux_impl::remove_tunnel(gtpu_teid_t teid) { std::lock_guard guard(map_mutex); - if (teid_to_tunnel.find(teid) == teid_to_tunnel.end()) { + auto it = teid_to_tunnel.find(teid); + if (it == teid_to_tunnel.end()) { logger.error("Tunnel not found. teid={}", teid); return false; } + logger.info("Tunnel removed. teid={}", teid); - teid_to_tunnel.erase(teid); + teid_to_tunnel.erase(it); return true; } void gtpu_demux_impl::handle_pdu(byte_buffer pdu, const sockaddr_storage& src_addr) { uint32_t read_teid = 0x01; // default to test DRB - if (!cfg.test_mode) { - if (!gtpu_read_teid(read_teid, pdu, logger)) { + if (not cfg.test_mode) { + if (not gtpu_read_teid(read_teid, pdu, logger)) { logger.error("Failed to read TEID from GTP-U PDU. pdu_len={}", pdu.length()); return; } } - gtpu_teid_t teid{read_teid}; std::lock_guard guard(map_mutex); - const auto& it = teid_to_tunnel.find(teid); + + gtpu_teid_t teid{read_teid}; + auto it = teid_to_tunnel.find(teid); if (it == teid_to_tunnel.end()) { logger.info("Dropped GTP-U PDU, tunnel not found. teid={}", teid); return; } - auto fn = [this, teid, p = std::move(pdu), src_addr]() mutable { handle_pdu_impl(teid, std::move(p), src_addr); }; - - if (not it->second.tunnel_exec->defer(std::move(fn))) { + if (not it->second.tunnel_exec->defer( + [this, teid, p = std::move(pdu), src_addr]() mutable { handle_pdu_impl(teid, std::move(p), src_addr); })) { if (not cfg.warn_on_drop) { logger.info("Dropped GTP-U PDU, queue is full. teid={}", teid); } else { @@ -90,19 +93,18 @@ void gtpu_demux_impl::handle_pdu_impl(gtpu_teid_t teid, byte_buffer pdu, const s gtpu_tunnel_common_rx_upper_layer_interface* tunnel = nullptr; { - /// Get GTP-U tunnel. We lookup the tunnel again, as the tunnel could have been - /// removed between the time PDU processing was enqueued and the time we actually - /// run the task. + // Get GTP-U tunnel. + // We lookup the tunnel again, as the tunnel could have been removed between the time PDU processing was enqueued + // and the time we actually run the task. std::lock_guard guard(map_mutex); - const auto& it = teid_to_tunnel.find(teid); + auto it = teid_to_tunnel.find(teid); if (it == teid_to_tunnel.end()) { logger.info("Dropped GTP-U PDU, tunnel not found. teid={}", teid); return; } tunnel = it->second.tunnel; } - // Forward entire PDU to the tunnel - // As removal happens in the same thread as handling the PDU, we no longer - // need the lock. + // Forward entire PDU to the tunnel. + // As removal happens in the same thread as handling the PDU, we no longer need the lock. tunnel->handle_pdu(std::move(pdu), src_addr); } From 340050cfd17fda138894d5605f9d21ff2fa12392 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 27 Sep 2024 17:49:11 +0200 Subject: [PATCH 24/32] band_helper: fix UL ARFCN derivation Signed-off-by: Carlo Galiotto --- lib/ran/band_helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index 0c888aa2e3..903f7ce8ea 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -815,7 +815,7 @@ uint32_t srsran::band_helper::get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn, std: // Derive UL ARFCN for FDD bands. for (const nr_band_raster& b_it : nr_band_table) { - if (b_it.band == get_band_from_dl_arfcn(dl_arfcn)) { + if (b_it.band == operating_band) { const uint32_t offset = (dl_arfcn - b_it.dl_nref_first) / b_it.dl_nref_step; return (b_it.ul_nref_first + offset * b_it.ul_nref_step); } From 4180cb14ea839ddaccbb67716ca06fb7e42a4200 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 27 Sep 2024 18:49:29 +0200 Subject: [PATCH 25/32] du, band_helper: add option to set UL ARFCN Signed-off-by: Carlo Galiotto --- .../flexible_du/du_high/du_high_config.h | 4 ++ .../du_high/du_high_config_cli11_schema.cpp | 1 + .../du_high/du_high_config_translators.cpp | 1 + .../du_high/du_high_config_validator.cpp | 14 ++++- include/srsran/ran/band_helper.h | 8 +++ .../config/cell_config_builder_params.h | 5 ++ lib/ran/band_helper.cpp | 58 +++++++++++++++---- .../config/serving_cell_config_factory.cpp | 8 ++- 8 files changed, 82 insertions(+), 17 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config.h b/apps/units/flexible_du/du_high/du_high_config.h index 59b9af2d19..7dab4e2397 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -547,6 +547,10 @@ struct du_high_unit_base_cell_config { std::optional sector_id; /// DL ARFCN of "F_REF", which is the RF reference frequency, as per TS 38.104, Section 5.4.2.1. unsigned dl_f_ref_arfcn = 536020; + /// UL ARFCN of "F_REF", which is the RF reference frequency, as per TS 38.104, Section 5.4.2.1. + /// \remark Only relevant for FDD bands. If set with TDD bands, it will be ignored. + /// For FDD bands, if not set, the UL ARFCN will be computed automatically. + std::optional ul_f_ref_arfcn = std::nullopt; /// Common subcarrier spacing for the entire resource grid. It must be supported by the band SS raster. subcarrier_spacing common_scs = subcarrier_spacing::kHz15; /// NR band. diff --git a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp index 3a4624741d..5fe73287f4 100644 --- a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp @@ -1114,6 +1114,7 @@ static void configure_cli11_common_cell_args(CLI::App& app, du_high_unit_base_ce ->capture_default_str() ->check(CLI::Range(0U, (1U << 14) - 1U)); add_option(app, "--dl_arfcn", cell_params.dl_f_ref_arfcn, "Downlink ARFCN")->capture_default_str(); + add_option(app, "--ul_arfcn", cell_params.ul_f_ref_arfcn, "Uplink ARFCN")->capture_default_str(); add_auto_enum_option(app, "--band", cell_params.band, "NR band"); add_option_function( app, diff --git a/apps/units/flexible_du/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/du_high/du_high_config_translators.cpp index fba3b05b3e..da5ff59bf2 100644 --- a/apps/units/flexible_du/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_translators.cpp @@ -230,6 +230,7 @@ std::vector srsran::generate_du_cell_config(const du_hig param.scs_common = base_cell.common_scs; param.channel_bw_mhz = base_cell.channel_bw_mhz; param.dl_f_ref_arfcn = base_cell.dl_f_ref_arfcn; + param.ul_f_ref_arfcn = base_cell.ul_f_ref_arfcn; param.band = *base_cell.band; // Enable CSI-RS if the PDSCH mcs is dynamic (min_ue_mcs != max_ue_mcs). param.csi_rs_enabled = base_cell.csi_cfg.csi_rs_enabled; diff --git a/apps/units/flexible_du/du_high/du_high_config_validator.cpp b/apps/units/flexible_du/du_high/du_high_config_validator.cpp index 24993aa40f..0a98910599 100644 --- a/apps/units/flexible_du/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_validator.cpp @@ -601,7 +601,7 @@ static bool validate_tdd_ul_dl_unit_config(const du_high_unit_tdd_ul_dl_config& return true; } -static bool validate_dl_arfcn_and_band(const du_high_unit_base_cell_config& config) +static bool validate_dl_ul_arfcn_and_band(const du_high_unit_base_cell_config& config) { nr_band band = config.band.has_value() ? config.band.value() : band_helper::get_band_from_dl_arfcn(config.dl_f_ref_arfcn); @@ -643,7 +643,7 @@ static bool validate_dl_arfcn_and_band(const du_high_unit_base_cell_config& conf return false; } - // Check whether the DL-ARFCN is within the band and follows the Raster step. + // Check whether the DL-ARFCN (and optionally the UL-ARFCN) is within the band and follows the Raster step. if (config.band.has_value()) { error_type ret = band_helper::is_dl_arfcn_valid_given_band( *config.band, config.dl_f_ref_arfcn, config.common_scs, config.channel_bw_mhz); @@ -651,6 +651,14 @@ static bool validate_dl_arfcn_and_band(const du_high_unit_base_cell_config& conf fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); return false; } + if (config.ul_f_ref_arfcn.has_value()) { + ret = + band_helper::is_ul_arfcn_valid_given_band(*config.band, config.ul_f_ref_arfcn.value(), config.channel_bw_mhz); + if (not ret.has_value()) { + fmt::print("Invalid UL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); + return false; + } + } } else { if (band == nr_band::invalid) { fmt::print("Invalid DL ARFCN={}. Cause: Could not find a valid band.\n", config.dl_f_ref_arfcn); @@ -757,7 +765,7 @@ static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& fmt::print("Maximum Channel BW with SCS common 120kHz is 400MHz.\n"); return false; } - if (!validate_dl_arfcn_and_band(config)) { + if (!validate_dl_ul_arfcn_and_band(config)) { return false; } diff --git a/include/srsran/ran/band_helper.h b/include/srsran/ran/band_helper.h index bbf71edca5..033f3ac62a 100644 --- a/include/srsran/ran/band_helper.h +++ b/include/srsran/ran/band_helper.h @@ -85,6 +85,14 @@ error_type is_dl_arfcn_valid_given_band(nr_band band, subcarrier_spacing scs, bs_channel_bandwidth bw = bs_channel_bandwidth::MHz10); +/// \brief Checks whether an Uplink ARFCN is valid for a given band. +/// \param[in] band Given NR band. +/// \param[in] arfcn_f_ref Given Uplink ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. +/// \param[in] bw Channel Bandwidth in MHz, which is required to validate some bands' ARFCN values. +/// \return If the UL ARFCN is invalid for the band, a std::string value is returned with the reason. +error_type +is_ul_arfcn_valid_given_band(nr_band band, uint32_t arfcn_f_ref, bs_channel_bandwidth bw = bs_channel_bandwidth::MHz10); + /// @brief Get the respective UL ARFCN of a DL ARFCN. /// /// For paired spectrum (FDD) the function returns the respective ARFCN in the same band. diff --git a/include/srsran/scheduler/config/cell_config_builder_params.h b/include/srsran/scheduler/config/cell_config_builder_params.h index b4d4c30b16..de26261d38 100644 --- a/include/srsran/scheduler/config/cell_config_builder_params.h +++ b/include/srsran/scheduler/config/cell_config_builder_params.h @@ -31,6 +31,11 @@ struct cell_config_builder_params { /// This ARFCN represents "f_ref" for DL, as per TS 38.104, Section 5.4.2.1. As per TS 38.104, Section 5.4.2.2, /// "f_ref" maps to the central frequency of the band. unsigned dl_f_ref_arfcn = 365000; + /// This ARFCN represents "f_ref" for UL, as per TS 38.104, Section 5.4.2.1. As per TS 38.104, Section 5.4.2.2, + /// "f_ref" maps to the central frequency of the band. + /// \remark Only relevant for FDD bands. + /// If set, this value has been set by the application user. + std::optional ul_f_ref_arfcn = std::nullopt; /// NR operating band<\em>, as per Table 5.2-1 and 5.2-2, TS 38.104. If not specified, a valid band for the /// provided DL ARFCN is automatically derived. std::optional band; diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index 903f7ce8ea..4cbacec89d 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -56,7 +56,7 @@ struct nr_band_raster { // NOTE: FR2 bands have two different Freq raster, we only consider raster 120kHz. const uint32_t nof_nr_DL_bands = 83; static constexpr std::array nr_band_table = {{ - // clang-format off + // clang-format off {nr_band::n1, delta_freq_raster::kHz100, 384000, 20, 396000, 422000, 20, 434000}, {nr_band::n2, delta_freq_raster::kHz100, 370000, 20, 382000, 386000, 20, 398000}, {nr_band::n3, delta_freq_raster::kHz100, 342000, 20, 357000, 361000, 20, 376000}, @@ -150,7 +150,7 @@ struct nr_operating_band { }; static const uint32_t nof_nr_operating_band = 68; static constexpr std::array nr_operating_bands = {{ - // clang-format off + // clang-format off {nr_band::n1, duplex_mode::FDD}, {nr_band::n2, duplex_mode::FDD}, {nr_band::n3, duplex_mode::FDD}, @@ -456,7 +456,7 @@ static bool is_valid_raster_param(const nr_raster_params& raster) // Validates band n28, which has an additional ARFCN value to the given interval, as per Table 5.4.2.3-1, TS 38.104, // version 17.8.0. -static error_type validate_band_n28(uint32_t arfcn, bs_channel_bandwidth bw) +static error_type validate_band_n28(uint32_t arfcn, bs_channel_bandwidth bw, bool is_dl = true) { const nr_band_raster band_raster = fetch_band_raster(nr_band::n28, {}); if (band_raster.band == srsran::nr_band::invalid) { @@ -464,22 +464,25 @@ static error_type validate_band_n28(uint32_t arfcn, bs_channel_band } // Try first if the ARFCN matches any value of the interval for 100kHz channel raster. - if (arfcn >= band_raster.dl_nref_first and arfcn <= band_raster.dl_nref_last and - ((arfcn - band_raster.dl_nref_first) % band_raster.dl_nref_step) == 0) { + uint32_t nref_first = is_dl ? band_raster.dl_nref_first : band_raster.ul_nref_first; + uint32_t nref_last = is_dl ? band_raster.dl_nref_last : band_raster.ul_nref_last; + uint32_t nref_step = is_dl ? band_raster.dl_nref_step : band_raster.ul_nref_step; + if (arfcn >= nref_first and arfcn <= nref_last and ((arfcn - nref_first) % nref_step) == 0) { return error_type{}; } // Extra ARFCN value as per Table 5.4.2.3-1, TS 38.104, version 17.8.0 (see NOTE 4 in the table). - const uint32_t dl_arfnc_40MHz = 155608U; - if (bw == srsran::bs_channel_bandwidth::MHz40 and arfcn == dl_arfnc_40MHz) { + const uint32_t arfnc_40MHz = is_dl ? 155608U : 144608U; + if (bw == srsran::bs_channel_bandwidth::MHz40 and arfcn == arfnc_40MHz) { return error_type{}; } return make_unexpected( - fmt::format("DL ARFCN must be within the interval [{},{}], in steps of {}, for the chosen band", - band_raster.dl_nref_first, - band_raster.dl_nref_last, - band_raster.dl_nref_step)); + fmt::format("{} ARFCN must be within the interval [{},{}], in steps of {}, for the chosen band", + is_dl ? "DL" : "UL", + nref_first, + nref_last, + nref_step)); } // Validates band n46, whose valid ARFCN values depend on the channel BW, as per Table 5.4.2.3-1, TS 38.104, @@ -743,7 +746,7 @@ error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_ban { // Validates first the bands with non-standard ARFCN values. if (band == nr_band::n28) { - return validate_band_n28(arfcn_f_ref, bw); + return validate_band_n28(arfcn_f_ref, bw, true); } if (band == nr_band::n46) { @@ -796,6 +799,37 @@ error_type srsran::band_helper::is_dl_arfcn_valid_given_band(nr_ban return make_unexpected(fmt::format("Band {} is not valid", band)); } +error_type +srsran::band_helper::is_ul_arfcn_valid_given_band(nr_band band, uint32_t arfcn_f_ref, bs_channel_bandwidth bw) +{ + if (get_duplex_mode(band) != duplex_mode::FDD) { + return {}; + } + + // Validates first the bands with non-standard ARFCN values. + if (band == nr_band::n28) { + return validate_band_n28(arfcn_f_ref, bw, false); + } + + // Assume standard Delta freq raster of 100kHz. + const delta_freq_raster band_delta_freq_raster = delta_freq_raster::kHz100; + + for (const nr_band_raster& raster_band : nr_band_table) { + if (raster_band.band == band and raster_band.delta_f_rast == band_delta_freq_raster) { + if (arfcn_f_ref >= raster_band.ul_nref_first and arfcn_f_ref <= raster_band.ul_nref_last and + ((arfcn_f_ref - raster_band.ul_nref_first) % raster_band.ul_nref_step) == 0) { + return {}; + } + return make_unexpected( + fmt::format("UL ARFCN must be within the interval [{},{}], in steps of {}, for the chosen band", + raster_band.ul_nref_first, + raster_band.ul_nref_last, + raster_band.ul_nref_step)); + } + } + return make_unexpected(fmt::format("Band {} is not valid", band)); +} + uint32_t srsran::band_helper::get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn, std::optional band) { // NOTE: The procedure implemented in this function is implementation-defined. diff --git a/lib/scheduler/config/serving_cell_config_factory.cpp b/lib/scheduler/config/serving_cell_config_factory.cpp index 3d19236ec2..1e399a308f 100644 --- a/lib/scheduler/config/serving_cell_config_factory.cpp +++ b/lib/scheduler/config/serving_cell_config_factory.cpp @@ -89,7 +89,9 @@ static carrier_configuration make_default_carrier_configuration(const cell_confi cfg.arfcn_f_ref = params.dl_f_ref_arfcn; cfg.nof_ant = params.nof_dl_ports; } else { - cfg.arfcn_f_ref = band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, cfg.band); + cfg.arfcn_f_ref = params.ul_f_ref_arfcn.has_value() + ? params.ul_f_ref_arfcn.value() + : band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, cfg.band); cfg.nof_ant = 1; } const min_channel_bandwidth min_channel_bw = band_helper::get_min_channel_bw(cfg.band, params.scs_common); @@ -334,7 +336,9 @@ srsran::config_helpers::make_default_ul_config_common(const cell_config_builder_ { ul_config_common cfg{}; // This is the ARFCN of the UL f_ref, as per TS 38.104, Section 5.4.2.1. - const uint32_t ul_arfcn = band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, params.band); + const uint32_t ul_arfcn = params.ul_f_ref_arfcn.has_value() + ? params.ul_f_ref_arfcn.value() + : band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, params.band); const double ul_absolute_freq_point_a = band_helper::get_abs_freq_point_a_from_f_ref( band_helper::nr_arfcn_to_freq(ul_arfcn), params.cell_nof_crbs, params.scs_common); // \c absolute_freq_point_a needs to be expressed as in ARFCN, as per \c absoluteFrequencyPointA definition in 38.211, From 97a2ddd13634e135734c7fea572875d6f8dda7d3 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 30 Sep 2024 11:32:43 +0200 Subject: [PATCH 26/32] band helper: add unittest for ARFCN validators Signed-off-by: Carlo Galiotto --- include/srsran/ran/band_helper.h | 2 +- lib/ran/band_helper.cpp | 72 +- tests/unittests/ran/band_helper_test.cpp | 1060 ++++++++++++++-------- 3 files changed, 696 insertions(+), 438 deletions(-) diff --git a/include/srsran/ran/band_helper.h b/include/srsran/ran/band_helper.h index 033f3ac62a..60562dc79f 100644 --- a/include/srsran/ran/band_helper.h +++ b/include/srsran/ran/band_helper.h @@ -88,7 +88,7 @@ error_type is_dl_arfcn_valid_given_band(nr_band band, /// \brief Checks whether an Uplink ARFCN is valid for a given band. /// \param[in] band Given NR band. /// \param[in] arfcn_f_ref Given Uplink ARFCN of \c F_REF, as per TS 38.104, Section 5.4.2.1. -/// \param[in] bw Channel Bandwidth in MHz, which is required to validate some bands' ARFCN values. +/// \param[in] bw Channel Bandwidth in MHz, which is required only to validate n28. /// \return If the UL ARFCN is invalid for the band, a std::string value is returned with the reason. error_type is_ul_arfcn_valid_given_band(nr_band band, uint32_t arfcn_f_ref, bs_channel_bandwidth bw = bs_channel_bandwidth::MHz10); diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index 4cbacec89d..01ab1ed8e1 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -51,7 +51,7 @@ struct nr_band_raster { // lower-bound and upper-bound. (FDD, TDD or SDL). // // NOTE: It only includes FDD, TDD, and SDL bands. -// NOTE: Band 2 is a subset of band 25 +// NOTE: Band 2 is a subset of band 25. // NOTE: Band 41 has two different Freq raster, we only consider raster 15kHz. // NOTE: FR2 bands have two different Freq raster, we only consider raster 120kHz. const uint32_t nof_nr_DL_bands = 83; @@ -81,6 +81,9 @@ static constexpr std::array nr_band_table = { {nr_band::n40, delta_freq_raster::kHz100, 460000, 20, 480000, 460000, 20, 480000}, {nr_band::n41, delta_freq_raster::kHz15, 499200, 3, 537999, 499200, 3, 537999}, {nr_band::n41, delta_freq_raster::kHz30, 499200, 6, 537996, 499200, 6, 537996}, + // Band n46 has a raster definded in Table 5.4.2.3-1, TS 38.104, but according to the table notes, only a few ARFCN + // values are valid. This range is reported below for completeness, but only the applicable ARFCN given in the + // notes will be used. {nr_band::n46, delta_freq_raster::kHz15, 743334, 1, 795000, 743334, 1, 795000}, {nr_band::n48, delta_freq_raster::kHz15, 636667, 1, 646666, 636667, 1, 646666}, {nr_band::n48, delta_freq_raster::kHz30, 636668, 2, 646666, 636668, 2, 646666}, @@ -117,12 +120,18 @@ static constexpr std::array nr_band_table = { {nr_band::n93, delta_freq_raster::kHz100, 176000, 20, 183000, 285400, 20, 286400}, {nr_band::n94, delta_freq_raster::kHz100, 176000, 20, 183000, 286400, 20, 303400}, {nr_band::n95, delta_freq_raster::kHz100, 402000, 20, 405000, 0, 0, 0}, + // Band n96 has a raster definded in Table 5.4.2.3-1, TS 38.104, but according to the table notes, only a few ARFCN + // values are valid. This range is reported below for completeness, but only the applicable ARFCN given in the + // notes will be used. {nr_band::n96, delta_freq_raster::kHz15, 795000, 1, 875000, 795000, 1, 875000}, {nr_band::n97, delta_freq_raster::kHz100, 460000, 20, 480000, 0, 0, 0}, {nr_band::n98, delta_freq_raster::kHz100, 376000, 20, 384000, 0, 0, 0}, {nr_band::n99, delta_freq_raster::kHz100, 325300, 20, 332100, 0, 0, 0}, {nr_band::n100, delta_freq_raster::kHz100, 174880, 20, 176000, 183880, 20, 185000}, {nr_band::n101, delta_freq_raster::kHz100, 380000, 20, 382000, 380000, 20, 382000}, + // Band n102 has a raster definded in Table 5.4.2.3-1, TS 38.104, but according to the table notes, only a few + // ARFCN values are valid. This range is reported below for completeness, but only the applicable ARFCN given in + // the notes will be used. {nr_band::n102, delta_freq_raster::kHz15, 796334, 1 , 828333, 796334, 1, 828333}, {nr_band::n104, delta_freq_raster::kHz15, 828334, 1 , 875000, 828334, 1, 875000}, {nr_band::n104, delta_freq_raster::kHz30, 828334, 2 , 875000, 828334, 2, 875000}, @@ -446,12 +455,8 @@ static nr_raster_params get_raster_params(double freq) static bool is_valid_raster_param(const nr_raster_params& raster) { - for (const nr_raster_params& fr : nr_fr_params) { - if (fr == raster) { - return true; - } - } - return false; + return std::any_of( + nr_fr_params.begin(), nr_fr_params.end(), [raster](const nr_raster_params& fr) { return fr == raster; }); } // Validates band n28, which has an additional ARFCN value to the given interval, as per Table 5.4.2.3-1, TS 38.104, @@ -489,41 +494,35 @@ static error_type validate_band_n28(uint32_t arfcn, bs_channel_band // version 17.8.0. static error_type validate_band_n46(uint32_t arfcn, bs_channel_bandwidth bw) { - const std::array n46_b_10_dlarfnc = {782000, 788668}; - const std::array n46_b_20_dlarfnc = { + constexpr std::array n46_b_10_dlarfnc = {782000, 788668}; + constexpr std::array n46_b_20_dlarfnc = { // clang-format off 744000, 745332, 746668, 748000, 749332, 750668, 752000, 753332, 754668, 756000, 765332, 766668, 768000, 769332, 770668, 772000, 773332, 774668, 776000, 777332, 778668, 780000, 781332, 783000, 784332, 785668, 787000, 788332, 789668, 791000, 792332, 793668 // clang-format on }; - const std::array n46_b_40_dlarfnc = { + constexpr std::array n46_b_40_dlarfnc = { // clang-format off 744668, 746000, 748668, 751332, 754000, 755332, 766000, 767332, 770000, 772668, 775332, 778000, 780668, 783668, 786332, 787668, 790332, 793000 // clang-format on }; - const std::array n46_b_60_dlarfnc = { + constexpr std::array n46_b_60_dlarfnc = { // clang-format off 745332, 746668, 748000, 752000, 753332, 754668, 766668, 768000, 769332, 773332, 774668, 778668, 780000, 784332, 785668, 791000, 792332 // clang-format on }; - const std::array n46_b_80_dlarfnc = { + constexpr std::array n46_b_80_dlarfnc = { 746000, 747332, 752668, 754000, 767332, 768668, 774000, 779332, 785000, 791668}; - const std::array n46_b_100_dlarfnc = {746668, 753332, 768000, 791000}; - - const nr_band_raster band_raster = fetch_band_raster(nr_band::n46, {}); - if (band_raster.band == srsran::nr_band::invalid or arfcn < band_raster.dl_nref_first or - arfcn > band_raster.dl_nref_last) { - return make_unexpected(fmt::format("Band n46 channel raster not found")); - } + constexpr std::array n46_b_100_dlarfnc = {746668, 753332, 768000, 791000}; + const char* error_msg = {"Only a restricted set of DL-ARFCN values are allowed in band n46"}; auto dl_arfcn_exist = [](span band_list, unsigned dl_arfcn) { return std::find(band_list.begin(), band_list.end(), dl_arfcn) != band_list.end(); }; - const char* error_msg = {"Only a restricted set of DL-ARFCN values are allowed in band n46"}; switch (bw) { case bs_channel_bandwidth::MHz10: { return dl_arfcn_exist(span(n46_b_10_dlarfnc), arfcn) ? error_type{} @@ -558,7 +557,7 @@ static error_type validate_band_n46(uint32_t arfcn, bs_channel_band // version 17.8.0. static error_type validate_band_n96(uint32_t arfcn, bs_channel_bandwidth bw) { - const std::array b_20_dlarfnc = { + constexpr std::array b_20_dlarfnc = { // clang-format off 797000, 798332, 799668, 801000, 802332, 803668, 805000, 806332, 807668, 809000, 810332, 811668, 813000, 814332, 815668, 817000, 818332, 819668, 821000, 822332, 823668, 825000, 826332, 827668, 829000, 830332, 831668, 833000, @@ -567,38 +566,32 @@ static error_type validate_band_n96(uint32_t arfcn, bs_channel_band 871668, 873000, 874332 // clang-format on }; - const std::array b_40_dlarfnc = { + constexpr std::array b_40_dlarfnc = { // clang-format off 797668, 800332, 803000, 805668, 808332, 811000, 813668, 816332, 819000, 821668, 824332, 827000, 829668, 832332, 835000, 837668, 840332, 843000, 845668, 848332, 851000, 853668, 856332, 859000, 861668, 864332, 867000, 869668, 872332 // clang-format on }; - const std::array b_60_dlarfnc = { + constexpr std::array b_60_dlarfnc = { // clang-format off 798332, 799668, 803668, 805000, 809000, 810332, 814332, 815668, 819668, 821000, 825000, 826332, 830332, 831668, 835668, 837000, 841000, 842332, 846332, 847668, 851668, 853000, 857000, 858332, 862332, 863668, 867668, 869000, 873000 // clang-format on }; - const std::array b_80_dlarfnc = { + constexpr std::array b_80_dlarfnc = { // clang-format off 799000, 804332, 809668, 815000, 820332, 825668, 831000, 836332, 841668, 847000, 852332, 857668, 863000, 868332 // clang-format on }; - const std::array b_100_dlarfnc = { + constexpr std::array b_100_dlarfnc = { // clang-format off 799668, 803668, 810332, 814332, 821000, 825000, 831668, 835668, 842332, 846332, 853000, 857000, 863668, 867668, 869000, 870332, 871668 // clang-format on }; - const nr_band_raster band_raster = fetch_band_raster(nr_band::n96, {}); - if (band_raster.band == srsran::nr_band::invalid or arfcn < band_raster.dl_nref_first or - arfcn > band_raster.dl_nref_last) { - return make_unexpected(fmt::format("Band n96 channel raster not found")); - } - auto dl_arfcn_exist = [](span band_list, unsigned dl_arfcn) { return std::find(band_list.begin(), band_list.end(), dl_arfcn) != band_list.end(); }; @@ -634,24 +627,24 @@ static error_type validate_band_n96(uint32_t arfcn, bs_channel_band // version 17.8.0. static error_type validate_band_n102(uint32_t arfcn, bs_channel_bandwidth bw) { - const std::array b_20_dlarfnc = { + constexpr std::array b_20_dlarfnc = { // clang-format off 797000, 798332, 799668, 801000, 802332, 803668, 805000, 806332, 807668, 809000, 810332, 811668, 813000, 814332, 815668, 817000, 818332, 819668, 821000, 822332, 823668, 825000, 826332, 827668 // clang-format on }; - const std::array b_40_dlarfnc = { + constexpr std::array b_40_dlarfnc = { // clang-format off 797668, 800332, 803000, 805668, 808332, 811000, 813668, 816332, 819000, 821668, 824332, 827000 // clang-format on }; - const std::array b_60_dlarfnc = { + constexpr std::array b_60_dlarfnc = { // clang-format off 798332, 799668, 803668, 805000, 809000, 810332, 814332, 815668, 819668, 821000, 825000, 826332 // clang-format on }; - const std::array b_80_dlarfnc = {799000, 804332, 809668, 815000, 820332, 825668}; - const std::array b_100_dlarfnc = {799668, 803668, 810332, 814332, 821000, 825000}; + constexpr std::array b_80_dlarfnc = {799000, 804332, 809668, 815000, 820332, 825668}; + constexpr std::array b_100_dlarfnc = {799668, 803668, 810332, 814332, 821000, 825000}; const nr_band_raster band_raster = fetch_band_raster(nr_band::n102, {}); if (band_raster.band == srsran::nr_band::invalid or arfcn < band_raster.dl_nref_first or @@ -850,8 +843,11 @@ uint32_t srsran::band_helper::get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn, std: // Derive UL ARFCN for FDD bands. for (const nr_band_raster& b_it : nr_band_table) { if (b_it.band == operating_band) { - const uint32_t offset = (dl_arfcn - b_it.dl_nref_first) / b_it.dl_nref_step; - return (b_it.ul_nref_first + offset * b_it.ul_nref_step); + const uint32_t offset = (dl_arfcn - b_it.dl_nref_first) / b_it.dl_nref_step; + const uint32_t candidate_ul_arfcn = b_it.ul_nref_first + offset * b_it.ul_nref_step; + // For band n65, n66, n70, n92, n94, the UL spectrum is smaller than the corresponding DL spectrum, therefore we + // need to cap the UL ARFCN to its upper-bound. + return std::min(candidate_ul_arfcn, b_it.ul_nref_last); } } diff --git a/tests/unittests/ran/band_helper_test.cpp b/tests/unittests/ran/band_helper_test.cpp index c9f2512359..bad41ff8da 100644 --- a/tests/unittests/ran/band_helper_test.cpp +++ b/tests/unittests/ran/band_helper_test.cpp @@ -8,108 +8,129 @@ * */ +#include "srsran/adt/span.h" #include "srsran/ran/band_helper.h" #include "srsran/ran/bs_channel_bandwidth.h" #include "srsran/ran/duplex_mode.h" #include "srsran/ran/subcarrier_spacing.h" +#include "srsran/support/test_utils.h" #include using namespace srsran; +using namespace band_helper; TEST(test_get_band_from_arfcn, mix_bands) { - ASSERT_NE(nr_band::invalid, band_helper::get_band_from_dl_arfcn(530000U)); - ASSERT_EQ(nr_band::invalid, band_helper::get_band_from_dl_arfcn(5300000U)); - ASSERT_EQ(nr_band::n1, band_helper::get_band_from_dl_arfcn(423000U)); - ASSERT_EQ(nr_band::n3, band_helper::get_band_from_dl_arfcn(365000U)); - ASSERT_EQ(nr_band::n5, band_helper::get_band_from_dl_arfcn(175000U)); - ASSERT_EQ(nr_band::n7, band_helper::get_band_from_dl_arfcn(530000U)); - ASSERT_EQ(nr_band::n25, band_helper::get_band_from_dl_arfcn(399000U)); - ASSERT_EQ(nr_band::n34, band_helper::get_band_from_dl_arfcn(404000U)); - ASSERT_EQ(nr_band::n38, band_helper::get_band_from_dl_arfcn(515000U)); - ASSERT_EQ(nr_band::n41, band_helper::get_band_from_dl_arfcn(499902U)); - ASSERT_EQ(nr_band::n41, band_helper::get_band_from_dl_arfcn(504000U)); - ASSERT_EQ(nr_band::n50, band_helper::get_band_from_dl_arfcn(286500U)); - ASSERT_EQ(nr_band::n51, band_helper::get_band_from_dl_arfcn(285500U)); - ASSERT_EQ(nr_band::n70, band_helper::get_band_from_dl_arfcn(400000U)); - ASSERT_EQ(nr_band::n77, band_helper::get_band_from_dl_arfcn(630500U)); + ASSERT_NE(nr_band::invalid, get_band_from_dl_arfcn(530000U)); + ASSERT_EQ(nr_band::invalid, get_band_from_dl_arfcn(5300000U)); + ASSERT_EQ(nr_band::n1, get_band_from_dl_arfcn(423000U)); + ASSERT_EQ(nr_band::n3, get_band_from_dl_arfcn(365000U)); + ASSERT_EQ(nr_band::n5, get_band_from_dl_arfcn(175000U)); + ASSERT_EQ(nr_band::n7, get_band_from_dl_arfcn(530000U)); + ASSERT_EQ(nr_band::n25, get_band_from_dl_arfcn(399000U)); + ASSERT_EQ(nr_band::n34, get_band_from_dl_arfcn(404000U)); + ASSERT_EQ(nr_band::n38, get_band_from_dl_arfcn(515000U)); + ASSERT_EQ(nr_band::n41, get_band_from_dl_arfcn(499902U)); + ASSERT_EQ(nr_band::n41, get_band_from_dl_arfcn(504000U)); + ASSERT_EQ(nr_band::n50, get_band_from_dl_arfcn(286500U)); + ASSERT_EQ(nr_band::n51, get_band_from_dl_arfcn(285500U)); + ASSERT_EQ(nr_band::n70, get_band_from_dl_arfcn(400000U)); + ASSERT_EQ(nr_band::n77, get_band_from_dl_arfcn(630500U)); } TEST(test_arfcn_freq_conversion, arfcn_to_freq) { - ASSERT_DOUBLE_EQ(3489.42e6, band_helper::nr_arfcn_to_freq(632628)); + ASSERT_DOUBLE_EQ(3489.42e6, nr_arfcn_to_freq(632628)); // default refPointA. - ASSERT_DOUBLE_EQ(3508.92e6, band_helper::nr_arfcn_to_freq(633928)); + ASSERT_DOUBLE_EQ(3508.92e6, nr_arfcn_to_freq(633928)); // default ARFCN with freq divisible by 11.52 MHz. - ASSERT_DOUBLE_EQ(3513.6e6, band_helper::nr_arfcn_to_freq(634240)); + ASSERT_DOUBLE_EQ(3513.6e6, nr_arfcn_to_freq(634240)); // n28 n67 - ASSERT_DOUBLE_EQ(703.0e6, band_helper::nr_arfcn_to_freq(140600)); - ASSERT_DOUBLE_EQ(729.0e6, band_helper::nr_arfcn_to_freq(145800)); - ASSERT_DOUBLE_EQ(768.0e6, band_helper::nr_arfcn_to_freq(153600)); - ASSERT_DOUBLE_EQ(788.0e6, band_helper::nr_arfcn_to_freq(157600)); + ASSERT_DOUBLE_EQ(703.0e6, nr_arfcn_to_freq(140600)); + ASSERT_DOUBLE_EQ(729.0e6, nr_arfcn_to_freq(145800)); + ASSERT_DOUBLE_EQ(768.0e6, nr_arfcn_to_freq(153600)); + ASSERT_DOUBLE_EQ(788.0e6, nr_arfcn_to_freq(157600)); // n20 - ASSERT_DOUBLE_EQ(791.0e6, band_helper::nr_arfcn_to_freq(158200)); - ASSERT_DOUBLE_EQ(801.0e6, band_helper::nr_arfcn_to_freq(160200)); - ASSERT_DOUBLE_EQ(811.0e6, band_helper::nr_arfcn_to_freq(162200)); - ASSERT_DOUBLE_EQ(842.0e6, band_helper::nr_arfcn_to_freq(168400)); + ASSERT_DOUBLE_EQ(791.0e6, nr_arfcn_to_freq(158200)); + ASSERT_DOUBLE_EQ(801.0e6, nr_arfcn_to_freq(160200)); + ASSERT_DOUBLE_EQ(811.0e6, nr_arfcn_to_freq(162200)); + ASSERT_DOUBLE_EQ(842.0e6, nr_arfcn_to_freq(168400)); // n32 n75 - ASSERT_DOUBLE_EQ(1452.0e6, band_helper::nr_arfcn_to_freq(290400)); - ASSERT_DOUBLE_EQ(1472.0e6, band_helper::nr_arfcn_to_freq(294400)); + ASSERT_DOUBLE_EQ(1452.0e6, nr_arfcn_to_freq(290400)); + ASSERT_DOUBLE_EQ(1472.0e6, nr_arfcn_to_freq(294400)); // n1 - ASSERT_DOUBLE_EQ(1920.0e6, band_helper::nr_arfcn_to_freq(384000)); - ASSERT_DOUBLE_EQ(1940.15e6, band_helper::nr_arfcn_to_freq(388030)); - ASSERT_DOUBLE_EQ(1959.15e6, band_helper::nr_arfcn_to_freq(391830)); - ASSERT_DOUBLE_EQ(2170.0e6, band_helper::nr_arfcn_to_freq(434000)); + ASSERT_DOUBLE_EQ(1920.0e6, nr_arfcn_to_freq(384000)); + ASSERT_DOUBLE_EQ(1940.15e6, nr_arfcn_to_freq(388030)); + ASSERT_DOUBLE_EQ(1959.15e6, nr_arfcn_to_freq(391830)); + ASSERT_DOUBLE_EQ(2170.0e6, nr_arfcn_to_freq(434000)); // n3 - ASSERT_DOUBLE_EQ(1710.0e6, band_helper::nr_arfcn_to_freq(342000)); - ASSERT_DOUBLE_EQ(1740.0e6, band_helper::nr_arfcn_to_freq(348000)); - ASSERT_DOUBLE_EQ(1805.0e6, band_helper::nr_arfcn_to_freq(361000)); - ASSERT_DOUBLE_EQ(1842.5e6, band_helper::nr_arfcn_to_freq(368500)); - ASSERT_DOUBLE_EQ(1880.0e6, band_helper::nr_arfcn_to_freq(376000)); + ASSERT_DOUBLE_EQ(1710.0e6, nr_arfcn_to_freq(342000)); + ASSERT_DOUBLE_EQ(1740.0e6, nr_arfcn_to_freq(348000)); + ASSERT_DOUBLE_EQ(1805.0e6, nr_arfcn_to_freq(361000)); + ASSERT_DOUBLE_EQ(1842.5e6, nr_arfcn_to_freq(368500)); + ASSERT_DOUBLE_EQ(1880.0e6, nr_arfcn_to_freq(376000)); // n5 - ASSERT_DOUBLE_EQ(881.5e6, band_helper::nr_arfcn_to_freq(176300)); - ASSERT_DOUBLE_EQ(836.5e6, band_helper::nr_arfcn_to_freq(167300)); + ASSERT_DOUBLE_EQ(881.5e6, nr_arfcn_to_freq(176300)); + ASSERT_DOUBLE_EQ(836.5e6, nr_arfcn_to_freq(167300)); // n7 n38 - ASSERT_DOUBLE_EQ(2500.0e6, band_helper::nr_arfcn_to_freq(500000)); - ASSERT_DOUBLE_EQ(2540.0e6, band_helper::nr_arfcn_to_freq(508000)); - ASSERT_DOUBLE_EQ(2610.0e6, band_helper::nr_arfcn_to_freq(522000)); - ASSERT_DOUBLE_EQ(2690.0e6, band_helper::nr_arfcn_to_freq(538000)); + ASSERT_DOUBLE_EQ(2500.0e6, nr_arfcn_to_freq(500000)); + ASSERT_DOUBLE_EQ(2540.0e6, nr_arfcn_to_freq(508000)); + ASSERT_DOUBLE_EQ(2610.0e6, nr_arfcn_to_freq(522000)); + ASSERT_DOUBLE_EQ(2690.0e6, nr_arfcn_to_freq(538000)); // n78 - ASSERT_DOUBLE_EQ(3513.6e6, band_helper::nr_arfcn_to_freq(634240)); + ASSERT_DOUBLE_EQ(3513.6e6, nr_arfcn_to_freq(634240)); } TEST(test_arfcn_freq_conversion, freq_to_arfcn) { - ASSERT_EQ(632628, band_helper::freq_to_nr_arfcn(3489.42e6)); - ASSERT_EQ(633928, band_helper::freq_to_nr_arfcn(3508.92e6)); - ASSERT_EQ(634240, band_helper::freq_to_nr_arfcn(3513.6e6)); + ASSERT_EQ(632628, freq_to_nr_arfcn(3489.42e6)); + ASSERT_EQ(633928, freq_to_nr_arfcn(3508.92e6)); + ASSERT_EQ(634240, freq_to_nr_arfcn(3513.6e6)); // n28 n67 - ASSERT_EQ(140600, band_helper::freq_to_nr_arfcn(703.0e6)); - ASSERT_EQ(145800, band_helper::freq_to_nr_arfcn(729.0e6)); - ASSERT_EQ(153600, band_helper::freq_to_nr_arfcn(768.0e6)); - ASSERT_EQ(157600, band_helper::freq_to_nr_arfcn(788.0e6)); + ASSERT_EQ(140600, freq_to_nr_arfcn(703.0e6)); + ASSERT_EQ(145800, freq_to_nr_arfcn(729.0e6)); + ASSERT_EQ(153600, freq_to_nr_arfcn(768.0e6)); + ASSERT_EQ(157600, freq_to_nr_arfcn(788.0e6)); // n5 - ASSERT_EQ(176300, band_helper::freq_to_nr_arfcn(881.5e6)); + ASSERT_EQ(176300, freq_to_nr_arfcn(881.5e6)); } TEST(get_ul_arfcn_from_dl_arfcn, mixed_frequencies) { // n5 - ASSERT_EQ(167300, band_helper::get_ul_arfcn_from_dl_arfcn(176300, {})); + ASSERT_EQ(167300, get_ul_arfcn_from_dl_arfcn(176300, {})); + + ASSERT_EQ(500000, get_ul_arfcn_from_dl_arfcn(524000, nr_band::n7)); + ASSERT_EQ(504060, get_ul_arfcn_from_dl_arfcn(528060, nr_band::n7)); + ASSERT_EQ(514000, get_ul_arfcn_from_dl_arfcn(538000, nr_band::n7)); + + ASSERT_EQ(383000, get_ul_arfcn_from_dl_arfcn(399000, nr_band::n25)); + + // n28. The spectrum of this band overlaps with that of n14. We need to check that the return UL ARFCN belongs to n28. + ASSERT_EQ(142600, get_ul_arfcn_from_dl_arfcn(153600, nr_band::n28)); + ASSERT_EQ(144608, get_ul_arfcn_from_dl_arfcn(155608, nr_band::n28)); + + // For n65, m66, n70, n92, n94, the UL spectrum is smaller than the DL spectrum. When we convert the DL ARFCN + // upper-bound to the corresponding UL ARFCN, we need to cap the value to the UL spectrum upper-bound. + ASSERT_EQ(402000, get_ul_arfcn_from_dl_arfcn(440000, nr_band::n65)); + ASSERT_EQ(356000, get_ul_arfcn_from_dl_arfcn(440000, nr_band::n66)); + ASSERT_EQ(342000, get_ul_arfcn_from_dl_arfcn(404000, nr_band::n70)); + ASSERT_EQ(172400, get_ul_arfcn_from_dl_arfcn(303400, nr_band::n92)); + ASSERT_EQ(183000, get_ul_arfcn_from_dl_arfcn(303400, nr_band::n94)); } TEST(test_get_abs_freq_point_a_arfcn, mixed_frequencies) { // n3 - ASSERT_EQ(367564, band_helper::get_abs_freq_point_a_arfcn(52, 368500)); + ASSERT_EQ(367564, get_abs_freq_point_a_arfcn(52, 368500)); // n5 - ASSERT_EQ(175364, band_helper::get_abs_freq_point_a_arfcn(52, 176300)); + ASSERT_EQ(175364, get_abs_freq_point_a_arfcn(52, 176300)); // n7 n38 - ASSERT_EQ(528984, band_helper::get_abs_freq_point_a_arfcn(52, 529920)); + ASSERT_EQ(528984, get_abs_freq_point_a_arfcn(52, 529920)); // n78 - ASSERT_EQ(633928, band_helper::get_abs_freq_point_a_arfcn(52, 634240)); + ASSERT_EQ(633928, get_abs_freq_point_a_arfcn(52, 634240)); } TEST(test_arfcn_freq_conversion, arfcn_to_freq_corner_cases) @@ -117,16 +138,16 @@ TEST(test_arfcn_freq_conversion, arfcn_to_freq_corner_cases) const uint32_t max_valid_nr_arfcn = 3279165; // Max ARFCN is 3279165 at almost 10 GHz - ASSERT_DOUBLE_EQ(99.99996e9, band_helper::nr_arfcn_to_freq(max_valid_nr_arfcn)); + ASSERT_DOUBLE_EQ(99.99996e9, nr_arfcn_to_freq(max_valid_nr_arfcn)); // Invalid ARFCN - ASSERT_DOUBLE_EQ(0.0, band_helper::nr_arfcn_to_freq(max_valid_nr_arfcn + 1)); + ASSERT_DOUBLE_EQ(0.0, nr_arfcn_to_freq(max_valid_nr_arfcn + 1)); } TEST(test_center_freq_conversion, freq_center) { - ASSERT_DOUBLE_EQ(881.5e6, band_helper::get_center_freq_from_abs_freq_point_a(52, 175364)); - ASSERT_DOUBLE_EQ(836.5e6, band_helper::get_center_freq_from_abs_freq_point_a(52, 166364)); + ASSERT_DOUBLE_EQ(881.5e6, get_center_freq_from_abs_freq_point_a(52, 175364)); + ASSERT_DOUBLE_EQ(836.5e6, get_center_freq_from_abs_freq_point_a(52, 166364)); } TEST(test_band_duplexing, all_bands) @@ -135,18 +156,18 @@ TEST(test_band_duplexing, all_bands) if (b < nr_band::n29 or b == nr_band::n30 or b == nr_band::n65 or b == nr_band::n66 or (b >= srsran::nr_band::n70 and b <= srsran::nr_band::n74) or b == nr_band::n85 or (b >= srsran::nr_band::n91 and b <= srsran::nr_band::n94) or b == srsran::nr_band::n100) { - ASSERT_EQ(duplex_mode::FDD, band_helper::get_duplex_mode(b)); + ASSERT_EQ(duplex_mode::FDD, get_duplex_mode(b)); } else if ((b >= srsran::nr_band::n34 and b <= srsran::nr_band::n53) or (b >= srsran::nr_band::n77 and b <= srsran::nr_band::n79) or b == srsran::nr_band::n90 or b == srsran::nr_band::n96 or b > srsran::nr_band::n100) { - ASSERT_EQ(duplex_mode::TDD, band_helper::get_duplex_mode(b)); + ASSERT_EQ(duplex_mode::TDD, get_duplex_mode(b)); } else if (b == srsran::nr_band::n29 or b == srsran::nr_band::n67 or b == srsran::nr_band::n75 or b == srsran::nr_band::n76) { - ASSERT_EQ(duplex_mode::SDL, band_helper::get_duplex_mode(b)); + ASSERT_EQ(duplex_mode::SDL, get_duplex_mode(b)); } else if ((b >= srsran::nr_band::n80 and b <= srsran::nr_band::n84) or b == srsran::nr_band::n86 or b == srsran::nr_band::n89 or b == srsran::nr_band::n95 or (b >= srsran::nr_band::n97 and b <= srsran::nr_band::n99)) { - ASSERT_EQ(duplex_mode::SUL, band_helper::get_duplex_mode(b)); + ASSERT_EQ(duplex_mode::SUL, get_duplex_mode(b)); } else { ASSERT_FALSE(true); } @@ -167,7 +188,7 @@ TEST(test_is_paired_spectrum, paired) nr_band::n100}; for (const auto band : some_fdd_bands) { - ASSERT_TRUE(band_helper::is_paired_spectrum(band)); + ASSERT_TRUE(is_paired_spectrum(band)); } } @@ -188,7 +209,7 @@ TEST(test_is_paired_spectrum, unpaired) nr_band::n102}; for (const auto band : some_non_fdd_bands) { - ASSERT_FALSE(band_helper::is_paired_spectrum(band)); + ASSERT_FALSE(is_paired_spectrum(band)); } } @@ -212,10 +233,10 @@ TEST(test_ssb_pattern, ssb_pattern_case_A) // Skip SSB case-C-only bands and SUL bands. if (std::any_of( case_c_bands.begin(), case_c_bands.end(), [band](nr_band non_a_band) { return band == non_a_band; }) or - band_helper::get_duplex_mode(band) == srsran::duplex_mode::SUL) { + get_duplex_mode(band) == srsran::duplex_mode::SUL) { continue; } - ASSERT_EQ(ssb_pattern_case::A, band_helper::get_ssb_pattern(band, subcarrier_spacing::kHz15)); + ASSERT_EQ(ssb_pattern_case::A, get_ssb_pattern(band, subcarrier_spacing::kHz15)); } } @@ -224,7 +245,7 @@ TEST(test_ssb_pattern, ssb_pattern_case_B) const std::array case_b_bands{nr_band::n5, nr_band::n24, nr_band::n66}; for (auto band : case_b_bands) { - ASSERT_EQ(ssb_pattern_case::B, band_helper::get_ssb_pattern(band, subcarrier_spacing::kHz30)); + ASSERT_EQ(ssb_pattern_case::B, get_ssb_pattern(band, subcarrier_spacing::kHz30)); } } @@ -247,425 +268,666 @@ TEST(test_ssb_pattern, ssb_pattern_case_C) nr_band::n102, nr_band::n104}; for (auto band : case_c_bands) { - ASSERT_EQ(ssb_pattern_case::C, band_helper::get_ssb_pattern(band, subcarrier_spacing::kHz30)); + ASSERT_EQ(ssb_pattern_case::C, get_ssb_pattern(band, subcarrier_spacing::kHz30)); } } TEST(test_ssb_pattern, ssb_pattern_case_invalid) { - ASSERT_GT(ssb_pattern_case::invalid, band_helper::get_ssb_pattern(nr_band::n1, subcarrier_spacing::kHz15)); - ASSERT_EQ(ssb_pattern_case::invalid, band_helper::get_ssb_pattern(nr_band::n3, subcarrier_spacing::kHz30)); + ASSERT_GT(ssb_pattern_case::invalid, get_ssb_pattern(nr_band::n1, subcarrier_spacing::kHz15)); + ASSERT_EQ(ssb_pattern_case::invalid, get_ssb_pattern(nr_band::n3, subcarrier_spacing::kHz30)); } TEST(test_get_point_a_from_f_req, scs_kHz15) { // Band n1, BWs are {5MHz, 10MHz, 15MHz, 20MHz}. - ASSERT_DOUBLE_EQ(2122150000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2124400000.0, 25, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(2105420000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2110100000.0, 52, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(2108090000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2115200000.0, 79, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(2150860000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2160400000.0, 106, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2122150000.0, get_abs_freq_point_a_from_f_ref(2124400000.0, 25, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2105420000.0, get_abs_freq_point_a_from_f_ref(2110100000.0, 52, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2108090000.0, get_abs_freq_point_a_from_f_ref(2115200000.0, 79, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2150860000.0, get_abs_freq_point_a_from_f_ref(2160400000.0, 106, subcarrier_spacing::kHz15)); // Band n78, BWs are {10MHz, 15MHz, 20MHz, 30MHz, 40MHz, 50MHz}. - ASSERT_DOUBLE_EQ(3615675000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3620355000.0, 52, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3613245000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3620355000.0, 79, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3610815000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3620355000.0, 106, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3605955000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3620355000.0, 160, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3600915000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3620355000.0, 216, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3596055000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3620355000.0, 270, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3615675000.0, get_abs_freq_point_a_from_f_ref(3620355000.0, 52, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3613245000.0, get_abs_freq_point_a_from_f_ref(3620355000.0, 79, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3610815000.0, get_abs_freq_point_a_from_f_ref(3620355000.0, 106, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3605955000.0, get_abs_freq_point_a_from_f_ref(3620355000.0, 160, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3600915000.0, get_abs_freq_point_a_from_f_ref(3620355000.0, 216, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3596055000.0, get_abs_freq_point_a_from_f_ref(3620355000.0, 270, subcarrier_spacing::kHz15)); } TEST(test_get_point_a_from_f_req, scs_kHz30) { // Band n3, BWs are {10MHz, 15MHz, 20MHz, 25MHz, 30MHz}. - ASSERT_DOUBLE_EQ(1821380000.0, - band_helper::get_abs_freq_point_a_from_f_ref(1825700000.0, 24, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1844460000.0, - band_helper::get_abs_freq_point_a_from_f_ref(1851300000.0, 38, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1860220000.0, - band_helper::get_abs_freq_point_a_from_f_ref(1869400000.0, 51, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1837800000.0, - band_helper::get_abs_freq_point_a_from_f_ref(1849500000.0, 65, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1837800000.0, - band_helper::get_abs_freq_point_a_from_f_ref(1849500000.0, 65, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1842060000.0, - band_helper::get_abs_freq_point_a_from_f_ref(1856100000.0, 78, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1821380000.0, get_abs_freq_point_a_from_f_ref(1825700000.0, 24, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1844460000.0, get_abs_freq_point_a_from_f_ref(1851300000.0, 38, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1860220000.0, get_abs_freq_point_a_from_f_ref(1869400000.0, 51, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1837800000.0, get_abs_freq_point_a_from_f_ref(1849500000.0, 65, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1837800000.0, get_abs_freq_point_a_from_f_ref(1849500000.0, 65, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1842060000.0, get_abs_freq_point_a_from_f_ref(1856100000.0, 78, subcarrier_spacing::kHz30)); // Band n78, BWs that are tested are {15MHz, 20MHz, 30MHz, 50MHz, 80MHz, 100MHz}. - ASSERT_DOUBLE_EQ(3697320000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 38, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3694980000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 51, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3690120000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 78, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3680220000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 133, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3665100000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 217, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3655020000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 273, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3697320000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 38, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3694980000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 51, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3690120000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 78, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3680220000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 133, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3665100000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 217, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3655020000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 273, subcarrier_spacing::kHz30)); } TEST(test_get_point_a_from_f_req, scs_kHz60) { // Band n41, BWs are {40MHz, 50MHz, 60MHz, 70MHz, 80MHz, 90MHz, 100MHz}. - ASSERT_DOUBLE_EQ(2671620000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 51, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2666580000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 65, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2661540000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 79, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2656500000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 93, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2651460000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 107, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2646420000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 121, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2641380000.0, - band_helper::get_abs_freq_point_a_from_f_ref(2689980000.0, 135, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2671620000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 51, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2666580000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 65, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2661540000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 79, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2656500000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 93, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2651460000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 107, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2646420000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 121, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2641380000.0, get_abs_freq_point_a_from_f_ref(2689980000.0, 135, subcarrier_spacing::kHz60)); // Band n78, BWs that are tested are {10MHz, 40MHz, 60MHz, 70MHz, 90MHz}. - ASSERT_DOUBLE_EQ(3700200000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 11, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3685800000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 51, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3675720000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 79, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3670680000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 93, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3660600000.0, - band_helper::get_abs_freq_point_a_from_f_ref(3704160000.0, 121, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3700200000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 11, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3685800000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 51, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3675720000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 79, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3670680000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 93, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3660600000.0, get_abs_freq_point_a_from_f_ref(3704160000.0, 121, subcarrier_spacing::kHz60)); } TEST(test_get_f_req_from_f_req_point_a, scs_kHz15) { // Band n1, BWs are {5MHz, 10MHz, 15MHz, 20MHz}. - ASSERT_DOUBLE_EQ(2124400000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2122150000.0, 25, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(2110100000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2105420000.0, 52, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(2115200000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2108090000.0, 79, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(2160400000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2150860000.0, 106, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2124400000.0, get_f_ref_from_abs_freq_point_a(2122150000.0, 25, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2110100000.0, get_f_ref_from_abs_freq_point_a(2105420000.0, 52, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2115200000.0, get_f_ref_from_abs_freq_point_a(2108090000.0, 79, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(2160400000.0, get_f_ref_from_abs_freq_point_a(2150860000.0, 106, subcarrier_spacing::kHz15)); // Band n78, BWs are {10MHz, 15MHz, 20MHz, 30MHz, 40MHz, 50MHz}. - ASSERT_DOUBLE_EQ(3620355000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3615675000.0, 52, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3620355000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3613245000.0, 79, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3620355000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3610815000.0, 106, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3620355000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3605955000.0, 160, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3620355000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3600915000.0, 216, subcarrier_spacing::kHz15)); - ASSERT_DOUBLE_EQ(3620355000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3596055000.0, 270, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3620355000.0, get_f_ref_from_abs_freq_point_a(3615675000.0, 52, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3620355000.0, get_f_ref_from_abs_freq_point_a(3613245000.0, 79, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3620355000.0, get_f_ref_from_abs_freq_point_a(3610815000.0, 106, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3620355000.0, get_f_ref_from_abs_freq_point_a(3605955000.0, 160, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3620355000.0, get_f_ref_from_abs_freq_point_a(3600915000.0, 216, subcarrier_spacing::kHz15)); + ASSERT_DOUBLE_EQ(3620355000.0, get_f_ref_from_abs_freq_point_a(3596055000.0, 270, subcarrier_spacing::kHz15)); } TEST(test_get_f_req_from_f_req_point_a, scs_kHz30) { // Band n3, BWs are {10MHz, 15MHz, 20MHz, 25MHz, 30MHz}. - ASSERT_DOUBLE_EQ(1825700000.0, - band_helper::get_f_ref_from_abs_freq_point_a(1821380000.0, 24, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1851300000.0, - band_helper::get_f_ref_from_abs_freq_point_a(1844460000.0, 38, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1869400000.0, - band_helper::get_f_ref_from_abs_freq_point_a(1860220000.0, 51, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1849500000.0, - band_helper::get_f_ref_from_abs_freq_point_a(1837800000.0, 65, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1849500000.0, - band_helper::get_f_ref_from_abs_freq_point_a(1837800000.0, 65, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(1856100000.0, - band_helper::get_f_ref_from_abs_freq_point_a(1842060000.0, 78, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1825700000.0, get_f_ref_from_abs_freq_point_a(1821380000.0, 24, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1851300000.0, get_f_ref_from_abs_freq_point_a(1844460000.0, 38, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1869400000.0, get_f_ref_from_abs_freq_point_a(1860220000.0, 51, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1849500000.0, get_f_ref_from_abs_freq_point_a(1837800000.0, 65, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1849500000.0, get_f_ref_from_abs_freq_point_a(1837800000.0, 65, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(1856100000.0, get_f_ref_from_abs_freq_point_a(1842060000.0, 78, subcarrier_spacing::kHz30)); // Band n78, BWs that are tested are {15MHz, 20MHz, 30MHz, 50MHz, 80MHz, 100MHz}. - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3697320000.0, 38, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3694980000.0, 51, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3690120000.0, 78, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3680220000.0, 133, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3665100000.0, 217, subcarrier_spacing::kHz30)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3655020000.0, 273, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3697320000.0, 38, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3694980000.0, 51, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3690120000.0, 78, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3680220000.0, 133, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3665100000.0, 217, subcarrier_spacing::kHz30)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3655020000.0, 273, subcarrier_spacing::kHz30)); } TEST(test_get_f_req_from_f_req_point_a, scs_kHz60) { // Band n41, BWs are {40MHz, 50MHz, 60MHz, 70MHz, 80MHz, 90MHz, 100MHz}. - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2671620000.0, 51, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2666580000.0, 65, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2661540000.0, 79, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2656500000.0, 93, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2651460000.0, 107, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2646420000.0, 121, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(2689980000.0, - band_helper::get_f_ref_from_abs_freq_point_a(2641380000.0, 135, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2671620000.0, 51, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2666580000.0, 65, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2661540000.0, 79, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2656500000.0, 93, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2651460000.0, 107, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2646420000.0, 121, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(2689980000.0, get_f_ref_from_abs_freq_point_a(2641380000.0, 135, subcarrier_spacing::kHz60)); // Band n78, BWs that are tested are {10MHz, 40MHz, 60MHz, 70MHz, 90MHz}. - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3700200000.0, 11, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3685800000.0, 51, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3675720000.0, 79, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3670680000.0, 93, subcarrier_spacing::kHz60)); - ASSERT_DOUBLE_EQ(3704160000.0, - band_helper::get_f_ref_from_abs_freq_point_a(3660600000.0, 121, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3700200000.0, 11, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3685800000.0, 51, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3675720000.0, 79, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3670680000.0, 93, subcarrier_spacing::kHz60)); + ASSERT_DOUBLE_EQ(3704160000.0, get_f_ref_from_abs_freq_point_a(3660600000.0, 121, subcarrier_spacing::kHz60)); } TEST(test_get_n_rbs_from_bw, scs_15kHz) { - ASSERT_EQ( - 25, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz5, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 52, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz10, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 79, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz15, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 106, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz20, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 133, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz25, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 160, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz30, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 188, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz35, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 216, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz40, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 242, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz45, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 270, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz15, frequency_range::FR1)); - ASSERT_EQ( - 0, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz60, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(25, get_n_rbs_from_bw(bs_channel_bandwidth::MHz5, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(52, get_n_rbs_from_bw(bs_channel_bandwidth::MHz10, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(79, get_n_rbs_from_bw(bs_channel_bandwidth::MHz15, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(106, get_n_rbs_from_bw(bs_channel_bandwidth::MHz20, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(133, get_n_rbs_from_bw(bs_channel_bandwidth::MHz25, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(160, get_n_rbs_from_bw(bs_channel_bandwidth::MHz30, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(188, get_n_rbs_from_bw(bs_channel_bandwidth::MHz35, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(216, get_n_rbs_from_bw(bs_channel_bandwidth::MHz40, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(242, get_n_rbs_from_bw(bs_channel_bandwidth::MHz45, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(270, get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz15, frequency_range::FR1)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz60, subcarrier_spacing::kHz15, frequency_range::FR1)); } TEST(test_get_n_rbs_from_bw, scs_30kHz) { - ASSERT_EQ( - 11, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz5, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 24, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz10, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 38, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz15, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 51, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz20, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 65, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz25, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 78, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz30, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 92, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz35, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 106, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz40, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 119, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz45, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 133, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 162, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz60, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 189, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz70, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 217, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz80, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 245, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz90, subcarrier_spacing::kHz30, frequency_range::FR1)); - ASSERT_EQ( - 273, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(11, get_n_rbs_from_bw(bs_channel_bandwidth::MHz5, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(24, get_n_rbs_from_bw(bs_channel_bandwidth::MHz10, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(38, get_n_rbs_from_bw(bs_channel_bandwidth::MHz15, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(51, get_n_rbs_from_bw(bs_channel_bandwidth::MHz20, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(65, get_n_rbs_from_bw(bs_channel_bandwidth::MHz25, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(78, get_n_rbs_from_bw(bs_channel_bandwidth::MHz30, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(92, get_n_rbs_from_bw(bs_channel_bandwidth::MHz35, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(106, get_n_rbs_from_bw(bs_channel_bandwidth::MHz40, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(119, get_n_rbs_from_bw(bs_channel_bandwidth::MHz45, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(133, get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(162, get_n_rbs_from_bw(bs_channel_bandwidth::MHz60, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(189, get_n_rbs_from_bw(bs_channel_bandwidth::MHz70, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(217, get_n_rbs_from_bw(bs_channel_bandwidth::MHz80, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(245, get_n_rbs_from_bw(bs_channel_bandwidth::MHz90, subcarrier_spacing::kHz30, frequency_range::FR1)); + ASSERT_EQ(273, get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz30, frequency_range::FR1)); } TEST(test_get_n_rbs_from_bw, scs_60kHz) { - ASSERT_EQ( - 0, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz5, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 11, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz10, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 18, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz15, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 24, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz20, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 31, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz25, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 38, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz30, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 44, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz35, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 51, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz40, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 58, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz45, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 65, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 79, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz60, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 93, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz70, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 107, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz80, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 121, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz90, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 135, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz5, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(11, get_n_rbs_from_bw(bs_channel_bandwidth::MHz10, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(18, get_n_rbs_from_bw(bs_channel_bandwidth::MHz15, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(24, get_n_rbs_from_bw(bs_channel_bandwidth::MHz20, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(31, get_n_rbs_from_bw(bs_channel_bandwidth::MHz25, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(38, get_n_rbs_from_bw(bs_channel_bandwidth::MHz30, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(44, get_n_rbs_from_bw(bs_channel_bandwidth::MHz35, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(51, get_n_rbs_from_bw(bs_channel_bandwidth::MHz40, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(58, get_n_rbs_from_bw(bs_channel_bandwidth::MHz45, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(65, get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(79, get_n_rbs_from_bw(bs_channel_bandwidth::MHz60, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(93, get_n_rbs_from_bw(bs_channel_bandwidth::MHz70, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(107, get_n_rbs_from_bw(bs_channel_bandwidth::MHz80, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(121, get_n_rbs_from_bw(bs_channel_bandwidth::MHz90, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(135, get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz60, frequency_range::FR1)); } TEST(test_get_n_rbs_from_bw, scs_120kHz_fr2) { - ASSERT_EQ( - 66, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz60, frequency_range::FR2)); - ASSERT_EQ( - 132, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz60, frequency_range::FR2)); - ASSERT_EQ( - 264, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz200, subcarrier_spacing::kHz60, frequency_range::FR2)); + ASSERT_EQ(66, get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz60, frequency_range::FR2)); + ASSERT_EQ(132, get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz60, frequency_range::FR2)); + ASSERT_EQ(264, get_n_rbs_from_bw(bs_channel_bandwidth::MHz200, subcarrier_spacing::kHz60, frequency_range::FR2)); } TEST(test_get_n_rbs_from_bw, scs_120kHz) { - ASSERT_EQ( - 32, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz120, frequency_range::FR2)); - ASSERT_EQ( - 66, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz120, frequency_range::FR2)); - ASSERT_EQ( - 132, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz200, subcarrier_spacing::kHz120, frequency_range::FR2)); - ASSERT_EQ( - 264, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz120, frequency_range::FR2)); + ASSERT_EQ(32, get_n_rbs_from_bw(bs_channel_bandwidth::MHz50, subcarrier_spacing::kHz120, frequency_range::FR2)); + ASSERT_EQ(66, get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz120, frequency_range::FR2)); + ASSERT_EQ(132, get_n_rbs_from_bw(bs_channel_bandwidth::MHz200, subcarrier_spacing::kHz120, frequency_range::FR2)); + ASSERT_EQ(264, get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz120, frequency_range::FR2)); } TEST(test_get_n_rbs_from_bw, invalid_cases) { - ASSERT_EQ( - 0, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz200, subcarrier_spacing::kHz60, frequency_range::FR1)); - ASSERT_EQ( - 0, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz60, frequency_range::FR2)); - ASSERT_EQ( - 0, band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz15, frequency_range::FR2)); - ASSERT_EQ( - 0, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz240, frequency_range::FR2)); - ASSERT_EQ( - 0, - band_helper::get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz120, frequency_range::FR1)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz200, subcarrier_spacing::kHz60, frequency_range::FR1)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz60, frequency_range::FR2)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz15, frequency_range::FR2)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz400, subcarrier_spacing::kHz240, frequency_range::FR2)); + ASSERT_EQ(0, get_n_rbs_from_bw(bs_channel_bandwidth::MHz100, subcarrier_spacing::kHz120, frequency_range::FR1)); } TEST(test_get_min_channel_bw, invalid_cases) { - ASSERT_EQ(min_channel_bandwidth::MHz5, band_helper::get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz120)); - - ASSERT_EQ(min_channel_bandwidth::MHz5, band_helper::get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz120)); - - ASSERT_EQ(min_channel_bandwidth::MHz5, band_helper::get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz120)); - - ASSERT_EQ(min_channel_bandwidth::MHz5, band_helper::get_min_channel_bw(nr_band::n20, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n20, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n20, subcarrier_spacing::kHz60)); - - ASSERT_EQ(min_channel_bandwidth::MHz5, band_helper::get_min_channel_bw(nr_band::n76, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n76, subcarrier_spacing::kHz30)); - - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz120)); - - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::MHz10, band_helper::get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz120)); - - ASSERT_EQ(min_channel_bandwidth::MHz20, band_helper::get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::MHz20, band_helper::get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz30)); - ASSERT_EQ(min_channel_bandwidth::MHz20, band_helper::get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz120)); - - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n257, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n258, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n260, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n261, subcarrier_spacing::kHz60)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n257, subcarrier_spacing::kHz120)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n258, subcarrier_spacing::kHz120)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n260, subcarrier_spacing::kHz120)); - ASSERT_EQ(min_channel_bandwidth::MHz50, band_helper::get_min_channel_bw(nr_band::n261, subcarrier_spacing::kHz120)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n257, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n258, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n260, subcarrier_spacing::kHz15)); - ASSERT_EQ(min_channel_bandwidth::invalid, band_helper::get_min_channel_bw(nr_band::n261, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz5, get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n1, subcarrier_spacing::kHz120)); + + ASSERT_EQ(min_channel_bandwidth::MHz5, get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n3, subcarrier_spacing::kHz120)); + + ASSERT_EQ(min_channel_bandwidth::MHz5, get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n7, subcarrier_spacing::kHz120)); + + ASSERT_EQ(min_channel_bandwidth::MHz5, get_min_channel_bw(nr_band::n20, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n20, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n20, subcarrier_spacing::kHz60)); + + ASSERT_EQ(min_channel_bandwidth::MHz5, get_min_channel_bw(nr_band::n76, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n76, subcarrier_spacing::kHz30)); + + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n78, subcarrier_spacing::kHz120)); + + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::MHz10, get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n79, subcarrier_spacing::kHz120)); + + ASSERT_EQ(min_channel_bandwidth::MHz20, get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::MHz20, get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz30)); + ASSERT_EQ(min_channel_bandwidth::MHz20, get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n102, subcarrier_spacing::kHz120)); + + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n257, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n258, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n260, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n261, subcarrier_spacing::kHz60)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n257, subcarrier_spacing::kHz120)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n258, subcarrier_spacing::kHz120)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n260, subcarrier_spacing::kHz120)); + ASSERT_EQ(min_channel_bandwidth::MHz50, get_min_channel_bw(nr_band::n261, subcarrier_spacing::kHz120)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n257, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n258, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n260, subcarrier_spacing::kHz15)); + ASSERT_EQ(min_channel_bandwidth::invalid, get_min_channel_bw(nr_band::n261, subcarrier_spacing::kHz15)); } TEST(test_is_valid_ssb_arfcn, mixed_bands) { // ARFCN 427970 is a valid SSB ARFCN for n1, expect no error. - ASSERT_TRUE(band_helper::is_ssb_arfcn_valid_given_band(427970U, nr_band::n1, subcarrier_spacing::kHz15).has_value()); + ASSERT_TRUE(is_ssb_arfcn_valid_given_band(427970U, nr_band::n1, subcarrier_spacing::kHz15).has_value()); // ARFCN 433970 is NOT a valid SSB ARFCN for n1, expect an error. - ASSERT_FALSE(band_helper::is_ssb_arfcn_valid_given_band(433970U, nr_band::n1, subcarrier_spacing::kHz15).has_value()); + ASSERT_FALSE(is_ssb_arfcn_valid_given_band(433970U, nr_band::n1, subcarrier_spacing::kHz15).has_value()); // ARFCN 427970 is a valid SSB ARFCN for n1, expect no error. - ASSERT_TRUE(band_helper::is_ssb_arfcn_valid_given_band(755712U, nr_band::n46, subcarrier_spacing::kHz30).has_value()); + ASSERT_TRUE(is_ssb_arfcn_valid_given_band(755712U, nr_band::n46, subcarrier_spacing::kHz30).has_value()); // ARFCN 433970 is NOT a valid SSB ARFCN for n1, expect an error. - ASSERT_FALSE( - band_helper::is_ssb_arfcn_valid_given_band(785856U, nr_band::n46, subcarrier_spacing::kHz30).has_value()); + ASSERT_FALSE(is_ssb_arfcn_valid_given_band(785856U, nr_band::n46, subcarrier_spacing::kHz30).has_value()); } TEST(test_get_ssb_l_max, test_different_ssb_cases) { // Case A. - ASSERT_EQ(4, band_helper::get_ssb_l_max(nr_band::n3, subcarrier_spacing::kHz15, 363640U)); + ASSERT_EQ(4, get_ssb_l_max(nr_band::n3, subcarrier_spacing::kHz15, 363640U)); // Case B. - ASSERT_EQ(8, band_helper::get_ssb_l_max(nr_band::n5, subcarrier_spacing::kHz30, 176800U)); + ASSERT_EQ(8, get_ssb_l_max(nr_band::n5, subcarrier_spacing::kHz30, 176800U)); // Case C, f < f_cutoff. - ASSERT_EQ(4, band_helper::get_ssb_l_max(nr_band::n50, subcarrier_spacing::kHz30, 296400U)); + ASSERT_EQ(4, get_ssb_l_max(nr_band::n50, subcarrier_spacing::kHz30, 296400U)); // Case C, f > f_cutoff. - ASSERT_EQ(8, band_helper::get_ssb_l_max(nr_band::n104, subcarrier_spacing::kHz30, 860000U)); + ASSERT_EQ(8, get_ssb_l_max(nr_band::n104, subcarrier_spacing::kHz30, 860000U)); +} + +TEST(test_dl_arfcn_validator, test_different_fdd_bands) +{ + // Get a random raster point from the band raster. If outside_raster is true, the function returns a point outside the + // raster. + auto get_rnd_raster_point = [](span raster, bool outside_raster = false) -> uint32_t { + const uint32_t raster_step = raster[1]; + if (outside_raster) { + return test_rgen::bernoulli(0.5) ? raster.front() - raster_step : raster.back() + raster_step; + } + const unsigned nof_raster_points = (raster.back() - raster.front()) / raster_step + 1; + return test_rgen::uniform_int(0, nof_raster_points - 1) * raster_step + raster.front(); + }; + + // Definition of UL rasters for different bands. + constexpr std::array n1_raster = {422000, 20, 434000}; + constexpr std::array n2_raster = {386000, 20, 398000}; + constexpr std::array n3_raster = {361000, 20, 376000}; + constexpr std::array n5_raster = {173800, 20, 178800}; + constexpr std::array n7_raster = {524000, 20, 538000}; + constexpr std::array n14_raster = {151600, 20, 153600}; + constexpr std::array n28_raster = {151600, 20, 160600}; + + // FDD bands + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n1, get_rnd_raster_point(n1_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n1, get_rnd_raster_point(n1_raster, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n2, get_rnd_raster_point(n2_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n2, get_rnd_raster_point(n2_raster, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n3, get_rnd_raster_point(n3_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n3, get_rnd_raster_point(n3_raster, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n5, get_rnd_raster_point(n5_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n5, get_rnd_raster_point(n5_raster, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n7, get_rnd_raster_point(n7_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n7, get_rnd_raster_point(n7_raster, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n14, get_rnd_raster_point(n14_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n14, get_rnd_raster_point(n14_raster, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n28, get_rnd_raster_point(n28_raster), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n28, get_rnd_raster_point(n28_raster, true), subcarrier_spacing::kHz15) + .has_value()); + // Single UL ARFCN for n28, BW 40Mhz. + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n28, 155608, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n28, 155608, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz20) + .has_value()); +} + +TEST(test_dl_arfcn_validator, test_different_tdd_bands_with_regular_raster) +{ + // Get a random raster point from the band raster. If outside_raster is true, the function returns a point outside the + // raster. + auto get_rnd_raster_point = [](span raster, bool outside_raster = false) -> uint32_t { + const uint32_t raster_step = raster[1]; + if (outside_raster) { + return test_rgen::bernoulli(0.5) ? raster.front() - raster_step : raster.back() + raster_step; + } + const unsigned nof_raster_points = (raster.back() - raster.front()) / raster_step + 1; + return test_rgen::uniform_int(0, nof_raster_points - 1) * raster_step + raster.front(); + }; + + // Definition of UL rasters for different bands. + constexpr std::array n34_raster = {402000, 20, 405000}; + constexpr std::array n38_raster = {514000, 20, 524000}; + constexpr std::array n39_raster = {376000, 20, 384000}; + constexpr std::array n40_raster = {460000, 20, 480000}; + constexpr std::array n50_raster = {286400, 20, 303400}; + constexpr std::array n51_raster = {285400, 20, 286400}; + constexpr std::array n53_raster = {496700, 20, 499000}; + constexpr std::array n100_raster = {183880, 20, 185000}; + + // TDD bands. + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n34, get_rnd_raster_point(n34_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n34, get_rnd_raster_point(n34_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n38, get_rnd_raster_point(n38_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n38, get_rnd_raster_point(n38_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n39, get_rnd_raster_point(n39_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n39, get_rnd_raster_point(n39_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n40, get_rnd_raster_point(n40_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n40, get_rnd_raster_point(n40_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n50, get_rnd_raster_point(n50_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n50, get_rnd_raster_point(n50_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n51, get_rnd_raster_point(n51_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n51, get_rnd_raster_point(n51_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n53, get_rnd_raster_point(n53_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n53, get_rnd_raster_point(n53_raster, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band(nr_band::n100, get_rnd_raster_point(n100_raster), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE( + is_dl_arfcn_valid_given_band(nr_band::n100, get_rnd_raster_point(n100_raster, true), subcarrier_spacing::kHz30) + .has_value()); +} + +TEST(test_dl_arfcn_validator, test_tdd_bands_with_sparse_raster) +{ + // Band n46. + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n46, 788668U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz10) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n46, 769332U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz10) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n46, 774668U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz20) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n46, 782000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz20) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n46, 770000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n46, 755334U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n46, 778668U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz60) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n46, 746000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz60) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n46, 746000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz80) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n46, 791000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz80) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n46, 791000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz100) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n46, 782000U, subcarrier_spacing::kHz15, srsran::bs_channel_bandwidth::MHz100) + .has_value()); + + // Band n96. + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n96, 838332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz20) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n96, 827000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz20) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n96, 821668U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n96, 857000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n96, 873000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz60) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n96, 859000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz60) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n96, 815000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz80) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n96, 798332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz80) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n96, 870332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz100) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n96, 841668U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz100) + .has_value()); + + // Band n102. + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n102, 805000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz20) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n102, 797668U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz20) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n102, 808332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n102, 805000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz40) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n102, 803668U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz60) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n102, 800332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz60) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n102, 825668U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz80) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n102, 852000U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz80) + .has_value()); + ASSERT_TRUE(is_dl_arfcn_valid_given_band( + nr_band::n102, 814332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz100) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n102, 798332U, subcarrier_spacing::kHz30, srsran::bs_channel_bandwidth::MHz100) + .has_value()); +} + +TEST(test_dl_arfcn_validator, test_tdd_bands_with_scs_dependent_raster) +{ + // Get a random raster point from the band raster. If outside_raster is true, the function returns a point outside the + // raster. + auto get_rnd_raster_point = [](span raster, bool outside_raster = false) -> uint32_t { + const uint32_t raster_step = raster[1]; + if (outside_raster) { + return test_rgen::bernoulli(0.5) ? raster.front() - raster_step : raster.back() + raster_step; + } + const unsigned nof_raster_points = (raster.back() - raster.front()) / raster_step + 1; + return test_rgen::uniform_int(0, nof_raster_points - 1) * raster_step + raster.front(); + }; + + // Definition of UL rasters for different bands. + constexpr std::array n41_raster_scs_15 = {499200, 3, 537999}; + constexpr std::array n41_raster_scs_30 = {499200, 6, 537996}; + constexpr std::array n48_raster_scs_15 = {636667, 1, 646666}; + constexpr std::array n48_raster_scs_30 = {636668, 2, 646666}; + constexpr std::array n77_raster_scs_15 = {620000, 1, 680000}; + constexpr std::array n77_raster_scs_30 = {620000, 2, 680000}; + constexpr std::array n78_raster_scs_15 = {620000, 1, 653333}; + constexpr std::array n78_raster_scs_30 = {620000, 2, 653332}; + constexpr std::array n79_raster_scs_15 = {693334, 1, 733333}; + constexpr std::array n79_raster_scs_30 = {693334, 2, 733332}; + constexpr std::array n90_raster_scs_15 = {499200, 3, 537999}; + constexpr std::array n90_raster_scs_30 = {499200, 6, 537996}; + constexpr std::array n104_raster_scs_15 = {828334, 1, 875000}; + constexpr std::array n104_raster_scs_30 = {828334, 2, 875000}; + + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n41, get_rnd_raster_point(n41_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n41, get_rnd_raster_point(n41_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n41, get_rnd_raster_point(n41_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n41, get_rnd_raster_point(n41_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n48, get_rnd_raster_point(n48_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n48, get_rnd_raster_point(n48_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n48, get_rnd_raster_point(n48_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n48, get_rnd_raster_point(n48_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n77, get_rnd_raster_point(n77_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n77, get_rnd_raster_point(n77_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n77, get_rnd_raster_point(n77_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n77, get_rnd_raster_point(n77_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n78, get_rnd_raster_point(n78_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n78, get_rnd_raster_point(n78_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n78, get_rnd_raster_point(n78_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n78, get_rnd_raster_point(n78_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n79, get_rnd_raster_point(n79_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n79, get_rnd_raster_point(n79_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n79, get_rnd_raster_point(n79_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n79, get_rnd_raster_point(n79_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n90, get_rnd_raster_point(n90_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n90, get_rnd_raster_point(n90_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n90, get_rnd_raster_point(n90_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n90, get_rnd_raster_point(n90_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n104, get_rnd_raster_point(n104_raster_scs_15), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n104, get_rnd_raster_point(n104_raster_scs_15, true), subcarrier_spacing::kHz15) + .has_value()); + ASSERT_TRUE( + is_dl_arfcn_valid_given_band(nr_band::n104, get_rnd_raster_point(n104_raster_scs_30), subcarrier_spacing::kHz30) + .has_value()); + ASSERT_FALSE(is_dl_arfcn_valid_given_band( + nr_band::n104, get_rnd_raster_point(n104_raster_scs_30, true), subcarrier_spacing::kHz30) + .has_value()); +} + +TEST(test_ul_arfcn_validator, test_different_bands) +{ + // Get a random raster point from the band raster. If outside_raster is true, the function returns a point outside the + // raster. + auto get_rnd_raster_point = [](span raster, bool outside_raster = false) -> uint32_t { + const uint32_t raster_step = raster[1]; + if (outside_raster) { + return test_rgen::bernoulli(0.5) ? raster.front() - raster_step : raster.back() + raster_step; + } + const unsigned nof_raster_points = (raster.back() - raster.front()) / raster_step + 1; + return test_rgen::uniform_int(0, nof_raster_points - 1) * raster_step + raster.front(); + }; + + // Definition of UL rasters for different bands. + constexpr std::array n2_raster = {370000, 20, 382000}; + constexpr std::array n3_raster = {342000, 20, 357000}; + constexpr std::array n7_raster = {500000, 20, 514000}; + constexpr std::array n14_raster = {157600, 20, 159600}; + constexpr std::array n28_raster = {140600, 20, 149600}; + + ASSERT_TRUE(is_ul_arfcn_valid_given_band(nr_band::n2, get_rnd_raster_point(n2_raster)).has_value()); + ASSERT_FALSE(is_ul_arfcn_valid_given_band(nr_band::n2, get_rnd_raster_point(n2_raster, true)).has_value()); + ASSERT_TRUE(is_ul_arfcn_valid_given_band(nr_band::n3, get_rnd_raster_point(n3_raster)).has_value()); + ASSERT_FALSE(is_ul_arfcn_valid_given_band(nr_band::n3, get_rnd_raster_point(n3_raster, true)).has_value()); + ASSERT_TRUE(is_ul_arfcn_valid_given_band(nr_band::n7, get_rnd_raster_point(n7_raster)).has_value()); + ASSERT_FALSE(is_ul_arfcn_valid_given_band(nr_band::n7, get_rnd_raster_point(n7_raster, true)).has_value()); + ASSERT_TRUE(is_ul_arfcn_valid_given_band(nr_band::n14, get_rnd_raster_point(n14_raster)).has_value()); + ASSERT_FALSE(is_ul_arfcn_valid_given_band(nr_band::n14, get_rnd_raster_point(n14_raster, true)).has_value()); + ASSERT_TRUE(is_ul_arfcn_valid_given_band(nr_band::n28, get_rnd_raster_point(n28_raster)).has_value()); + ASSERT_FALSE(is_ul_arfcn_valid_given_band(nr_band::n28, get_rnd_raster_point(n28_raster, true)).has_value()); + // Single UL ARFCN for n28, BW 40Mhz. + ASSERT_TRUE(is_ul_arfcn_valid_given_band(nr_band::n28, 144608, bs_channel_bandwidth::MHz40).has_value()); + // Let's provide a n14 frequency to n28. + ASSERT_FALSE(is_ul_arfcn_valid_given_band(nr_band::n28, 157600).has_value()); } From e4a0490e25241de7698d54102ec9eeef26d858a5 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 1 Oct 2024 13:18:34 +0200 Subject: [PATCH 27/32] du: remove option to set UL ARFCN in config Signed-off-by: Carlo Galiotto --- .../flexible_du/du_high/du_high_config.h | 4 ---- .../du_high/du_high_config_cli11_schema.cpp | 1 - .../du_high/du_high_config_translators.cpp | 1 - .../du_high/du_high_config_validator.cpp | 21 +++++++++---------- .../config/cell_config_builder_params.h | 5 ----- lib/ran/band_helper.cpp | 18 +++++++++++++--- .../config/serving_cell_config_factory.cpp | 8 ++----- tests/unittests/ran/band_helper_test.cpp | 17 ++++++++------- 8 files changed, 37 insertions(+), 38 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config.h b/apps/units/flexible_du/du_high/du_high_config.h index 7dab4e2397..59b9af2d19 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -547,10 +547,6 @@ struct du_high_unit_base_cell_config { std::optional sector_id; /// DL ARFCN of "F_REF", which is the RF reference frequency, as per TS 38.104, Section 5.4.2.1. unsigned dl_f_ref_arfcn = 536020; - /// UL ARFCN of "F_REF", which is the RF reference frequency, as per TS 38.104, Section 5.4.2.1. - /// \remark Only relevant for FDD bands. If set with TDD bands, it will be ignored. - /// For FDD bands, if not set, the UL ARFCN will be computed automatically. - std::optional ul_f_ref_arfcn = std::nullopt; /// Common subcarrier spacing for the entire resource grid. It must be supported by the band SS raster. subcarrier_spacing common_scs = subcarrier_spacing::kHz15; /// NR band. diff --git a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp index 5fe73287f4..3a4624741d 100644 --- a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp @@ -1114,7 +1114,6 @@ static void configure_cli11_common_cell_args(CLI::App& app, du_high_unit_base_ce ->capture_default_str() ->check(CLI::Range(0U, (1U << 14) - 1U)); add_option(app, "--dl_arfcn", cell_params.dl_f_ref_arfcn, "Downlink ARFCN")->capture_default_str(); - add_option(app, "--ul_arfcn", cell_params.ul_f_ref_arfcn, "Uplink ARFCN")->capture_default_str(); add_auto_enum_option(app, "--band", cell_params.band, "NR band"); add_option_function( app, diff --git a/apps/units/flexible_du/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/du_high/du_high_config_translators.cpp index da5ff59bf2..fba3b05b3e 100644 --- a/apps/units/flexible_du/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_translators.cpp @@ -230,7 +230,6 @@ std::vector srsran::generate_du_cell_config(const du_hig param.scs_common = base_cell.common_scs; param.channel_bw_mhz = base_cell.channel_bw_mhz; param.dl_f_ref_arfcn = base_cell.dl_f_ref_arfcn; - param.ul_f_ref_arfcn = base_cell.ul_f_ref_arfcn; param.band = *base_cell.band; // Enable CSI-RS if the PDSCH mcs is dynamic (min_ue_mcs != max_ue_mcs). param.csi_rs_enabled = base_cell.csi_cfg.csi_rs_enabled; diff --git a/apps/units/flexible_du/du_high/du_high_config_validator.cpp b/apps/units/flexible_du/du_high/du_high_config_validator.cpp index 0a98910599..d5afb5278f 100644 --- a/apps/units/flexible_du/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_validator.cpp @@ -651,13 +651,12 @@ static bool validate_dl_ul_arfcn_and_band(const du_high_unit_base_cell_config& c fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); return false; } - if (config.ul_f_ref_arfcn.has_value()) { - ret = - band_helper::is_ul_arfcn_valid_given_band(*config.band, config.ul_f_ref_arfcn.value(), config.channel_bw_mhz); - if (not ret.has_value()) { - fmt::print("Invalid UL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); - return false; - } + // Check if also the corresponding UL ARFCN is valid. + const uint32_t ul_arfcn = band_helper::get_ul_arfcn_from_dl_arfcn(config.dl_f_ref_arfcn, config.band.value()); + ret = band_helper::is_ul_arfcn_valid_given_band(*config.band, ul_arfcn, config.channel_bw_mhz); + if (not ret.has_value()) { + fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); + return false; } } else { if (band == nr_band::invalid) { @@ -769,16 +768,16 @@ static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& return false; } - const auto ssb_scs = band_helper::get_most_suitable_ssb_scs( - band_helper::get_band_from_dl_arfcn(config.dl_f_ref_arfcn), config.common_scs); + const nr_band band = + config.band.has_value() ? config.band.value() : band_helper::get_band_from_dl_arfcn(config.dl_f_ref_arfcn); + const auto ssb_scs = band_helper::get_most_suitable_ssb_scs(band, config.common_scs); if (ssb_scs != config.common_scs) { fmt::print("Common SCS {}kHz is not equal to SSB SCS {}kHz. Different SCS for common and SSB is not supported.\n", scs_to_khz(config.common_scs), scs_to_khz(ssb_scs)); return false; } - const nr_band band = - config.band.has_value() ? config.band.value() : band_helper::get_band_from_dl_arfcn(config.dl_f_ref_arfcn); + const unsigned nof_crbs = band_helper::get_n_rbs_from_bw(config.channel_bw_mhz, config.common_scs, band_helper::get_freq_range(band)); diff --git a/include/srsran/scheduler/config/cell_config_builder_params.h b/include/srsran/scheduler/config/cell_config_builder_params.h index de26261d38..b4d4c30b16 100644 --- a/include/srsran/scheduler/config/cell_config_builder_params.h +++ b/include/srsran/scheduler/config/cell_config_builder_params.h @@ -31,11 +31,6 @@ struct cell_config_builder_params { /// This ARFCN represents "f_ref" for DL, as per TS 38.104, Section 5.4.2.1. As per TS 38.104, Section 5.4.2.2, /// "f_ref" maps to the central frequency of the band. unsigned dl_f_ref_arfcn = 365000; - /// This ARFCN represents "f_ref" for UL, as per TS 38.104, Section 5.4.2.1. As per TS 38.104, Section 5.4.2.2, - /// "f_ref" maps to the central frequency of the band. - /// \remark Only relevant for FDD bands. - /// If set, this value has been set by the application user. - std::optional ul_f_ref_arfcn = std::nullopt; /// NR operating band<\em>, as per Table 5.2-1 and 5.2-2, TS 38.104. If not specified, a valid band for the /// provided DL ARFCN is automatically derived. std::optional band; diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index 01ab1ed8e1..fba0f546aa 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -809,6 +809,16 @@ srsran::band_helper::is_ul_arfcn_valid_given_band(nr_band band, uint32_t arfcn_f for (const nr_band_raster& raster_band : nr_band_table) { if (raster_band.band == band and raster_band.delta_f_rast == band_delta_freq_raster) { + // Check if the ARFCN doesn't exceed the band upper-bound for bands that support asymmetrical UL and DL channel + // BWs. + if ((band == nr_band::n66 or band == nr_band::n70 or band == nr_band::n92 or band == nr_band::n94) and + (arfcn_f_ref < raster_band.ul_nref_first or arfcn_f_ref > raster_band.ul_nref_last)) { + return make_unexpected( + fmt::format("Asymmetrical UL and DL channel BWs are not supported. The UL ARFCN resulting from the DL " + "ARFCN for band n{} must not exceed the band upper-bound={}", + band, + raster_band.ul_nref_last)); + } if (arfcn_f_ref >= raster_band.ul_nref_first and arfcn_f_ref <= raster_band.ul_nref_last and ((arfcn_f_ref - raster_band.ul_nref_first) % raster_band.ul_nref_step) == 0) { return {}; @@ -845,9 +855,11 @@ uint32_t srsran::band_helper::get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn, std: if (b_it.band == operating_band) { const uint32_t offset = (dl_arfcn - b_it.dl_nref_first) / b_it.dl_nref_step; const uint32_t candidate_ul_arfcn = b_it.ul_nref_first + offset * b_it.ul_nref_step; - // For band n65, n66, n70, n92, n94, the UL spectrum is smaller than the corresponding DL spectrum, therefore we - // need to cap the UL ARFCN to its upper-bound. - return std::min(candidate_ul_arfcn, b_it.ul_nref_last); + // For band n66, n70, n92, n94, the UL spectrum is smaller than the corresponding DL spectrum, as these bands + // supports asymmetrical UL anc DL channel operations. However, the current GNB doesn't support this feature. + // If the resulting UL ARFCN is outside the valid range, return 0. + return (candidate_ul_arfcn >= b_it.ul_nref_first and candidate_ul_arfcn <= b_it.ul_nref_last) ? candidate_ul_arfcn + : 0U; } } diff --git a/lib/scheduler/config/serving_cell_config_factory.cpp b/lib/scheduler/config/serving_cell_config_factory.cpp index 1e399a308f..3d19236ec2 100644 --- a/lib/scheduler/config/serving_cell_config_factory.cpp +++ b/lib/scheduler/config/serving_cell_config_factory.cpp @@ -89,9 +89,7 @@ static carrier_configuration make_default_carrier_configuration(const cell_confi cfg.arfcn_f_ref = params.dl_f_ref_arfcn; cfg.nof_ant = params.nof_dl_ports; } else { - cfg.arfcn_f_ref = params.ul_f_ref_arfcn.has_value() - ? params.ul_f_ref_arfcn.value() - : band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, cfg.band); + cfg.arfcn_f_ref = band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, cfg.band); cfg.nof_ant = 1; } const min_channel_bandwidth min_channel_bw = band_helper::get_min_channel_bw(cfg.band, params.scs_common); @@ -336,9 +334,7 @@ srsran::config_helpers::make_default_ul_config_common(const cell_config_builder_ { ul_config_common cfg{}; // This is the ARFCN of the UL f_ref, as per TS 38.104, Section 5.4.2.1. - const uint32_t ul_arfcn = params.ul_f_ref_arfcn.has_value() - ? params.ul_f_ref_arfcn.value() - : band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, params.band); + const uint32_t ul_arfcn = band_helper::get_ul_arfcn_from_dl_arfcn(params.dl_f_ref_arfcn, params.band); const double ul_absolute_freq_point_a = band_helper::get_abs_freq_point_a_from_f_ref( band_helper::nr_arfcn_to_freq(ul_arfcn), params.cell_nof_crbs, params.scs_common); // \c absolute_freq_point_a needs to be expressed as in ARFCN, as per \c absoluteFrequencyPointA definition in 38.211, diff --git a/tests/unittests/ran/band_helper_test.cpp b/tests/unittests/ran/band_helper_test.cpp index bad41ff8da..1449d0a108 100644 --- a/tests/unittests/ran/band_helper_test.cpp +++ b/tests/unittests/ran/band_helper_test.cpp @@ -112,13 +112,16 @@ TEST(get_ul_arfcn_from_dl_arfcn, mixed_frequencies) ASSERT_EQ(142600, get_ul_arfcn_from_dl_arfcn(153600, nr_band::n28)); ASSERT_EQ(144608, get_ul_arfcn_from_dl_arfcn(155608, nr_band::n28)); - // For n65, m66, n70, n92, n94, the UL spectrum is smaller than the DL spectrum. When we convert the DL ARFCN - // upper-bound to the corresponding UL ARFCN, we need to cap the value to the UL spectrum upper-bound. - ASSERT_EQ(402000, get_ul_arfcn_from_dl_arfcn(440000, nr_band::n65)); - ASSERT_EQ(356000, get_ul_arfcn_from_dl_arfcn(440000, nr_band::n66)); - ASSERT_EQ(342000, get_ul_arfcn_from_dl_arfcn(404000, nr_band::n70)); - ASSERT_EQ(172400, get_ul_arfcn_from_dl_arfcn(303400, nr_band::n92)); - ASSERT_EQ(183000, get_ul_arfcn_from_dl_arfcn(303400, nr_band::n94)); + // For n66, n70, n92, n94, the UL spectrum is smaller than the DL spectrum. When we convert the DL ARFCN + // to the corresponding UL ARFCN, if the UL ARFCN exceeds the band upper-bound, we return 0. + ASSERT_EQ(356000, get_ul_arfcn_from_dl_arfcn(436000, nr_band::n66)); + ASSERT_EQ(0, get_ul_arfcn_from_dl_arfcn(440000, nr_band::n66)); + ASSERT_EQ(342000, get_ul_arfcn_from_dl_arfcn(402000, nr_band::n70)); + ASSERT_EQ(0, get_ul_arfcn_from_dl_arfcn(404000, nr_band::n70)); + ASSERT_EQ(172400, get_ul_arfcn_from_dl_arfcn(292400, nr_band::n92)); + ASSERT_EQ(0, get_ul_arfcn_from_dl_arfcn(303400, nr_band::n92)); + ASSERT_EQ(183000, get_ul_arfcn_from_dl_arfcn(293400, nr_band::n94)); + ASSERT_EQ(0, get_ul_arfcn_from_dl_arfcn(303400, nr_band::n94)); } TEST(test_get_abs_freq_point_a_arfcn, mixed_frequencies) From 1ba7fdac76df1c2e4b81c19b277ccd40fec0c1c0 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 1 Oct 2024 15:33:11 +0200 Subject: [PATCH 28/32] du: prevent getting band from arfcn when band is given Signed-off-by: Carlo Galiotto --- .../du_high/du_high_config_validator.cpp | 21 +++++++++---------- .../dynamic_du_unit_cli11_schema.cpp | 6 +++--- include/srsran/ran/ssb_mapping.h | 3 --- lib/du/du_low/du_low_wrapper_factory.cpp | 10 ++++----- lib/mac/mac_dl/mac_cell_processor.cpp | 3 +-- lib/ran/band_helper.cpp | 6 +++--- lib/ran/ssb_mapping.cpp | 17 ++++----------- 7 files changed, 26 insertions(+), 40 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config_validator.cpp b/apps/units/flexible_du/du_high/du_high_config_validator.cpp index d5afb5278f..ab838d0ea9 100644 --- a/apps/units/flexible_du/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_validator.cpp @@ -195,10 +195,9 @@ static bool validate_srb_unit_config(const std::map ret = band_helper::is_dl_arfcn_valid_given_band( *config.band, config.dl_f_ref_arfcn, config.common_scs, config.channel_bw_mhz); @@ -655,6 +653,7 @@ static bool validate_dl_ul_arfcn_and_band(const du_high_unit_base_cell_config& c const uint32_t ul_arfcn = band_helper::get_ul_arfcn_from_dl_arfcn(config.dl_f_ref_arfcn, config.band.value()); ret = band_helper::is_ul_arfcn_valid_given_band(*config.band, ul_arfcn, config.channel_bw_mhz); if (not ret.has_value()) { + // NOTE: The message must say that it's the DL ARFCN that is invalid, as that is the parameters set by the user. fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); return false; } @@ -768,9 +767,8 @@ static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& return false; } - const nr_band band = - config.band.has_value() ? config.band.value() : band_helper::get_band_from_dl_arfcn(config.dl_f_ref_arfcn); - const auto ssb_scs = band_helper::get_most_suitable_ssb_scs(band, config.common_scs); + const nr_band band = config.band.value_or(band_helper::get_band_from_dl_arfcn(config.dl_f_ref_arfcn)); + const auto ssb_scs = band_helper::get_most_suitable_ssb_scs(band, config.common_scs); if (ssb_scs != config.common_scs) { fmt::print("Common SCS {}kHz is not equal to SSB SCS {}kHz. Different SCS for common and SSB is not supported.\n", scs_to_khz(config.common_scs), @@ -840,8 +838,9 @@ static bool validate_cells_unit_config(span conf fmt::print("Invalid Sector ID {}, for a gNB Id of {} bits\n", cell.cell.sector_id.value(), gnb_id.bit_length); return false; } - const auto band = cell.cell.band.value_or(band_helper::get_band_from_dl_arfcn(cell.cell.dl_f_ref_arfcn)); - bool is_unlicensed = band_helper::is_unlicensed_band(band); + const auto band = cell.cell.band.value_or(band_helper::get_band_from_dl_arfcn(cell.cell.dl_f_ref_arfcn)); + bool is_unlicensed = band_helper::is_unlicensed_band(band); + // Check if the RA Response Window (in ms) is within the limits for licensed and unlicensed bands. unsigned int max_ra_resp_window = is_unlicensed ? 40 : 10; unsigned int ra_resp_window_ms = cell.cell.prach_cfg.ra_resp_window.value() >> to_numerology_value(cell.cell.common_scs); diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp b/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp index e5db4a3b9f..60db142c89 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp @@ -155,9 +155,9 @@ void srsran::autoderive_dynamic_du_parameters_after_parsing(CLI::App& app, dynam } // Auto derive DU low parameters. - const auto& cell = parsed_cfg.du_high_cfg.config.cells_cfg.front().cell; - nr_band band = cell.band ? cell.band.value() : band_helper::get_band_from_dl_arfcn(cell.dl_f_ref_arfcn); - bool is_zmq_rf_driver = false; + const auto& cell = parsed_cfg.du_high_cfg.config.cells_cfg.front().cell; + const nr_band band = cell.band ? cell.band.value() : band_helper::get_band_from_dl_arfcn(cell.dl_f_ref_arfcn); + bool is_zmq_rf_driver = false; if (std::holds_alternative(parsed_cfg.ru_cfg)) { is_zmq_rf_driver = std::get(parsed_cfg.ru_cfg).device_driver == "zmq"; } diff --git a/include/srsran/ran/ssb_mapping.h b/include/srsran/ran/ssb_mapping.h index 0598e5c7c7..577796f381 100644 --- a/include/srsran/ran/ssb_mapping.h +++ b/include/srsran/ran/ssb_mapping.h @@ -158,9 +158,6 @@ inline unsigned ssb_get_k_first(frequency_range fr, return (k_first_15kHz * 15) / ssb_scs_kHz; } -/// Calculates SSB pattern from SSB subcarrier spacing and DL ARFCN. -ssb_pattern_case ssb_get_ssb_pattern(subcarrier_spacing ssb_scs, unsigned dl_arfcn); - /// \brief Calculates L_max, ie max number of SSB occasions per SSB period. Possible values are {4, 8, 64}. /// \remark See TS 38.213, Section 4.1. /// \param ssb_scs SSB Subcarrier Spacing. diff --git a/lib/du/du_low/du_low_wrapper_factory.cpp b/lib/du/du_low/du_low_wrapper_factory.cpp index 499caa09fc..21c908ea8b 100644 --- a/lib/du/du_low/du_low_wrapper_factory.cpp +++ b/lib/du/du_low/du_low_wrapper_factory.cpp @@ -52,11 +52,11 @@ static fapi::prach_config generate_prach_config_tlv(const du_cell_config& cell_c static fapi::carrier_config generate_carrier_config_tlv(const du_cell_config& du_cell) { // Deduce common numerology and grid size for DL and UL. - unsigned numerology = to_numerology_value(du_cell.scs_common); - unsigned grid_size_bw_prb = band_helper::get_n_rbs_from_bw( - MHz_to_bs_channel_bandwidth(du_cell.dl_carrier.carrier_bw_mhz), - du_cell.scs_common, - band_helper::get_freq_range(band_helper::get_band_from_dl_arfcn(du_cell.dl_carrier.arfcn_f_ref))); + unsigned numerology = to_numerology_value(du_cell.scs_common); + unsigned grid_size_bw_prb = + band_helper::get_n_rbs_from_bw(MHz_to_bs_channel_bandwidth(du_cell.dl_carrier.carrier_bw_mhz), + du_cell.scs_common, + band_helper::get_freq_range(du_cell.dl_carrier.band)); fapi::carrier_config fapi_config = {}; diff --git a/lib/mac/mac_dl/mac_cell_processor.cpp b/lib/mac/mac_dl/mac_cell_processor.cpp index b03ed8c625..d64d82715f 100644 --- a/lib/mac/mac_dl/mac_cell_processor.cpp +++ b/lib/mac/mac_dl/mac_cell_processor.cpp @@ -36,8 +36,7 @@ mac_cell_processor::mac_cell_processor(const mac_cell_creation_request& cell_cfg ue_mng(rnti_table), dl_harq_buffers(band_helper::get_n_rbs_from_bw(MHz_to_bs_channel_bandwidth(cell_cfg.dl_carrier.carrier_bw_mhz), cell_cfg.scs_common, - band_helper::get_freq_range(band_helper::get_band_from_dl_arfcn( - cell_cfg.dl_carrier.arfcn_f_ref))), + band_helper::get_freq_range(cell_cfg.dl_carrier.band)), cell_cfg.dl_carrier.nof_ant, ctrl_exec_), // The PDU pool has to be large enough to fit the maximum number of RARs and Paging PDUs per slot for all possible K0 diff --git a/lib/ran/band_helper.cpp b/lib/ran/band_helper.cpp index fba0f546aa..b7e794e810 100644 --- a/lib/ran/band_helper.cpp +++ b/lib/ran/band_helper.cpp @@ -56,7 +56,7 @@ struct nr_band_raster { // NOTE: FR2 bands have two different Freq raster, we only consider raster 120kHz. const uint32_t nof_nr_DL_bands = 83; static constexpr std::array nr_band_table = {{ - // clang-format off + // clang-format off {nr_band::n1, delta_freq_raster::kHz100, 384000, 20, 396000, 422000, 20, 434000}, {nr_band::n2, delta_freq_raster::kHz100, 370000, 20, 382000, 386000, 20, 398000}, {nr_band::n3, delta_freq_raster::kHz100, 342000, 20, 357000, 361000, 20, 376000}, @@ -159,7 +159,7 @@ struct nr_operating_band { }; static const uint32_t nof_nr_operating_band = 68; static constexpr std::array nr_operating_bands = {{ - // clang-format off + // clang-format off {nr_band::n1, duplex_mode::FDD}, {nr_band::n2, duplex_mode::FDD}, {nr_band::n3, duplex_mode::FDD}, @@ -836,7 +836,7 @@ srsran::band_helper::is_ul_arfcn_valid_given_band(nr_band band, uint32_t arfcn_f uint32_t srsran::band_helper::get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn, std::optional band) { // NOTE: The procedure implemented in this function is implementation-defined. - const nr_band operating_band = band.has_value() ? band.value() : get_band_from_dl_arfcn(dl_arfcn); + const nr_band operating_band = band.value_or(get_band_from_dl_arfcn(dl_arfcn)); // Return same ARFCN for TDD bands. if (get_duplex_mode(operating_band) == duplex_mode::TDD) { diff --git a/lib/ran/ssb_mapping.cpp b/lib/ran/ssb_mapping.cpp index 4c9507bed2..c791f12651 100644 --- a/lib/ran/ssb_mapping.cpp +++ b/lib/ran/ssb_mapping.cpp @@ -15,26 +15,17 @@ using namespace srsran; -ssb_pattern_case srsran::ssb_get_ssb_pattern(subcarrier_spacing ssb_scs, unsigned dl_arfcn) -{ - nr_band dl_idx_nr_band = band_helper::get_band_from_dl_arfcn(dl_arfcn); - srsran_assert(dl_idx_nr_band != nr_band::invalid, "Invalid NR band index"); - return band_helper::get_ssb_pattern(dl_idx_nr_band, ssb_scs); -} - uint8_t srsran::ssb_get_L_max(subcarrier_spacing ssb_scs, unsigned dl_arfcn, std::optional band) { uint8_t L_max = 0; // Derive the SSB-specific parameters (SSB pattern case, SSB L_max and SSB paired_spectrum flag) from those in the // MAC Cell config. - if (not band.has_value()) { - band.emplace(band_helper::get_band_from_dl_arfcn(dl_arfcn)); - srsran_assert(band.value() != nr_band::invalid, "Invalid NR band index"); - } - ssb_pattern_case ssb_case = band_helper::get_ssb_pattern(band.value(), ssb_scs); + const nr_band gnb_band = band.value_or(band_helper::get_band_from_dl_arfcn(dl_arfcn)); + srsran_assert(gnb_band != nr_band::invalid, "Invalid NR band index"); + ssb_pattern_case ssb_case = band_helper::get_ssb_pattern(gnb_band, ssb_scs); // Flag indicating whether cell is on paired spectrum (FDD) or unpaired (TDD, SDL, SUL). - bool paired_spectrum = band_helper::is_paired_spectrum(band.value()); + bool paired_spectrum = band_helper::is_paired_spectrum(gnb_band); // Get L_max from SSB pattern case and carrier frequency and paired spectrum flag. uint32_t f_arfcn = dl_arfcn; From ddb2705eb795beb5b683bdb7e1b4128d00280d28 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Fri, 27 Sep 2024 14:03:49 +0200 Subject: [PATCH 29/32] du_unit: moved the DPDK DU low code to the DU low folder --- .../du_low/du_low_config_cli11_schema.cpp | 2 +- .../du_low/du_low_config_translator.cpp | 19 ++-- .../du_low/du_low_config_translator.h | 12 +-- .../du_low/du_low_wrapper_config_helper.cpp | 94 ++++++++++++++++++- .../du_low/du_low_wrapper_config_helper.h | 1 - .../flexible_du/split_7_2/CMakeLists.txt | 11 +-- .../split_7_2/split_7_2_du_factory.cpp | 83 ---------------- apps/units/flexible_du/split_8/CMakeLists.txt | 11 +-- .../split_8/split_8_du_factory.cpp | 83 ---------------- .../flexible_du/split_dynamic/CMakeLists.txt | 11 +-- .../split_dynamic/dynamic_du_factory.cpp | 83 ---------------- 11 files changed, 106 insertions(+), 304 deletions(-) diff --git a/apps/units/flexible_du/du_low/du_low_config_cli11_schema.cpp b/apps/units/flexible_du/du_low/du_low_config_cli11_schema.cpp index 594e83d800..a1a57fbd9f 100644 --- a/apps/units/flexible_du/du_low/du_low_config_cli11_schema.cpp +++ b/apps/units/flexible_du/du_low/du_low_config_cli11_schema.cpp @@ -242,7 +242,7 @@ static void configure_cli11_bbdev_hwacc_args(CLI::App& app, std::optionalhwacc_type, "Type of BBDEV implementation")->capture_default_str(); + app.add_option("--bbdev_acc_type", config->bbdev_acc_type, "Type of BBDEV implementation")->capture_default_str(); app.add_option("--hwacc_type", config->hwacc_type, "Type of BBDEV hardware-accelerator")->capture_default_str(); app.add_option("--id", config->id, "ID of the BBDEV-based hardware-accelerator.") ->capture_default_str() diff --git a/apps/units/flexible_du/du_low/du_low_config_translator.cpp b/apps/units/flexible_du/du_low/du_low_config_translator.cpp index 5c0cad3527..20fd1dbe5f 100644 --- a/apps/units/flexible_du/du_low/du_low_config_translator.cpp +++ b/apps/units/flexible_du/du_low/du_low_config_translator.cpp @@ -20,7 +20,6 @@ using namespace srsran; static void generate_du_low_config(srs_du::du_low_config& out_config, const du_low_unit_config& du_low, - const hal_upper_phy_config& hal_config, span du_cells, span max_puschs_per_slot, unsigned du_id) @@ -31,9 +30,6 @@ static void generate_du_low_config(srs_du::du_low_config& out_config const srs_du::du_cell_config& cell = du_cells[i]; upper_phy_config& upper_phy_cell = out_config.cells.emplace_back().upper_phy_cfg; - // Initialize the HAL config of the upper PHY. - upper_phy_cell.hal_config = hal_config; - // Get band, frequency range and duplex mode from the band. nr_band band = cell.dl_carrier.band; const frequency_range freq_range = band_helper::get_freq_range(band); @@ -160,16 +156,13 @@ static void generate_du_low_config(srs_du::du_low_config& out_config } } -void srsran::generate_du_low_wrapper_config(srs_du::du_low_wrapper_config& out_config, - const du_low_unit_config& du_low_unit_cfg, - const hal_upper_phy_config& hal_config, - std::vector prach_ports, - span du_cells, - span max_puschs_per_slot, - unsigned du_id) +void srsran::generate_du_low_wrapper_config(srs_du::du_low_wrapper_config& out_config, + const du_low_unit_config& du_low_unit_cfg, + span du_cells, + span max_puschs_per_slot, + unsigned du_id) { - generate_du_low_config(out_config.du_low_cfg, du_low_unit_cfg, hal_config, du_cells, max_puschs_per_slot, du_id); - out_config.prach_ports = std::move(prach_ports); + generate_du_low_config(out_config.du_low_cfg, du_low_unit_cfg, du_cells, max_puschs_per_slot, du_id); } void srsran::fill_du_low_worker_manager_config(worker_manager_config& config, diff --git a/apps/units/flexible_du/du_low/du_low_config_translator.h b/apps/units/flexible_du/du_low/du_low_config_translator.h index c00fb84e15..6f0d9f5922 100644 --- a/apps/units/flexible_du/du_low/du_low_config_translator.h +++ b/apps/units/flexible_du/du_low/du_low_config_translator.h @@ -23,13 +23,11 @@ struct du_low_config; struct du_low_unit_config; struct worker_manager_config; -void generate_du_low_wrapper_config(srs_du::du_low_wrapper_config& out_config, - const du_low_unit_config& du_low_unit_cfg, - const hal_upper_phy_config& hal_config, - std::vector prach_ports, - span du_cells, - span max_puschs_per_slot, - unsigned du_id); +void generate_du_low_wrapper_config(srs_du::du_low_wrapper_config& out_config, + const du_low_unit_config& du_low_unit_cfg, + span du_cells, + span max_puschs_per_slot, + unsigned du_id); /// Fills the DU low worker manager parameters of the given worker manager configuration. void fill_du_low_worker_manager_config(worker_manager_config& config, diff --git a/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.cpp b/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.cpp index e751a1af59..d875c068b8 100644 --- a/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.cpp +++ b/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.cpp @@ -14,6 +14,13 @@ #include "du_low_config_translator.h" #include "srsran/du/du_low/du_low_wrapper_factory.h" #include "srsran/ran/slot_pdu_capacity_constants.h" +#ifdef DPDK_FOUND +#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" +#include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" +#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" +#include "srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h" +#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" +#endif // DPDK_FOUND using namespace srsran; @@ -55,7 +62,6 @@ static void generate_dl_processor_config(downlink_processor_factory_sw_config& o void srsran::make_du_low_wrapper_config_and_dependencies( srs_du::du_low_wrapper_config& out_cfg, const du_low_unit_config& du_low_unit_cfg, - const hal_upper_phy_config& hal_config, std::vector prach_ports, span du_cells, span max_puschs_per_slot, @@ -66,8 +72,90 @@ void srsran::make_du_low_wrapper_config_and_dependencies( { out_cfg.du_low_cfg.logger = &srslog::fetch_basic_logger("DU"); - generate_du_low_wrapper_config( - out_cfg, du_low_unit_cfg, hal_config, std::move(prach_ports), du_cells, max_puschs_per_slot, du_id); + // Initialize hardware-accelerator (only if needed). + hal_upper_phy_config hal_config = {}; + hal_config.hwacc_pdsch_processor = false; + hal_config.hwacc_pusch_processor = false; +#ifdef DPDK_FOUND + if (du_low_unit_cfg.hal_config && du_low_unit_cfg.hal_config->bbdev_hwacc && + !du_low_unit_cfg.hal_config->bbdev_hwacc->hwacc_type.empty()) { + const bbdev_appconfig& bbdev_app_cfg = du_low_unit_cfg.hal_config->bbdev_hwacc.value(); + srslog::basic_logger& hwacc_logger = srslog::fetch_basic_logger("HWACC", false); + hwacc_logger.set_level(du_low_unit_cfg.loggers.hal_level); + + hal::bbdev_hwacc_pdsch_enc_factory_configuration hwacc_pdsch_enc_cfg = {}; + hal::bbdev_hwacc_pusch_dec_factory_configuration hwacc_pusch_dec_cfg = {}; + std::shared_ptr harq_buffer_context = nullptr; + unsigned nof_hwacc_dus = du_cells.size(); + + // Create a bbdev accelerator factory. + std::unique_ptr bbdev_acc_factory = + dpdk::create_bbdev_acc_factory(bbdev_app_cfg.bbdev_acc_type); + report_error_if_not(bbdev_acc_factory, + "Unable to create the {} bbdev hardware-accelerator interface factory.", + bbdev_app_cfg.bbdev_acc_type); + + // Intefacing to the bbdev-based hardware-accelerator. + dpdk::bbdev_acc_configuration bbdev_config; + bbdev_config.id = bbdev_app_cfg.id; + if (bbdev_app_cfg.pdsch_enc && bbdev_app_cfg.pdsch_enc->nof_hwacc > 0) { + bbdev_config.nof_ldpc_enc_lcores = nof_hwacc_dus * bbdev_app_cfg.pdsch_enc->nof_hwacc; + } + if (bbdev_app_cfg.pusch_dec && bbdev_app_cfg.pusch_dec->nof_hwacc > 0) { + bbdev_config.nof_ldpc_dec_lcores = nof_hwacc_dus * bbdev_app_cfg.pusch_dec->nof_hwacc; + } + // If no msg_mbuf size is defined, a worst-case value will be used. + bbdev_config.msg_mbuf_size = bbdev_app_cfg.msg_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); + // If no rm_mbuf size is defined, a worst-case value will be used. + bbdev_config.rm_mbuf_size = bbdev_app_cfg.rm_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); + // If no number of mbufs is defined, a worst-case value will be used. + bbdev_config.nof_mbuf = bbdev_app_cfg.nof_mbuf.value_or(static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS)))); + std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, hwacc_logger); + report_error_if_not(bbdev_accelerator, "Unable to open the {} hardware-accelerator.", bbdev_app_cfg.hwacc_type); + + // Configure the hardware-accelerated PDSCH encoding factory (only if needed). + if (bbdev_app_cfg.pdsch_enc && bbdev_app_cfg.pdsch_enc->nof_hwacc > 0) { + hwacc_pdsch_enc_cfg.acc_type = bbdev_app_cfg.hwacc_type; + hwacc_pdsch_enc_cfg.bbdev_accelerator = bbdev_accelerator; + hwacc_pdsch_enc_cfg.cb_mode = bbdev_app_cfg.pdsch_enc->cb_mode; + // If no maximum buffer size is defined, a worst-case value will be used. + hwacc_pdsch_enc_cfg.max_tb_size = bbdev_app_cfg.pdsch_enc->max_buffer_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); + hwacc_pdsch_enc_cfg.dedicated_queue = bbdev_app_cfg.pdsch_enc->dedicated_queue; + hal_config.hwacc_pdsch_processor = true; + hal_config.hwacc_pdsch_enc_cfg = hwacc_pdsch_enc_cfg; + } + + // Configure the hardware-accelerated PUSCH decoding factory (only if needed). + if (bbdev_app_cfg.pusch_dec && bbdev_app_cfg.pusch_dec->nof_hwacc > 0) { + hwacc_pusch_dec_cfg.acc_type = bbdev_app_cfg.hwacc_type; + hwacc_pusch_dec_cfg.bbdev_accelerator = bbdev_accelerator; + hwacc_pusch_dec_cfg.ext_softbuffer = bbdev_app_cfg.pusch_dec->ext_softbuffer; + if (hwacc_pusch_dec_cfg.ext_softbuffer) { + // Set up an external HARQ buffer context repository. + unsigned nof_cbs = bbdev_app_cfg.pusch_dec->harq_context_size.value_or(MAX_NOF_SEGMENTS); + uint64_t ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); + harq_buffer_context = hal::create_ext_harq_buffer_context_repository(nof_cbs, ext_harq_buff_size, false); + report_error_if_not(harq_buffer_context, + "Unable to create the external HARQ buffer context for the {} hardware-accelerator.", + bbdev_app_cfg.hwacc_type); + hwacc_pusch_dec_cfg.harq_buffer_context = harq_buffer_context; + } + hwacc_pusch_dec_cfg.dedicated_queue = bbdev_app_cfg.pusch_dec->dedicated_queue; + hal_config.hwacc_pusch_processor = true; + hal_config.hwacc_pusch_dec_cfg = hwacc_pusch_dec_cfg; + } + } +#endif // DPDK_FOUND + + generate_du_low_wrapper_config(out_cfg, du_low_unit_cfg, du_cells, max_puschs_per_slot, du_id); + + // Fill the hal config. + for (auto& cell : out_cfg.du_low_cfg.cells) { + cell.upper_phy_cfg.hal_config = hal_config; + } + + // Fill the PRACH ports. + out_cfg.prach_ports = std::move(prach_ports); // Fill the workers information. for (unsigned i = 0, e = out_cfg.du_low_cfg.cells.size(); i != e; ++i) { diff --git a/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.h b/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.h index 4b3f19561b..d3006e878b 100644 --- a/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.h +++ b/apps/units/flexible_du/du_low/du_low_wrapper_config_helper.h @@ -24,7 +24,6 @@ struct worker_manager; void make_du_low_wrapper_config_and_dependencies(srs_du::du_low_wrapper_config& out_cfg, const du_low_unit_config& du_low_unit_cfg, - const hal_upper_phy_config& hal_config, std::vector prach_ports, span du_cells, span max_puschs_per_slot, diff --git a/apps/units/flexible_du/split_7_2/CMakeLists.txt b/apps/units/flexible_du/split_7_2/CMakeLists.txt index d1596233c3..183b433308 100644 --- a/apps/units/flexible_du/split_7_2/CMakeLists.txt +++ b/apps/units/flexible_du/split_7_2/CMakeLists.txt @@ -21,7 +21,7 @@ if (DU_SPLIT_7_2) add_library(srsran_flexible_du STATIC ${SOURCES}) target_include_directories(srsran_flexible_du PRIVATE ${CMAKE_SOURCE_DIR}) - set(FLEXIBLE_DU_LIBRARIES + target_link_libraries(srsran_flexible_du srsran_du_wrapper srsran_pcap srsran_app_services @@ -30,13 +30,4 @@ if (DU_SPLIT_7_2) srsran_split_7_2_app_unit_helpers srsran_du_high_unit_helpers) - # Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. - if (DPDK_FOUND) - set_source_files_properties(split_7_2_du_factory.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") - list(APPEND FLEXIBLE_DU_LIBRARIES hal_hwacc_pusch - hal_hwacc_pdsch - hal_bbdev_factory) - endif (DPDK_FOUND) - target_link_libraries(srsran_flexible_du ${FLEXIBLE_DU_LIBRARIES}) - endif () diff --git a/apps/units/flexible_du/split_7_2/split_7_2_du_factory.cpp b/apps/units/flexible_du/split_7_2/split_7_2_du_factory.cpp index eb37314aa3..2415cf8d2f 100644 --- a/apps/units/flexible_du/split_7_2/split_7_2_du_factory.cpp +++ b/apps/units/flexible_du/split_7_2/split_7_2_du_factory.cpp @@ -23,13 +23,6 @@ #include "srsran/du/du_wrapper_factory.h" #include "srsran/pcap/rlc_pcap.h" #include "srsran/ru/ru_dummy_factory.h" -#ifdef DPDK_FOUND -#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" -#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" -#endif // DPDK_FOUND using namespace srsran; @@ -108,81 +101,6 @@ du_unit srsran::create_split_7_2_du(const split_7_2_du_unit_config& du_72_cfg, c max_pusch_per_slot.push_back(high.cell.pusch_cfg.max_puschs_per_slot); } - // Initialize hardware-accelerator (only if needed). - hal_upper_phy_config hal_config = {}; - hal_config.hwacc_pdsch_processor = false; - hal_config.hwacc_pusch_processor = false; -#ifdef DPDK_FOUND - hal::bbdev_hwacc_pdsch_enc_factory_configuration hwacc_pdsch_enc_cfg = {}; - hal::bbdev_hwacc_pusch_dec_factory_configuration hwacc_pusch_dec_cfg = {}; - std::shared_ptr harq_buffer_context = nullptr; - unsigned nof_hwacc_dus = du_cells.size(); - if (!du_lo.hal_config->bbdev_hwacc->hwacc_type.empty()) { - srslog::basic_logger& hwacc_logger = srslog::fetch_basic_logger("HWACC", false); - hwacc_logger.set_level(du_lo.loggers.hal_level); - - // Create a bbdev accelerator factory. - std::unique_ptr bbdev_acc_factory = - srsran::dpdk::create_bbdev_acc_factory(du_lo.hal_config->bbdev_hwacc->bbdev_acc_type); - report_error_if_not(bbdev_acc_factory, - "Unable to create the {} bbdev hardware-accelerator interface factory.", - du_lo.hal_config->bbdev_hwacc->bbdev_acc_type); - - // Intefacing to the bbdev-based hardware-accelerator. - dpdk::bbdev_acc_configuration bbdev_config; - bbdev_config.id = du_lo.hal_config->bbdev_hwacc->id; - if (du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc > 0) { - bbdev_config.nof_ldpc_enc_lcores = nof_hwacc_dus * du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc; - } - if (du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc > 0) { - bbdev_config.nof_ldpc_dec_lcores = nof_hwacc_dus * du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc; - } - // If no msg_mbuf size is defined, a worst-case value will be used. - bbdev_config.msg_mbuf_size = du_lo.hal_config->bbdev_hwacc->msg_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - // If no rm_mbuf size is defined, a worst-case value will be used. - bbdev_config.rm_mbuf_size = du_lo.hal_config->bbdev_hwacc->rm_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - // If no number of mbufs is defined, a worst-case value will be used. - bbdev_config.nof_mbuf = - du_lo.hal_config->bbdev_hwacc->nof_mbuf.value_or(static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS)))); - std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, hwacc_logger); - report_error_if_not( - bbdev_accelerator, "Unable to open the {} hardware-accelerator.", du_lo.hal_config->bbdev_hwacc->hwacc_type); - - // Configure the hardware-accelerated PDSCH encoding factory (only if needed). - if (du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc > 0) { - hwacc_pdsch_enc_cfg.acc_type = du_lo.hal_config->bbdev_hwacc->hwacc_type; - hwacc_pdsch_enc_cfg.bbdev_accelerator = bbdev_accelerator; - hwacc_pdsch_enc_cfg.cb_mode = du_lo.hal_config->bbdev_hwacc->pdsch_enc->cb_mode; - // If no maximum buffer size is defined, a worst-case value will be used. - hwacc_pdsch_enc_cfg.max_tb_size = - du_lo.hal_config->bbdev_hwacc->pdsch_enc->max_buffer_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - hwacc_pdsch_enc_cfg.dedicated_queue = du_lo.hal_config->bbdev_hwacc->pdsch_enc->dedicated_queue; - hal_config.hwacc_pdsch_processor = true; - hal_config.hwacc_pdsch_enc_cfg = hwacc_pdsch_enc_cfg; - } - - // Configure the hardware-accelerated PUSCH decoding factory (only if needed). - if (du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc > 0) { - hwacc_pusch_dec_cfg.acc_type = du_lo.hal_config->bbdev_hwacc->hwacc_type; - hwacc_pusch_dec_cfg.bbdev_accelerator = bbdev_accelerator; - hwacc_pusch_dec_cfg.ext_softbuffer = du_lo.hal_config->bbdev_hwacc->pusch_dec->ext_softbuffer; - if (hwacc_pusch_dec_cfg.ext_softbuffer) { - // Set up an external HARQ buffer context repository. - unsigned nof_cbs = du_lo.hal_config->bbdev_hwacc->pusch_dec->harq_context_size.value_or(MAX_NOF_SEGMENTS); - uint64_t ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); - harq_buffer_context = hal::create_ext_harq_buffer_context_repository(nof_cbs, ext_harq_buff_size, false); - report_error_if_not(harq_buffer_context, - "Unable to create the external HARQ buffer context for the {} hardware-accelerator.", - du_lo.hal_config->bbdev_hwacc->hwacc_type); - hwacc_pusch_dec_cfg.harq_buffer_context = harq_buffer_context; - } - hwacc_pusch_dec_cfg.dedicated_queue = du_lo.hal_config->bbdev_hwacc->pusch_dec->dedicated_queue; - hal_config.hwacc_pusch_processor = true; - hal_config.hwacc_pusch_dec_cfg = hwacc_pusch_dec_cfg; - } - } -#endif // DPDK_FOUND - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { // Create one DU per cell. srs_du::du_wrapper_config du_cfg = {}; @@ -192,7 +110,6 @@ du_unit srsran::create_split_7_2_du(const split_7_2_du_unit_config& du_72_cfg, c make_du_low_wrapper_config_and_dependencies(du_cfg.du_low_cfg, du_lo, - hal_config, {prach_ports[i]}, span(&du_cells[i], 1), span(&max_pusch_per_slot[i], 1), diff --git a/apps/units/flexible_du/split_8/CMakeLists.txt b/apps/units/flexible_du/split_8/CMakeLists.txt index 83b487f7bc..96fcd3fe83 100644 --- a/apps/units/flexible_du/split_8/CMakeLists.txt +++ b/apps/units/flexible_du/split_8/CMakeLists.txt @@ -21,7 +21,7 @@ if (DU_SPLIT_8) add_library(srsran_flexible_du STATIC ${SOURCES}) target_include_directories(srsran_flexible_du PRIVATE ${CMAKE_SOURCE_DIR}) - set(FLEXIBLE_DU_LIBRARIES + target_link_libraries(srsran_flexible_du srsran_du_wrapper srsran_pcap srsran_app_services @@ -30,13 +30,4 @@ if (DU_SPLIT_8) srsran_split_8_app_unit_helpers srsran_du_high_unit_helpers) - # Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. - if (DPDK_FOUND) - set_source_files_properties(split_8_du_factory.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") - list(APPEND FLEXIBLE_DU_LIBRARIES hal_hwacc_pusch - hal_hwacc_pdsch - hal_bbdev_factory) - endif (DPDK_FOUND) - target_link_libraries(srsran_flexible_du ${FLEXIBLE_DU_LIBRARIES}) - endif () diff --git a/apps/units/flexible_du/split_8/split_8_du_factory.cpp b/apps/units/flexible_du/split_8/split_8_du_factory.cpp index 11202de1a5..fbe6bd2987 100644 --- a/apps/units/flexible_du/split_8/split_8_du_factory.cpp +++ b/apps/units/flexible_du/split_8/split_8_du_factory.cpp @@ -23,13 +23,6 @@ #include "srsran/du/du_wrapper_factory.h" #include "srsran/pcap/rlc_pcap.h" #include "srsran/ru/ru_dummy_factory.h" -#ifdef DPDK_FOUND -#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" -#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" -#endif // DPDK_FOUND using namespace srsran; @@ -108,81 +101,6 @@ du_unit srsran::create_split_8_du(const split_8_du_unit_config& du_8_cfg, const max_pusch_per_slot.push_back(high.cell.pusch_cfg.max_puschs_per_slot); } - // Initialize hardware-accelerator (only if needed). - hal_upper_phy_config hal_config = {}; - hal_config.hwacc_pdsch_processor = false; - hal_config.hwacc_pusch_processor = false; -#ifdef DPDK_FOUND - hal::bbdev_hwacc_pdsch_enc_factory_configuration hwacc_pdsch_enc_cfg = {}; - hal::bbdev_hwacc_pusch_dec_factory_configuration hwacc_pusch_dec_cfg = {}; - std::shared_ptr harq_buffer_context = nullptr; - unsigned nof_hwacc_dus = du_cells.size(); - if (!du_lo.hal_config->bbdev_hwacc->hwacc_type.empty()) { - srslog::basic_logger& hwacc_logger = srslog::fetch_basic_logger("HWACC", false); - hwacc_logger.set_level(du_lo.loggers.hal_level); - - // Create a bbdev accelerator factory. - std::unique_ptr bbdev_acc_factory = - srsran::dpdk::create_bbdev_acc_factory(du_lo.hal_config->bbdev_hwacc->bbdev_acc_type); - report_error_if_not(bbdev_acc_factory, - "Unable to create the {} bbdev hardware-accelerator interface factory.", - du_lo.hal_config->bbdev_hwacc->bbdev_acc_type); - - // Intefacing to the bbdev-based hardware-accelerator. - dpdk::bbdev_acc_configuration bbdev_config; - bbdev_config.id = du_lo.hal_config->bbdev_hwacc->id; - if (du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc > 0) { - bbdev_config.nof_ldpc_enc_lcores = nof_hwacc_dus * du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc; - } - if (du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc > 0) { - bbdev_config.nof_ldpc_dec_lcores = nof_hwacc_dus * du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc; - } - // If no msg_mbuf size is defined, a worst-case value will be used. - bbdev_config.msg_mbuf_size = du_lo.hal_config->bbdev_hwacc->msg_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - // If no rm_mbuf size is defined, a worst-case value will be used. - bbdev_config.rm_mbuf_size = du_lo.hal_config->bbdev_hwacc->rm_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - // If no number of mbufs is defined, a worst-case value will be used. - bbdev_config.nof_mbuf = - du_lo.hal_config->bbdev_hwacc->nof_mbuf.value_or(static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS)))); - std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, hwacc_logger); - report_error_if_not( - bbdev_accelerator, "Unable to open the {} hardware-accelerator.", du_lo.hal_config->bbdev_hwacc->hwacc_type); - - // Configure the hardware-accelerated PDSCH encoding factory (only if needed). - if (du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc > 0) { - hwacc_pdsch_enc_cfg.acc_type = du_lo.hal_config->bbdev_hwacc->hwacc_type; - hwacc_pdsch_enc_cfg.bbdev_accelerator = bbdev_accelerator; - hwacc_pdsch_enc_cfg.cb_mode = du_lo.hal_config->bbdev_hwacc->pdsch_enc->cb_mode; - // If no maximum buffer size is defined, a worst-case value will be used. - hwacc_pdsch_enc_cfg.max_tb_size = - du_lo.hal_config->bbdev_hwacc->pdsch_enc->max_buffer_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - hwacc_pdsch_enc_cfg.dedicated_queue = du_lo.hal_config->bbdev_hwacc->pdsch_enc->dedicated_queue; - hal_config.hwacc_pdsch_processor = true; - hal_config.hwacc_pdsch_enc_cfg = hwacc_pdsch_enc_cfg; - } - - // Configure the hardware-accelerated PUSCH decoding factory (only if needed). - if (du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc > 0) { - hwacc_pusch_dec_cfg.acc_type = du_lo.hal_config->bbdev_hwacc->hwacc_type; - hwacc_pusch_dec_cfg.bbdev_accelerator = bbdev_accelerator; - hwacc_pusch_dec_cfg.ext_softbuffer = du_lo.hal_config->bbdev_hwacc->pusch_dec->ext_softbuffer; - if (hwacc_pusch_dec_cfg.ext_softbuffer) { - // Set up an external HARQ buffer context repository. - unsigned nof_cbs = du_lo.hal_config->bbdev_hwacc->pusch_dec->harq_context_size.value_or(MAX_NOF_SEGMENTS); - uint64_t ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); - harq_buffer_context = hal::create_ext_harq_buffer_context_repository(nof_cbs, ext_harq_buff_size, false); - report_error_if_not(harq_buffer_context, - "Unable to create the external HARQ buffer context for the {} hardware-accelerator.", - du_lo.hal_config->bbdev_hwacc->hwacc_type); - hwacc_pusch_dec_cfg.harq_buffer_context = harq_buffer_context; - } - hwacc_pusch_dec_cfg.dedicated_queue = du_lo.hal_config->bbdev_hwacc->pusch_dec->dedicated_queue; - hal_config.hwacc_pusch_processor = true; - hal_config.hwacc_pusch_dec_cfg = hwacc_pusch_dec_cfg; - } - } -#endif // DPDK_FOUND - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { // Create one DU per cell. srs_du::du_wrapper_config du_cfg = {}; @@ -192,7 +110,6 @@ du_unit srsran::create_split_8_du(const split_8_du_unit_config& du_8_cfg, const make_du_low_wrapper_config_and_dependencies(du_cfg.du_low_cfg, du_lo, - hal_config, {prach_ports[i]}, span(&du_cells[i], 1), span(&max_pusch_per_slot[i], 1), diff --git a/apps/units/flexible_du/split_dynamic/CMakeLists.txt b/apps/units/flexible_du/split_dynamic/CMakeLists.txt index 7b2b8630af..fd2305a175 100644 --- a/apps/units/flexible_du/split_dynamic/CMakeLists.txt +++ b/apps/units/flexible_du/split_dynamic/CMakeLists.txt @@ -17,7 +17,7 @@ set(SOURCES add_library(srsran_flexible_du STATIC ${SOURCES}) target_include_directories(srsran_flexible_du PRIVATE ${CMAKE_SOURCE_DIR}) -set(FLEXIBLE_DU_LIBRARIES +target_link_libraries(srsran_flexible_du srsran_du_wrapper srsran_ru_dummy srsran_pcap @@ -27,12 +27,3 @@ set(FLEXIBLE_DU_LIBRARIES srsran_split_8_app_unit_helpers srsran_split_7_2_app_unit_helpers srsran_du_high_unit_helpers) - -# Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. -if (DPDK_FOUND) - set_source_files_properties(dynamic_du_factory.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") - list(APPEND FLEXIBLE_DU_LIBRARIES hal_hwacc_pusch - hal_hwacc_pdsch - hal_bbdev_factory) -endif (DPDK_FOUND) -target_link_libraries(srsran_flexible_du ${FLEXIBLE_DU_LIBRARIES}) diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp index fecf9a3f2c..5f10d4440d 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp @@ -27,13 +27,6 @@ #include "srsran/du/du_wrapper_factory.h" #include "srsran/pcap/rlc_pcap.h" #include "srsran/ru/ru_dummy_factory.h" -#ifdef DPDK_FOUND -#include "srsran/hal/dpdk/bbdev/bbdev_acc.h" -#include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" -#include "srsran/hal/phy/upper/channel_processors/hw_accelerator_factories.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h" -#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_factories.h" -#endif // DPDK_FOUND using namespace srsran; @@ -159,81 +152,6 @@ du_unit srsran::create_dynamic_du(const dynamic_du_unit_config& dyn_du_cfg, cons max_pusch_per_slot.push_back(high.cell.pusch_cfg.max_puschs_per_slot); } - // Initialize hardware-accelerator (only if needed). - hal_upper_phy_config hal_config = {}; - hal_config.hwacc_pdsch_processor = false; - hal_config.hwacc_pusch_processor = false; -#ifdef DPDK_FOUND - hal::bbdev_hwacc_pdsch_enc_factory_configuration hwacc_pdsch_enc_cfg = {}; - hal::bbdev_hwacc_pusch_dec_factory_configuration hwacc_pusch_dec_cfg = {}; - std::shared_ptr harq_buffer_context = nullptr; - unsigned nof_hwacc_dus = du_cells.size(); - if (!du_lo.hal_config->bbdev_hwacc->hwacc_type.empty()) { - srslog::basic_logger& hwacc_logger = srslog::fetch_basic_logger("HWACC", false); - hwacc_logger.set_level(du_lo.loggers.hal_level); - - // Create a bbdev accelerator factory. - std::unique_ptr bbdev_acc_factory = - srsran::dpdk::create_bbdev_acc_factory(du_lo.hal_config->bbdev_hwacc->bbdev_acc_type); - report_error_if_not(bbdev_acc_factory, - "Unable to create the {} bbdev hardware-accelerator interface factory.", - du_lo.hal_config->bbdev_hwacc->bbdev_acc_type); - - // Intefacing to the bbdev-based hardware-accelerator. - dpdk::bbdev_acc_configuration bbdev_config; - bbdev_config.id = du_lo.hal_config->bbdev_hwacc->id; - if (du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc > 0) { - bbdev_config.nof_ldpc_enc_lcores = nof_hwacc_dus * du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc; - } - if (du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc > 0) { - bbdev_config.nof_ldpc_dec_lcores = nof_hwacc_dus * du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc; - } - // If no msg_mbuf size is defined, a worst-case value will be used. - bbdev_config.msg_mbuf_size = du_lo.hal_config->bbdev_hwacc->msg_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - // If no rm_mbuf size is defined, a worst-case value will be used. - bbdev_config.rm_mbuf_size = du_lo.hal_config->bbdev_hwacc->rm_mbuf_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - // If no number of mbufs is defined, a worst-case value will be used. - bbdev_config.nof_mbuf = - du_lo.hal_config->bbdev_hwacc->nof_mbuf.value_or(static_cast(pow2(log2_ceil(MAX_NOF_SEGMENTS)))); - std::shared_ptr bbdev_accelerator = bbdev_acc_factory->create(bbdev_config, hwacc_logger); - report_error_if_not( - bbdev_accelerator, "Unable to open the {} hardware-accelerator.", du_lo.hal_config->bbdev_hwacc->hwacc_type); - - // Configure the hardware-accelerated PDSCH encoding factory (only if needed). - if (du_lo.hal_config->bbdev_hwacc->pdsch_enc->nof_hwacc > 0) { - hwacc_pdsch_enc_cfg.acc_type = du_lo.hal_config->bbdev_hwacc->hwacc_type; - hwacc_pdsch_enc_cfg.bbdev_accelerator = bbdev_accelerator; - hwacc_pdsch_enc_cfg.cb_mode = du_lo.hal_config->bbdev_hwacc->pdsch_enc->cb_mode; - // If no maximum buffer size is defined, a worst-case value will be used. - hwacc_pdsch_enc_cfg.max_tb_size = - du_lo.hal_config->bbdev_hwacc->pdsch_enc->max_buffer_size.value_or(RTE_BBDEV_LDPC_E_MAX_MBUF); - hwacc_pdsch_enc_cfg.dedicated_queue = du_lo.hal_config->bbdev_hwacc->pdsch_enc->dedicated_queue; - hal_config.hwacc_pdsch_processor = true; - hal_config.hwacc_pdsch_enc_cfg = hwacc_pdsch_enc_cfg; - } - - // Configure the hardware-accelerated PUSCH decoding factory (only if needed). - if (du_lo.hal_config->bbdev_hwacc->pusch_dec->nof_hwacc > 0) { - hwacc_pusch_dec_cfg.acc_type = du_lo.hal_config->bbdev_hwacc->hwacc_type; - hwacc_pusch_dec_cfg.bbdev_accelerator = bbdev_accelerator; - hwacc_pusch_dec_cfg.ext_softbuffer = du_lo.hal_config->bbdev_hwacc->pusch_dec->ext_softbuffer; - if (hwacc_pusch_dec_cfg.ext_softbuffer) { - // Set up an external HARQ buffer context repository. - unsigned nof_cbs = du_lo.hal_config->bbdev_hwacc->pusch_dec->harq_context_size.value_or(MAX_NOF_SEGMENTS); - uint64_t ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); - harq_buffer_context = hal::create_ext_harq_buffer_context_repository(nof_cbs, ext_harq_buff_size, false); - report_error_if_not(harq_buffer_context, - "Unable to create the external HARQ buffer context for the {} hardware-accelerator.", - du_lo.hal_config->bbdev_hwacc->hwacc_type); - hwacc_pusch_dec_cfg.harq_buffer_context = harq_buffer_context; - } - hwacc_pusch_dec_cfg.dedicated_queue = du_lo.hal_config->bbdev_hwacc->pusch_dec->dedicated_queue; - hal_config.hwacc_pusch_processor = true; - hal_config.hwacc_pusch_dec_cfg = hwacc_pusch_dec_cfg; - } - } -#endif // DPDK_FOUND - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { // Create one DU per cell. srs_du::du_wrapper_config du_cfg = {}; @@ -243,7 +161,6 @@ du_unit srsran::create_dynamic_du(const dynamic_du_unit_config& dyn_du_cfg, cons make_du_low_wrapper_config_and_dependencies(du_cfg.du_low_cfg, du_lo, - hal_config, {prach_ports[i]}, span(&du_cells[i], 1), span(&max_pusch_per_slot[i], 1), From 2a685e4e936c70a61f7f4ced67baf28b1b495e1b Mon Sep 17 00:00:00 2001 From: ofontbach Date: Tue, 1 Oct 2024 11:45:07 +0200 Subject: [PATCH 30/32] hal: fix dpdk/hwacc-related flag propagation in du factories --- apps/units/flexible_du/split_7_2/CMakeLists.txt | 6 ++++++ apps/units/flexible_du/split_8/CMakeLists.txt | 6 ++++++ apps/units/flexible_du/split_dynamic/CMakeLists.txt | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/apps/units/flexible_du/split_7_2/CMakeLists.txt b/apps/units/flexible_du/split_7_2/CMakeLists.txt index 183b433308..a59cf62fa4 100644 --- a/apps/units/flexible_du/split_7_2/CMakeLists.txt +++ b/apps/units/flexible_du/split_7_2/CMakeLists.txt @@ -21,6 +21,12 @@ if (DU_SPLIT_7_2) add_library(srsran_flexible_du STATIC ${SOURCES}) target_include_directories(srsran_flexible_du PRIVATE ${CMAKE_SOURCE_DIR}) + + # Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. + if (DPDK_FOUND) + set_source_files_properties(split_7_2_du_factory.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + endif (DPDK_FOUND) + target_link_libraries(srsran_flexible_du srsran_du_wrapper srsran_pcap diff --git a/apps/units/flexible_du/split_8/CMakeLists.txt b/apps/units/flexible_du/split_8/CMakeLists.txt index 96fcd3fe83..45600cc1e5 100644 --- a/apps/units/flexible_du/split_8/CMakeLists.txt +++ b/apps/units/flexible_du/split_8/CMakeLists.txt @@ -21,6 +21,12 @@ if (DU_SPLIT_8) add_library(srsran_flexible_du STATIC ${SOURCES}) target_include_directories(srsran_flexible_du PRIVATE ${CMAKE_SOURCE_DIR}) + + # Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. + if (DPDK_FOUND) + set_source_files_properties(split_8_du_factory.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") + endif (DPDK_FOUND) + target_link_libraries(srsran_flexible_du srsran_du_wrapper srsran_pcap diff --git a/apps/units/flexible_du/split_dynamic/CMakeLists.txt b/apps/units/flexible_du/split_dynamic/CMakeLists.txt index fd2305a175..132ca854df 100644 --- a/apps/units/flexible_du/split_dynamic/CMakeLists.txt +++ b/apps/units/flexible_du/split_dynamic/CMakeLists.txt @@ -17,6 +17,12 @@ set(SOURCES add_library(srsran_flexible_du STATIC ${SOURCES}) target_include_directories(srsran_flexible_du PRIVATE ${CMAKE_SOURCE_DIR}) + +# Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. +if (DPDK_FOUND) + set_source_files_properties(dynamic_du_factory.cpp PROPERTIES COMPILE_DEFINITIONS "DPDK_FOUND; HWACC_PDSCH_ENABLED; HWACC_PUSCH_ENABLED") +endif (DPDK_FOUND) + target_link_libraries(srsran_flexible_du srsran_du_wrapper srsran_ru_dummy From 7d446716db04daf8bd334468c2af21d0bd2b50cf Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Wed, 2 Oct 2024 12:25:47 +0200 Subject: [PATCH 31/32] cu_cp_unit: added a CU-CP wrapper to store objects related to the CU-CP. Moved the n2 clients to this wrapper and removed them from the gNB and CU applications --- apps/cu/cu.cpp | 14 ++------ apps/gnb/gnb.cpp | 36 +++++++------------ apps/units/cu_cp/CMakeLists.txt | 3 +- apps/units/cu_cp/cu_cp_builder.cpp | 23 ++++++++++-- apps/units/cu_cp/cu_cp_builder.h | 11 +++--- apps/units/cu_cp/cu_cp_wrapper.cpp | 56 ++++++++++++++++++++++++++++++ apps/units/cu_cp/cu_cp_wrapper.h | 47 +++++++++++++++++++++++++ 7 files changed, 147 insertions(+), 43 deletions(-) create mode 100644 apps/units/cu_cp/cu_cp_wrapper.cpp create mode 100644 apps/units/cu_cp/cu_cp_wrapper.h diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index d083cdbf4e..d4bbb0198c 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -313,18 +313,8 @@ int main(int argc, char** argv) cu_cp_dependencies.cu_cp_executor = workers.cu_cp_exec; cu_cp_dependencies.cu_cp_e2_exec = workers.cu_cp_e2_exec; cu_cp_dependencies.timers = cu_timers; - - // Create N2 Client Gateways. - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client( - generate_n2_client_config(cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, - cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf, - *cu_cp_dlt_pcaps.ngap, - *epoll_broker))); - - for (const auto& amf : cu_cp_app_unit->get_cu_cp_unit_config().extra_amfs) { - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( - cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); - } + cu_cp_dependencies.ngap_pcap = cu_cp_dlt_pcaps.ngap.get(); + cu_cp_dependencies.broker = epoll_broker.get(); // create CU-CP. auto cu_cp_obj_and_cmds = cu_cp_app_unit->create_cu_cp(cu_cp_dependencies); diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 99d77a6743..69b2c41eff 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -360,12 +360,6 @@ int main(int argc, char** argv) e2_metric_connector_manager e2_metric_connectors(du_app_unit->get_du_high_unit_config().cells_cfg.size()); - // Create CU-CP config. - cu_cp_build_dependencies cu_cp_dependencies; - cu_cp_dependencies.cu_cp_executor = workers.cu_cp_exec; - cu_cp_dependencies.cu_cp_e2_exec = workers.cu_cp_e2_exec; - cu_cp_dependencies.timers = cu_timers; - // Load CU-CP plugins if enabled std::optional ng_handover_plugin = cu_cp_app_unit->get_cu_cp_unit_config().load_plugins @@ -404,23 +398,13 @@ int main(int argc, char** argv) cu_cp_app_unit->get_cu_cp_unit_config().disconnect_amfs_func_ptr = disconnect_amfs.value(); } - // Create N2 Client Gateways. - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client( - generate_n2_client_config(cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, - cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf, - *cu_cp_dlt_pcaps.ngap, - *epoll_broker))); - - for (const auto& amf : cu_cp_app_unit->get_cu_cp_unit_config().extra_amfs) { - cu_cp_dependencies.n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( - cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core, amf, *cu_cp_dlt_pcaps.ngap, *epoll_broker))); - } - - // E2AP configuration. - srsran::sctp_network_connector_config e2_du_nw_config = generate_e2ap_nw_config(gnb_cfg, E2_DU_PPID); - - // Create E2AP GW remote connector. - e2_gateway_remote_connector e2_gw{*epoll_broker, e2_du_nw_config, *du_pcaps.e2ap}; + // Create CU-CP dependencies. + cu_cp_build_dependencies cu_cp_dependencies; + cu_cp_dependencies.cu_cp_executor = workers.cu_cp_exec; + cu_cp_dependencies.cu_cp_e2_exec = workers.cu_cp_e2_exec; + cu_cp_dependencies.timers = cu_timers; + cu_cp_dependencies.ngap_pcap = cu_cp_dlt_pcaps.ngap.get(); + cu_cp_dependencies.broker = epoll_broker.get(); // create CU-CP. auto cu_cp_obj_and_cmds = cu_cp_app_unit->create_cu_cp(cu_cp_dependencies); @@ -438,6 +422,12 @@ int main(int argc, char** argv) std::unique_ptr cu_up_obj = cu_up_app_unit->create_cu_up_unit(cu_up_unit_deps); + // E2AP configuration. + sctp_network_connector_config e2_du_nw_config = generate_e2ap_nw_config(gnb_cfg, E2_DU_PPID); + + // Create E2AP GW remote connector. + e2_gateway_remote_connector e2_gw{*epoll_broker, e2_du_nw_config, *du_pcaps.e2ap}; + // Instantiate one DU. app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder; du_unit_dependencies du_dependencies; diff --git a/apps/units/cu_cp/CMakeLists.txt b/apps/units/cu_cp/CMakeLists.txt index 5c9452f21e..4b0f803949 100644 --- a/apps/units/cu_cp/CMakeLists.txt +++ b/apps/units/cu_cp/CMakeLists.txt @@ -12,7 +12,8 @@ set(SOURCES cu_cp_unit_config_cli11_schema.cpp cu_cp_config_translators.cpp cu_cp_unit_config_validator.cpp - cu_cp_unit_config_yaml_writer.cpp) + cu_cp_unit_config_yaml_writer.cpp + cu_cp_wrapper.cpp) add_library(srsran_cu_cp_app_unit STATIC ${SOURCES}) target_include_directories(srsran_cu_cp_app_unit PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/cu_cp/cu_cp_builder.cpp b/apps/units/cu_cp/cu_cp_builder.cpp index b8744e891c..0b7a2c0090 100644 --- a/apps/units/cu_cp/cu_cp_builder.cpp +++ b/apps/units/cu_cp/cu_cp_builder.cpp @@ -11,6 +11,8 @@ #include "cu_cp_builder.h" #include "cu_cp_commands.h" #include "cu_cp_config_translators.h" +#include "cu_cp_unit_config.h" +#include "cu_cp_wrapper.h" #include "srsran/cu_cp/cu_cp_factory.h" using namespace srsran; @@ -20,18 +22,33 @@ cu_cp_unit srsran::build_cu_cp(const cu_cp_unit_config& cu_cp_unit_cfg, cu_cp_bu srsran_assert(dependencies.cu_cp_executor, "Invalid CU-CP executor"); srsran_assert(dependencies.cu_cp_e2_exec, "Invalid E2 executor"); srsran_assert(dependencies.cu_cp_e2_exec, "Invalid E2 executor"); + srsran_assert(dependencies.ngap_pcap, "Invalid NGAP PCAP"); + srsran_assert(dependencies.broker, "Invalid IO broker"); srs_cu_cp::cu_cp_configuration cu_cp_cfg = generate_cu_cp_config(cu_cp_unit_cfg); cu_cp_cfg.services.cu_cp_executor = dependencies.cu_cp_executor; cu_cp_cfg.services.cu_cp_e2_exec = dependencies.cu_cp_e2_exec; cu_cp_cfg.services.timers = dependencies.timers; - for (unsigned pos = 0; pos < dependencies.n2_clients.size(); pos++) { - cu_cp_cfg.ngaps[pos].n2_gw = dependencies.n2_clients[pos].get(); + // Create N2 Client Gateways. + std::vector> n2_clients; + n2_clients.push_back( + srs_cu_cp::create_n2_connection_client(generate_n2_client_config(cu_cp_unit_cfg.amf_config.no_core, + cu_cp_unit_cfg.amf_config.amf, + *dependencies.ngap_pcap, + *dependencies.broker))); + + for (const auto& amf : cu_cp_unit_cfg.extra_amfs) { + n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( + cu_cp_unit_cfg.amf_config.no_core, amf, *dependencies.ngap_pcap, *dependencies.broker))); + } + + for (unsigned pos = 0; pos < n2_clients.size(); pos++) { + cu_cp_cfg.ngaps[pos].n2_gw = n2_clients[pos].get(); } cu_cp_unit cu_cmd_wrapper; - cu_cmd_wrapper.unit = create_cu_cp(cu_cp_cfg); + cu_cmd_wrapper.unit = std::make_unique(std::move(n2_clients), create_cu_cp(cu_cp_cfg)); // Add the commands; cu_cmd_wrapper.commands.push_back(std::make_unique(cu_cmd_wrapper.unit->get_command_handler())); diff --git a/apps/units/cu_cp/cu_cp_builder.h b/apps/units/cu_cp/cu_cp_builder.h index 6dc94cf164..ebc2a28ac4 100644 --- a/apps/units/cu_cp/cu_cp_builder.h +++ b/apps/units/cu_cp/cu_cp_builder.h @@ -15,6 +15,8 @@ namespace srsran { +class dlt_pcap; +class io_broker; struct cu_cp_unit_config; struct worker_manager; @@ -24,10 +26,11 @@ class n2_connection_client; /// CU-CP build dependencies. struct cu_cp_build_dependencies { - task_executor* cu_cp_executor = nullptr; - task_executor* cu_cp_e2_exec = nullptr; - std::vector> n2_clients; - timer_manager* timers = nullptr; + task_executor* cu_cp_executor = nullptr; + task_executor* cu_cp_e2_exec = nullptr; + timer_manager* timers = nullptr; + dlt_pcap* ngap_pcap = nullptr; + io_broker* broker = nullptr; }; /// Wraps the CU-CP and its supported application commands. diff --git a/apps/units/cu_cp/cu_cp_wrapper.cpp b/apps/units/cu_cp/cu_cp_wrapper.cpp new file mode 100644 index 0000000000..398b1a10a4 --- /dev/null +++ b/apps/units/cu_cp/cu_cp_wrapper.cpp @@ -0,0 +1,56 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "cu_cp_wrapper.h" + +using namespace srsran; +using namespace srs_cu_cp; + +cu_cp_wrapper::cu_cp_wrapper(std::vector> n2_clients_, + std::unique_ptr cu_cp_) : + n2_clients(std::move(n2_clients_)), cu_cp(std::move(cu_cp_)) +{ + srsran_assert(cu_cp, "Invalid CU-CP object"); +} + +cu_cp_f1c_handler& cu_cp_wrapper::get_f1c_handler() +{ + return cu_cp->get_f1c_handler(); +} + +cu_cp_e1_handler& cu_cp_wrapper::get_e1_handler() +{ + return cu_cp->get_e1_handler(); +} + +cu_cp_ng_handler& cu_cp_wrapper::get_ng_handler() +{ + return cu_cp->get_ng_handler(); +} + +cu_cp_command_handler& cu_cp_wrapper::get_command_handler() +{ + return cu_cp->get_command_handler(); +} + +metrics_handler& cu_cp_wrapper::get_metrics_handler() +{ + return cu_cp->get_metrics_handler(); +} + +bool cu_cp_wrapper::start() +{ + return cu_cp->start(); +} + +void cu_cp_wrapper::stop() +{ + cu_cp->stop(); +} diff --git a/apps/units/cu_cp/cu_cp_wrapper.h b/apps/units/cu_cp/cu_cp_wrapper.h new file mode 100644 index 0000000000..acbd7917f9 --- /dev/null +++ b/apps/units/cu_cp/cu_cp_wrapper.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/cu_cp/cu_cp.h" +#include "srsran/ngap/gateways/n2_connection_client.h" + +namespace srsran { + +/// \brief CU-CP wrapper implementation. +/// +/// The purpose of this wrapper is to keep the life cycle of the objects related only to the CU-CP. +class cu_cp_wrapper : public srs_cu_cp::cu_cp +{ +public: + cu_cp_wrapper(std::vector> n2_clients_, + std::unique_ptr cu_cp_); + + // See interface for documentation. + srs_cu_cp::cu_cp_f1c_handler& get_f1c_handler() override; + // See interface for documentation. + srs_cu_cp::cu_cp_e1_handler& get_e1_handler() override; + // See interface for documentation. + srs_cu_cp::cu_cp_ng_handler& get_ng_handler() override; + // See interface for documentation. + srs_cu_cp::cu_cp_command_handler& get_command_handler() override; + // See interface for documentation. + srs_cu_cp::metrics_handler& get_metrics_handler() override; + // See interface for documentation. + bool start() override; + // See interface for documentation. + void stop() override; + +private: + std::vector> n2_clients; + std::unique_ptr cu_cp; +}; + +} // namespace srsran From bf310d5ad50767e0306d53359f39e445c4011263 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 2 Oct 2024 17:33:01 +0200 Subject: [PATCH 32/32] ci,e2e: increase uesim timeouts --- .gitlab/ci/e2e.yml | 1 + tests/e2e/tests/ping.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 6215f3f9b3..333164d62a 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -277,6 +277,7 @@ smoke zmq: GROUP: uesim TESTBED: zmq_uesim E2E_LOG_LEVEL: "info" + RETINA_LAUNCHER_ARGS: "--retina-pod-timeout 900" needs: - job: "basic relwithdeb" artifacts: true diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index b3b39121ab..cb2682b564 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -242,7 +242,7 @@ def test_zmq( sample_rate=None, # default from testbed global_timing_advance=0, time_alignment_calibration=0, - ue_stop_timeout=1, + ue_stop_timeout=3, enable_security_mode=ciphering, post_command=("cu_cp --inactivity_timer=600", ""), )